Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

facett-graph3d/.nornir/system-map-fluid-design.md

System Map — fluid flowing through glass pipes (design)

A selectable demo in facett-demo: a nice little map of the nordisk constellation where components are labelled glass tanks/junctions joined by glass pipes with fluid visibly flowing through them (fluid = data / activity moving between components). This doc records how it is modelled, how the glass-pipe render works, how the fluid steps, and exactly how zero-copy / zero-alloc / zero-wait are met on the frame path.

Where the pieces live (L5 reuse — nothing twinned)

Piece Crate Reuses
The fluid solver facett-cfd::fluid::FluidField znippy gatling (gatling_run)
The glass-pipe render skin facett-graph3d::pipes::SystemMap Graph3D camera/projection/layout/selection · neon glow orbs · graph_gpu bloom lane
The demo wiring facett-demo::demo_systemmap the deck picker + LEGEND + the mega-matrix

SystemMap is a skin over Graph3D exactly like CodeVault: the orbit/spin camera, the Layout3D node placement, the orthographic projection and the click-selection all come from an embedded Graph3D (its Graph3DView IS the Elm Model). The map adds only the genuinely new bits: the glass-pipe / glass-tank paint and the fluid→pipe wiring. No new renderer, no new fluid solver.

Dependency direction is clean (no cycle): facett-graph3d → facett-cfd; facett-cfd does not depend on facett-graph3d.

The model (nodes / pipes + where the topology comes from)

SystemMap::new(nodes: Vec<(label, Color32)>, edges: Vec<(from, to)>, layout):

The glass-pipe render (which renderer, the transparency/fresnel approach)

Reuses Graph3D's projection (project_all → screen pos + depth) and paints on the egui painter (the always-available CPU lane, wasm-clean — same as CodeVault's transparent boxes). Per pipe (paint_glass_pipe, back-to-front by depth):

  1. Translucent wall — a filled quad the width of the pipe at GLASS_ALPHA = 0.16 (× a depth term), so far pipes + the fluid show through the glass.
  2. Fresnel rim — a brighter thin stroke down both silhouette edges (glass edges catch light).
  3. Specular streak — a thin white highlight offset toward the light (the glossy sheen).

The fluid inside (paint_fluid) samples the pipe's dye row borrowed from the FluidField and draws it as a luminous column whose per-segment alpha follows the local dye — so the pulsing inlet packets read as bright slugs marching in the flow direction, with a bright specular core on hot packets.

Nodes (paint_glass_node) are glass tanks: a translucent tinted body + a frosted core + a fresnel rim ring + a specular highlight dot, with a neon::paint_node_orb emissive glow behind (bloom-fed on the GPU lane).

GPU path (feature gpu → facett-graph3d/wgpu): SystemMap::gpu_scene feeds tank centres + pipes (radiance scaled by each pipe's live dye load, so a gushing pipe blooms hotter) into the reused graph_gpu additive-HDR + bright-pass + gaussian-blur bloom lane — the same bloom Graph3D/CodeVault use. Without a GPU (headless CI / wasm) the CPU translucent paint above draws; the wgpu snapshot test still renders it onto a real GPU texture (Loki's RTX 5080).

The fluid step (facett-cfd + GPU-vs-gatling)

FluidField is a 1-D dye advection per pipe (CELLS = 48 samples): upwind advection at a signed per-pipe velocity (= flow direction/rate), gentle diffusion, slight decay, and a pulsing dye source injected at the inlet so packets form and travel. Pipes are independent ⇒ embarrassingly parallel.

This is facett-cfd's first gatling consumer and a reusable accelerated fluid API any facett app can drop on its edges (FluidField::new / set_flow / step / dye).

The three zeroes — EXACTLY how they're met on the frame path

Testing (L4 — it's visual, so it's robot/snapshot tested)