Scene Graph
The scene graph is a C# object graph that models the physical plant — equipment, pipes, structures, and instruments. It is rendered server-side to SVG and streamed to the browser via SignalR. Equipment symbols follow the ISA 5.1 standard.
How it works
sequenceDiagram
participant PLC as PLC
participant Orin as Edge Device
participant Grain as DeviceInstanceGrain
participant SG as Scene Graph
participant SR as SceneRenderer
participant Hub as SignalR Hub
participant Browser as Browser
PLC->>Orin: Tag value change
Orin->>Grain: gRPC tag update
Grain->>SG: TagBinding resolves
SG->>SG: Mark dirty nodes
SG->>SR: Re-render dirty SVG fragments
SR->>Hub: Push SVG patch
Hub->>Browser: WebSocket message
Browser->>Browser: Patch DOM
Target latency: PLC tag change → visual update in the browser in under 500ms.
Type hierarchy
Core nodes
| Node | Purpose |
Scene | Root container — one per process visualisation |
SceneNode | Base class for all nodes in the tree |
GroupNode | Logical grouping of child nodes |
ViewportNode | Defines a pannable/zoomable view area |
LayerNode | Z-ordered rendering layer (e.g. pipes behind equipment) |
Primitives
| Node | Purpose |
Rect | Rectangle with optional corner radius |
Circle | Circle or ellipse |
Path | SVG path for arbitrary shapes |
Text | Text label with font, size, and alignment |
Equipment (ISA 5.1)
| Node | Purpose |
PumpNode | Centrifugal, positive displacement, submersible |
MotorNode | Electric motor with rotation indicator |
ValveNode | Gate, globe, butterfly, check — with position binding |
TankNode | Vessel with level indicator |
PipeNode | Pipe segment with flow animation |
InstrumentNode | Pressure, temperature, flow, level transmitter |
ConveyorNode | Belt conveyor with speed and running state |
CrusherNode | Jaw, cone, impact crusher |
ScreenNode | Vibrating screen with throughput indicator |
FeederNode | Apron, belt, vibratory feeder |
Structures
| Node | Purpose |
DamNode | Tailings dam or water storage with level |
BuildingNode | Structure outline — crusher house, substation |
Annotations
| Node | Purpose |
TagDisplayNode | Live tag value with label and engineering units |
AlarmIndicatorNode | Alarm state indicator (flashing, colour-coded) |
HealthBadgeNode | Equipment health summary from edge ML |
Animation
| Type | Purpose |
Flow | Animated dashes along a pipe to indicate flow direction and rate |
Pulse | Pulsing glow on active equipment |
Rotation | Spinning motor or pump impeller |
Level | Fill level animation in tanks and dams |
Data binding
Scene graph nodes are bound to live data through binding objects:
| Binding | Source | Example |
TagBinding | Device instance tag value | Pump speed → motor rotation rate |
StateBinding | Discrete state (running, stopped, faulted) | Valve state → open/closed symbol |
AlarmBinding | Alarm state (active, acknowledged, cleared) | High temp → red indicator flash |
AIBinding | Edge ML inference result | Anomaly score → health badge colour |
When a bound value changes, the binding marks its node (and any ancestors that need re-compositing) as dirty. The renderer only re-renders dirty subtrees.
State flow — PLC to pixel
The full data path from a PLC register change to a visual update:
- PLC — a tag value changes (e.g. pump speed ramps up).
- Edge device — the Orin reads the new value via libplctag (EtherNet/IP).
- gRPC — the edge device sends the tag update to the site server.
- DeviceInstanceGrain — the grain stores the new value and publishes to the tag stream.
- TagBinding — the binding on the scene graph node resolves the new value.
- Dirty marking — the node and its rendering ancestors are marked dirty.
- SceneRenderer — re-renders only the dirty SVG fragments.
- SignalR — pushes the SVG patch to connected browsers.
- Browser — the TypeScript client patches the DOM node in place.
Rendering evolution
The scene graph is designed as an abstract model that is independent of the rendering backend:
| Phase | Renderer | Status |
| Current | Server-side SVG | Production |
| Next | 2D raster canvas (server-side) | Planned |
| Future | 3D WebGL / AR | Research |
Because rendering happens on the server and only the output (SVG, canvas frames, or 3D scene descriptions) is sent to the client, the browser client never changes when the rendering backend evolves. The same TypeScript shell that patches SVG today will receive canvas frames or WebGL scene updates tomorrow.