Data Format
ArrowCrab reads a JSON object matching GraphData. The wire
format contains flat-packed numeric records and one shared string table.
Top-level object
interface GraphData {
subgraphs: number[];
nodes: number[];
edges: number[];
strings: string[];
}
Each packed array must have a length divisible by its record width. An empty strings[] is valid when no node records reference it; every node label and color otherwise
requires a valid string-table index.
Node records
Every three consecutive values in nodes[] form one record.
| Offset | Field | Meaning |
|---|---|---|
i + 0 | id | Safe-integer node ID |
i + 1 | label | Integer index into strings[] |
i + 2 | color | Integer index into strings[]; interpreted as a CSS color
by the renderer |
Edge records
Every four consecutive values in edges[] form one record.
| Offset | Field | Meaning |
|---|---|---|
i + 0 | sourceId | Source node ID |
i + 1 | sourcePort | Non-negative source output-port index below 4,294,967,295 |
i + 2 | targetId | Target node ID |
i + 3 | targetPort | Non-negative target input-port index below 4,294,967,295 |
Subgraph records
Every three consecutive values in subgraphs[] form one record.
| Offset | Field | Meaning |
|---|---|---|
i + 0 | nodeId | Compound node that owns the scope |
i + 1 | inId | Scope entry boundary node |
i + 2 | outId | Scope exit boundary node |
Validation rules
The validator applies these rules before constructing the resolved model:
- All ID and port fields are safe integers; label and color references are integer indexes.
- Node records may appear in any order. Node IDs must be unique.
-
Each edge references existing nodes and satisfies
sourceId < targetId. -
Each subgraph has three existing IDs, satisfies
inId < outId, and placesnodeIdoutside the closed interval[inId, outId]. -
Two subgraph records may not reuse the same
(inId, outId)pair. -
Every label and color reference is an integer index inside
strings[], and every string-table entry is a string. -
Port indexes are non-negative and less than
4,294,967,295.
The increasing-ID and edge-direction rules establish the topological order used by the viewer. The wire format carries scope boundaries rather than an explicit child list; scope membership is resolved from those intervals.
Scope semantics
A node belongs to the innermost scope whose open interval strictly contains
its ID: inId < nodeId < outId. Entry and exit boundary
nodes are excluded from a scope's nodeIds, and the compound
owner is outside the closed interval. Boundary ports still contribute to the
compound frame's port counts.
An edge belongs to the innermost scope for which both endpoints are inside, or one endpoint is inside and the other is that scope's boundary.
Port-count inference
Port counts are not stored in the wire format. For each node, the input
count is the maximum referenced targetPort + 1, and the output
count is the maximum referenced sourcePort + 1. The same
inference is used for entry and exit boundary nodes when the renderer draws
ports on a compound frame.