.nornir/assets/graphview_render.svg
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1180 560" 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>
<marker id="arrow" markerWidth="9" markerHeight="9" refX="7" refY="4" orient="auto">
<path d="M0 0 L8 4 L0 8 Z" fill="#6fd3f5"/>
</marker>
</defs>
<rect x="0" y="0" width="1180" height="560" fill="url(#board)"/>
<g stroke="#143a52" stroke-width="1">
<line x1="0" y1="76" x2="1180" y2="76"/>
<line x1="0" y1="512" x2="1180" y2="512"/>
</g>
<g fill="#16415c">
<circle cx="40" cy="40" r="2"/><circle cx="1140" cy="40" r="2"/>
<circle cx="40" cy="532" r="2"/><circle cx="1140" cy="532" r="2"/>
</g>
<!-- title -->
<text x="40" y="44" fill="#eaf6ff" font-size="22" font-weight="700">facett-graphview</text>
<text x="270" y="44" fill="#9fc9e0" font-size="15">one model → <tspan fill="#bfe6ff" font-weight="700">decide(probe)</tspan> → vello GPU <tspan fill="#9fc9e0">or</tspan> vello_cpu SIMD → RGBA pixels</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">render path</text>
<line x1="958" y1="60" x2="998" y2="60" stroke="#7fb0cc" stroke-width="2.5" stroke-dasharray="5 4"/>
<text x="1006" y="64" fill="#cfe6f5">deferred / stub</text>
</g>
<!-- ===================== INPUT: GraphModel + Decorations ===================== -->
<rect x="36" y="120" width="210" height="300" rx="10" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
<text x="141" y="146" fill="#eaf6ff" font-size="14.5" font-weight="700" text-anchor="middle">input model</text>
<text x="141" y="165" fill="#9fc9e0" font-size="10.5" text-anchor="middle">domain-agnostic</text>
<rect x="58" y="184" width="166" height="44" rx="5" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.4"/>
<text x="141" y="202" fill="#bfe6ff" font-size="10.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">GraphModel</text>
<text x="141" y="218" fill="#9fc9e0" font-size="9" text-anchor="middle">nodes id/label/pos/fill · edges from/to/dashed</text>
<rect x="58" y="240" width="166" height="44" rx="5" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.4"/>
<text x="141" y="258" fill="#bfe6ff" font-size="10.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">Decorations</text>
<text x="141" y="274" fill="#9fc9e0" font-size="9" text-anchor="middle">caller ring/badge + emphasis edges</text>
<rect x="58" y="296" width="166" height="40" rx="5" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.4"/>
<text x="141" y="313" fill="#bfe6ff" font-size="10.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">Camera::fit(...)</text>
<text x="141" y="328" fill="#9fc9e0" font-size="9" text-anchor="middle">world → viewport projection</text>
<text x="141" y="362" fill="#86b3cc" font-size="10" text-anchor="middle">mirrors nornir's</text>
<text x="141" y="377" fill="#86b3cc" font-size="10" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">src/viz/graph_render.rs</text>
<text x="141" y="394" fill="#7fa8c4" font-size="9.5" text-anchor="middle">SHARED API — drop-in for draw_graph</text>
<line x1="246" y1="270" x2="300" y2="270" stroke="#6fd3f5" stroke-width="3" marker-end="url(#arrow)"/>
<!-- ===================== decide(probe) ===================== -->
<rect x="300" y="150" width="200" height="240" rx="12" fill="url(#rail)" stroke="#7fc8ea" stroke-width="2.5"/>
<text x="400" y="176" fill="#eaf6ff" font-size="14.5" font-weight="700" text-anchor="middle">decide(GpuProbe)</text>
<text x="400" y="195" fill="#9fc9e0" font-size="10.5" text-anchor="middle">probe → pick (pure policy)</text>
<rect x="322" y="214" width="156" height="48" rx="6" fill="url(#slot)" stroke="#6fd3f5" stroke-width="1.6"/>
<text x="400" y="232" fill="#bfe6ff" font-size="10" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">usable_gpu && !force_cpu</text>
<text x="400" y="249" fill="#9fc9e0" font-size="9" text-anchor="middle">&& cfg!(feature = "gpu")</text>
<text x="400" y="288" fill="#86b3cc" font-size="10" text-anchor="middle">FACETT_GRAPHVIEW_CPU=1</text>
<text x="400" y="304" fill="#86b3cc" font-size="10" text-anchor="middle">forces CPU (golden PNGs / CI)</text>
<text x="400" y="326" fill="#a9d8ee" font-size="9.5" text-anchor="middle">mirrors nornir's embedder</text>
<text x="400" y="341" fill="#a9d8ee" font-size="9.5" text-anchor="middle">probe→pick runtime-select</text>
<text x="400" y="364" fill="#7fa8c4" font-size="9.5" text-anchor="middle">default build = GPU-dep-free</text>
<!-- fan to two backends -->
<g stroke="#6fd3f5" stroke-width="3" fill="none">
<path d="M500 230 H540 V200 H586" marker-end="url(#arrow)"/>
<path d="M500 310 H540 V340 H586" marker-end="url(#arrow)"/>
</g>
<!-- ===================== Backend::GpuVello ===================== -->
<rect x="586" y="150" width="220" height="92" rx="11" fill="url(#chip)" stroke="#7fc8ea" stroke-width="2"/>
<text x="696" y="176" fill="#eaf6ff" font-size="14" font-weight="700" text-anchor="middle">Backend::GpuVello</text>
<text x="696" y="194" fill="#9fc9e0" font-size="10.5" text-anchor="middle">vello 0.9 · wgpu 29 · egui-wgpu 0.34</text>
<text x="696" y="212" fill="#86b3cc" font-size="10" text-anchor="middle">GPU compute rasterization</text>
<text x="696" y="230" fill="#7fa8c4" font-size="9.5" text-anchor="middle">behind `gpu` feature · build_scene()</text>
<!-- ===================== Backend::CpuVello ===================== -->
<rect x="586" y="298" width="220" height="92" rx="11" fill="url(#chip)" stroke="#5aa6cf" stroke-width="2"/>
<text x="696" y="324" fill="#eaf6ff" font-size="14" font-weight="700" text-anchor="middle">Backend::CpuVello</text>
<text x="696" y="342" fill="#9fc9e0" font-size="10.5" text-anchor="middle">vello_cpu · multithreaded SIMD</text>
<text x="696" y="360" fill="#86b3cc" font-size="10" text-anchor="middle">always available (in epaint 0.34)</text>
<text x="696" y="378" fill="#7fa8c4" font-size="9.5" text-anchor="middle">the proven reference path</text>
<!-- GPU readback dashed -> CPU raster (spike: both route through cpu::render) -->
<path d="M696 242 V270 H586" stroke="#7fb0cc" stroke-width="2.5" fill="none" stroke-dasharray="6 4"/>
<text x="700" y="266" fill="#86b3cc" font-size="9">GPU readback = #17 follow-up → spike routes both through cpu::render</text>
<!-- backends -> render_to_rgba -->
<g stroke="#6fd3f5" stroke-width="3" fill="none">
<path d="M806 196 H840 V260 H876" marker-end="url(#arrow)"/>
<path d="M806 344 H840 V280 H876" marker-end="url(#arrow)"/>
</g>
<!-- ===================== render_to_rgba -> pixels ===================== -->
<rect x="876" y="190" width="160" height="160" rx="11" fill="url(#chip)" stroke="#7fc8ea" stroke-width="2.5"/>
<text x="956" y="216" fill="#eaf6ff" font-size="13.5" font-weight="700" text-anchor="middle">render_to_rgba</text>
<text x="956" y="236" fill="#9fc9e0" font-size="10" text-anchor="middle">one pixel contract</text>
<text x="956" y="262" fill="#86b3cc" font-size="10" text-anchor="middle">straight RGBA8</text>
<text x="956" y="280" fill="#86b3cc" font-size="10" text-anchor="middle">PNG / egui-texture ready</text>
<text x="956" y="304" fill="#a9d8ee" font-size="9.5" text-anchor="middle" font-family="'DejaVu Sans Mono', monospace">Rendered { rgba }</text>
<text x="956" y="324" fill="#7fa8c4" font-size="9.5" text-anchor="middle">tested: non-blank frame</text>
<line x1="1036" y1="270" x2="1090" y2="270" stroke="#6fd3f5" stroke-width="3" marker-end="url(#arrow)"/>
<circle cx="1100" cy="270" r="5" fill="#bfecff"/>
<!-- ===================== STUBBED rail ===================== -->
<rect x="300" y="436" width="736" height="58" rx="10" fill="#0a2032" stroke="#3c6a86" stroke-width="1.4" stroke-dasharray="3 3"/>
<text x="324" y="460" fill="#bfe6ff" font-size="12.5" font-weight="700">STUBBED (seams left, not built)</text>
<text x="324" y="481" fill="#86b3cc" font-size="10.5">LOD / viewport-culling · clustering / aggregation · edge-bundling · streaming layout · data-source adapters (nornir dep graph / FalkorDB / pipeline)</text>
<!-- footer -->
<text x="40" y="540" fill="#5e86a0" font-size="11" font-family="'DejaVu Sans Mono', monospace">facett-graphview/src/{model,backend,cpu,gpu}.rs · default = vello_cpu (no GPU dep) · gpu feature = vello 0.9 seam · spike #17</text>
</svg>