.nornir/assets/facett_flow.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1180 680" font-family="'DejaVu Sans', 'Segoe UI', sans-serif">
<defs>
<linearGradient id="board" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#0b1c2e"/>
<stop offset="1" stop-color="#06111d"/>
</linearGradient>
<linearGradient id="chip" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#14384f"/>
<stop offset="1" stop-color="#0e2a3e"/>
</linearGradient>
<linearGradient id="rail" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#173d57"/>
<stop offset="1" stop-color="#0c2438"/>
</linearGradient>
<linearGradient id="slot" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#123448"/>
<stop offset="1" stop-color="#0a2032"/>
</linearGradient>
</defs>
<!-- PCB substrate -->
<rect x="0" y="0" width="1180" height="680" fill="url(#board)"/>
<g stroke="#143a52" stroke-width="1">
<line x1="0" y1="76" x2="1180" y2="76"/>
<line x1="0" y1="632" x2="1180" y2="632"/>
</g>
<g fill="#16415c">
<circle cx="40" cy="40" r="2"/><circle cx="1140" cy="40" r="2"/>
<circle cx="40" cy="652" r="2"/><circle cx="1140" cy="652" r="2"/>
</g>
<!-- title -->
<text x="40" y="44" fill="#eaf6ff" font-size="22" font-weight="700">facett</text>
<text x="122" y="44" fill="#9fc9e0" font-size="15">reusable egui data-viewing components — RecordBatch in, pixels out, <tspan fill="#bfe6ff" font-weight="700">state_json</tspan> always emitted</text>
<!-- legend -->
<g font-size="12.5">
<line x1="800" y1="60" x2="840" y2="60" stroke="#6fd3f5" stroke-width="3"/>
<text x="848" y="64" fill="#cfe6f5">data flow</text>
<line x1="970" y1="60" x2="1010" y2="60" stroke="#7fb0cc" stroke-width="2.5" stroke-dasharray="5 4"/>
<text x="1018" y="64" fill="#cfe6f5">state_json spur</text>
</g>
<!-- ===================== INPUT SOURCES (left) ===================== -->
<rect x="36" y="104" width="152" height="52" rx="9" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
<text x="112" y="127" fill="#eaf6ff" font-size="13" font-weight="700" text-anchor="middle">RecordBatch</text>
<text x="112" y="145" fill="#9fc9e0" font-size="10" text-anchor="middle">Arrow columnar input</text>
<rect x="188" y="122" width="6" height="8" fill="#6fd3f5"/>
<rect x="36" y="174" width="152" height="52" rx="9" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
<text x="112" y="197" fill="#eaf6ff" font-size="13" font-weight="700" text-anchor="middle">node/edge labels</text>
<text x="112" y="215" fill="#9fc9e0" font-size="10" text-anchor="middle">graph topology</text>
<rect x="188" y="192" width="6" height="8" fill="#6fd3f5"/>
<rect x="36" y="244" width="152" height="52" rx="9" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
<text x="112" y="267" fill="#eaf6ff" font-size="13" font-weight="700" text-anchor="middle">lon/lat coords</text>
<text x="112" y="285" fill="#9fc9e0" font-size="10" text-anchor="middle">geo / WKB data</text>
<rect x="188" y="262" width="6" height="8" fill="#6fd3f5"/>
<rect x="36" y="314" width="152" height="52" rx="9" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
<text x="112" y="337" fill="#eaf6ff" font-size="13" font-weight="700" text-anchor="middle">DAG nodes</text>
<text x="112" y="355" fill="#9fc9e0" font-size="10" text-anchor="middle">pipeline / task graph</text>
<rect x="188" y="332" width="6" height="8" fill="#6fd3f5"/>
<!-- inputs -> facett-core junction -->
<g stroke="#6fd3f5" stroke-width="2.5" fill="none">
<path d="M194 126 H238"/>
<path d="M194 196 H238"/>
<path d="M194 266 H238"/>
<path d="M194 336 H238"/>
</g>
<circle cx="238" cy="230" r="5" fill="#bfecff"/>
<g stroke="#6fd3f5" stroke-width="1.5" fill="none">
<path d="M238 126 V230"/>
<path d="M238 196 V230"/>
<path d="M238 266 V230"/>
<path d="M238 336 V230"/>
</g>
<!-- ===================== FACETT-CORE KERNEL ===================== -->
<rect x="238" y="100" width="188" height="316" rx="12" fill="url(#rail)" stroke="#7fc8ea" stroke-width="2.5"/>
<text x="332" y="128" fill="#eaf6ff" font-size="14.5" font-weight="700" text-anchor="middle">facett-core</text>
<text x="332" y="148" fill="#9fc9e0" font-size="10.5" text-anchor="middle">shared kernel</text>
<!-- Facet trait -->
<rect x="260" y="162" width="144" height="50" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.6"/>
<text x="332" y="178" fill="#bfe6ff" font-size="10.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">trait Facet</text>
<text x="332" y="193" fill="#9fc9e0" font-size="9" text-anchor="middle">title() / ui() / state_json()</text>
<text x="332" y="206" fill="#7fa8c4" font-size="9" text-anchor="middle">three obligations</text>
<!-- Scene / Node / Edge -->
<rect x="260" y="220" width="144" height="34" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.6"/>
<text x="332" y="236" fill="#bfe6ff" font-size="10.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">Scene/Node/Edge</text>
<text x="332" y="249" fill="#9fc9e0" font-size="9.5" text-anchor="middle">layout engine</text>
<!-- draw() / wgpu -->
<rect x="260" y="262" width="144" height="34" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.6"/>
<text x="332" y="278" fill="#bfe6ff" font-size="10.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">draw() / wgpu</text>
<text x="332" y="291" fill="#9fc9e0" font-size="9.5" text-anchor="middle">fast path behind same API</text>
<!-- FacetDeck -->
<rect x="260" y="304" width="144" height="34" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.6"/>
<text x="332" y="320" fill="#bfe6ff" font-size="10.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">FacetDeck</text>
<text x="332" y="333" fill="#9fc9e0" font-size="9.5" text-anchor="middle">Vec<Box<dyn Facet>></text>
<text x="332" y="368" fill="#86b3cc" font-size="10" text-anchor="middle">source-agnostic</text>
<text x="332" y="384" fill="#86b3cc" font-size="10" text-anchor="middle">hand it Arrow/graph/geo</text>
<rect x="426" y="226" width="6" height="8" fill="#6fd3f5"/>
<!-- kernel -> component fan-out -->
<g stroke="#6fd3f5" stroke-width="3" fill="none">
<path d="M432 230 H472"/>
</g>
<circle cx="472" cy="230" r="5" fill="#bfecff"/>
<g stroke="#6fd3f5" stroke-width="2.5" fill="none">
<path d="M472 230 V140 H520"/>
<path d="M472 230 V192 H520"/>
<path d="M472 230 V246 H520"/>
<path d="M472 230 V300 H520"/>
<path d="M472 230 V354 H520"/>
</g>
<g fill="#bfecff">
<circle cx="520" cy="140" r="3"/>
<circle cx="520" cy="192" r="3"/>
<circle cx="520" cy="246" r="3"/>
<circle cx="520" cy="300" r="3"/>
<circle cx="520" cy="354" r="3"/>
</g>
<!-- ===================== COMPONENTS ===================== -->
<!-- facett-grid -->
<rect x="520" y="116" width="172" height="48" rx="9" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
<text x="606" y="138" fill="#eaf6ff" font-size="13" font-weight="700" text-anchor="middle">facett-grid</text>
<text x="606" y="156" fill="#9fc9e0" font-size="10" text-anchor="middle">table / RecordBatch view</text>
<rect x="692" y="134" width="6" height="8" fill="#6fd3f5"/>
<!-- facett-graph -->
<rect x="520" y="168" width="172" height="48" rx="9" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
<text x="606" y="190" fill="#eaf6ff" font-size="13" font-weight="700" text-anchor="middle">facett-graph</text>
<text x="606" y="208" fill="#9fc9e0" font-size="10" text-anchor="middle">node/edge scene render</text>
<rect x="692" y="186" width="6" height="8" fill="#6fd3f5"/>
<!-- facett-chart -->
<rect x="520" y="222" width="172" height="48" rx="9" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
<text x="606" y="244" fill="#eaf6ff" font-size="13" font-weight="700" text-anchor="middle">facett-chart</text>
<text x="606" y="262" fill="#9fc9e0" font-size="10" text-anchor="middle">metrics / time series</text>
<rect x="692" y="240" width="6" height="8" fill="#6fd3f5"/>
<!-- facett-map (geomap) -->
<rect x="520" y="276" width="172" height="48" rx="9" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
<text x="606" y="298" fill="#eaf6ff" font-size="13" font-weight="700" text-anchor="middle">facett-map</text>
<text x="606" y="316" fill="#9fc9e0" font-size="10" text-anchor="middle">geo tiles · WKB overlay</text>
<rect x="692" y="294" width="6" height="8" fill="#6fd3f5"/>
<!-- facett-pipeline -->
<rect x="520" y="330" width="172" height="48" rx="9" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
<text x="606" y="352" fill="#eaf6ff" font-size="13" font-weight="700" text-anchor="middle">facett-pipeline</text>
<text x="606" y="370" fill="#9fc9e0" font-size="10" text-anchor="middle">DAG/Spark job view</text>
<rect x="692" y="348" width="6" height="8" fill="#6fd3f5"/>
<!-- ===================== EGUI RENDER ===================== -->
<!-- components -> egui -->
<g stroke="#6fd3f5" stroke-width="2.5" fill="none">
<path d="M698 138 H742 V256 H786"/>
<path d="M698 190 H752 V260 H786"/>
<path d="M698 244 H786"/>
<path d="M698 298 H752 V268 H786"/>
<path d="M698 352 H742 V272 H786"/>
</g>
<circle cx="786" cy="256" r="5" fill="#bfecff"/>
<rect x="786" y="160" width="168" height="220" rx="11" fill="url(#rail)" stroke="#7fc8ea" stroke-width="2.5"/>
<text x="870" y="188" fill="#eaf6ff" font-size="14.5" font-weight="700" text-anchor="middle">egui render</text>
<text x="870" y="207" fill="#9fc9e0" font-size="10.5" text-anchor="middle">eframe viewport</text>
<text x="870" y="227" fill="#86b3cc" font-size="10" text-anchor="middle">themed pixels on screen</text>
<text x="870" y="247" fill="#86b3cc" font-size="10" text-anchor="middle">tab bar via FacetDeck</text>
<text x="870" y="271" fill="#bfe6ff" font-size="10.5" text-anchor="middle" font-weight="700">state_json output</text>
<text x="870" y="289" fill="#86b3cc" font-size="10" text-anchor="middle">every visible count/status</text>
<text x="870" y="305" fill="#a9d8ee" font-size="9.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">composed under Facet title</text>
<text x="870" y="325" fill="#86b3cc" font-size="10" text-anchor="middle">headless robot-test hook</text>
<text x="870" y="343" fill="#7fa8c4" font-size="9.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">$KORP_STATE / $NORNIR_VIZ_STATE</text>
<text x="870" y="363" fill="#7fa8c4" font-size="9.5" text-anchor="middle">used by korp + nornir</text>
<rect x="954" y="248" width="6" height="8" fill="#6fd3f5"/>
<!-- state_json output -->
<g stroke="#6fd3f5" stroke-width="3" fill="none">
<path d="M960 252 H1004"/>
</g>
<circle cx="1004" cy="252" r="4" fill="#bfecff"/>
<!-- ===================== STATE_JSON BLOCK ===================== -->
<rect x="1004" y="164" width="144" height="192" rx="11" fill="url(#chip)" stroke="#7fc8ea" stroke-width="2.5"/>
<text x="1076" y="192" fill="#eaf6ff" font-size="13" font-weight="700" text-anchor="middle">state_json</text>
<text x="1076" y="212" fill="#9fc9e0" font-size="10.5" text-anchor="middle">serde_json::Value</text>
<text x="1076" y="234" fill="#bfe6ff" font-size="10.5" text-anchor="middle" font-weight="700">always emitted</text>
<text x="1076" y="254" fill="#86b3cc" font-size="10" text-anchor="middle">per-facet observable</text>
<text x="1076" y="274" fill="#86b3cc" font-size="10" text-anchor="middle">FacetDeck composes</text>
<text x="1076" y="294" fill="#86b3cc" font-size="10" text-anchor="middle">all facets under title</text>
<text x="1076" y="318" fill="#a9d8ee" font-size="9.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">robot-test contract</text>
<text x="1076" y="335" fill="#a9d8ee" font-size="9.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">assert without display</text>
<text x="1076" y="351" fill="#7fa8c4" font-size="9" text-anchor="middle">korp / nornir live by this</text>
<rect x="998" y="244" width="6" height="8" fill="#6fd3f5"/>
<!-- state_json spur feedback -->
<path d="M1076 356 V460 H332 V420" stroke="#7fb0cc" stroke-width="2.5" fill="none" stroke-dasharray="6 4"/>
<circle cx="332" cy="420" r="4" fill="#7fb0cc"/>
<text x="700" y="476" fill="#86b3cc" font-size="10" text-anchor="middle">state_json flows back to host (korp / nornir) without display</text>
<!-- ===================== GROUND RAIL ===================== -->
<rect x="238" y="552" width="910" height="56" rx="10" fill="url(#rail)" stroke="#7fc8ea" stroke-width="2"/>
<g fill="#0a1c2c" stroke="#7fc8ea" stroke-width="1.5">
<circle cx="282" cy="580" r="4"/><circle cx="556" cy="580" r="4"/>
<circle cx="820" cy="580" r="4"/><circle cx="1044" cy="580" r="4"/>
</g>
<text x="298" y="579" fill="#dff1ff" font-size="15" font-weight="700">properties</text>
<text x="440" y="575" fill="#bcd9ec" font-size="11.5">source-agnostic · Arrow/graph/geo/DAG · wgpu fast path · state_json always emitted</text>
<text x="440" y="596" fill="#7fa8c4" font-size="10.5" font-family="'DejaVu Sans Mono', monospace">grid · graph · chart · map · pipeline · FacetDeck · robot-test contract · used by korp + nornir</text>
</svg>