Architecture¶
Vixar is split between a Python library (data ingestion + scene config) and a
bundled JavaScript engine (viewer.js) that renders in WebGL2. They communicate
through a single versioned JSON contract and a typed postMessage protocol.
Python (vixar) JS engine (viewer.js)
read LAS/CSV/mesh ──► scene JSON ──► Scene Config Parser
pyproj UTM rebase Data Pipeline (Workers)
FastAPI / anywidget ◄─ events ◄── IRenderer → ThreeJSRenderer
Scene Manager (layers, slicer, LUT)
The renderer abstraction¶
All engine business logic is written against the IRenderer interface, never
directly against Three.js. ThreeJSRenderer is the v1 implementation; a
WebGPURenderer can be dropped in post-v1 without rewriting the engine.
UTM coordinate strategy¶
Large UTM coordinates (~500,000 m) lose precision in float32. At load time Python computes the scene-origin centroid across all layers, subtracts it to produce float32-safe local coordinates, and ships the origin in the config. The camera, measurements, and annotations all work in local coordinates; export adds the origin back to recover real-world UTM values.
Data pipeline & scale¶
- Tiling (
vixar tile) splits large LAS files into spatial binary tiles with ameta.jsonindex. - An octree frustum-culls tiles each frame; an LOD controller picks coarse vs. full density by distance.
- A byte-budgeted LRU cache bounds RAM; a WorkerPool parses tiles off the
main thread using Transferable
ArrayBuffers (no SharedArrayBuffer — keeps the viewer iframe-safe with no COOP/COEP headers). Crashed workers are restarted automatically and the offending tile is skipped.
Rust / WASM¶
vixar-wasm provides a Rust LAS parser and Marching Cubes, base64-inlined into
the bundle so viewer.js stays a single self-contained asset. The engine prefers
WASM and transparently falls back to the JS implementation when it is
unavailable.
Resilience (Phase 5)¶
- Progressive enhancement — without WebGL2 the viewer shows a clear message plus a 2-D summary table instead of crashing.
- Shader pre-warm — all layer GLSL programs compile up-front after a scene loads, so the first frame doesn't stall.
- Content-Security-Policy — emitted both as a
<meta>tag (to_html) and a response header (server);frame-ancestors *keeps the viewer embeddable.