50 lines
3.8 KiB
Markdown
50 lines
3.8 KiB
Markdown
# Spatial Lab JSON contract, version 1
|
||
|
||
## Editable project: `spatial-lab.project/1`
|
||
|
||
```json
|
||
{
|
||
"schema": "spatial-lab.project/1",
|
||
"id": "corridor-study",
|
||
"name": "Corridor study",
|
||
"parameters": {"length": 10},
|
||
"nodes": [
|
||
{"id":"axis","op":"polyline","version":1,"visible":false,
|
||
"params":{"points":[[0,0,0],[0,"length",0]]}},
|
||
{"id":"basis","op":"frames","visible":false,"inputs":{"path":"axis"}},
|
||
{"id":"deck","op":"sweep","inputs":{"frames":"basis"},
|
||
"params":{"profile":[[-1,-0.15],[1,-0.15],[1,0.15],[-1,0.15]]},
|
||
"color":[0.4,0.56,0.68],"role":"gallery"}
|
||
]
|
||
}
|
||
```
|
||
|
||
`id` identifies a project for ownership in the Blender adapter. Use a different project ID for independently managed studies in the same scene. Node IDs identify graph operations, never rename them during ordinary parameter edits. Version defaults to 1; visibility defaults to true. `name`, `color` and `role` are optional semantic presentation metadata. Parameters may be numbers or bounded arithmetic expressions. Dependencies are explicitly listed in `inputs`, as a node ID or list of node IDs. Cycles and missing references fail validation.
|
||
|
||
## Evaluated bundle: `spatial-lab.bundle/1`
|
||
|
||
| Field | Meaning |
|
||
| --- | --- |
|
||
| `project_id`, `name` | Source project identity |
|
||
| `units`, `handedness`, `up_axis` | Always `meters`, `right`, `+Z` |
|
||
| `matrix_convention` | Row arrays, column vectors, local-to-world matrices |
|
||
| `recipe` | Complete original project for further editing |
|
||
| `project_hash` | SHA-256 of canonical recipe JSON |
|
||
| `nodes` | Evaluated node summaries, input links and parameters |
|
||
| `geometries` | Dictionary keyed by geometry hash; each value has `vertices` and `faces` |
|
||
| `objects` | Stable ID, node ID, kind, transform, semantic metadata and geometry reference/data |
|
||
| `bounds` | World-space axis-aligned `min`/`max` |
|
||
| `validation` | Mesh reports, warnings, and explicit flags for checks not performed |
|
||
| `stats` | Node/object counts, unique vertex/mesh counts, triangles including instances |
|
||
| `bundle_hash` | SHA-256 of canonical bundle JSON excluding this field |
|
||
|
||
Every vertex is `[x,y,z]` in metres. Every face is exactly three zero-based vertex indices with outward winding for solid meshes. Geometry hash covers the complete `{"vertices":...,"faces":...}` object. Mesh instances reference it through `geometry`; they do not duplicate vertex arrays.
|
||
|
||
Every object has `id`, `node_id`, `name`, `kind`, `role`, `color` and a 4×4 `matrix`. Its bottom row is `[0,0,0,1]`; matrices are invertible and orientation-preserving. Translation is in the last column. A local position becomes `matrix * [x,y,z,1]`. Colour has three normalized RGB components.
|
||
|
||
Mesh object IDs combine node ID and part key, e.g. `braided-galleries/0000/main`. A curve object instead embeds `points` and `closed` and uses ID `NODE/path`. Its points are joined in order, with the final-to-first edge added only for closed curves. Frames are individual objects of kind `frame`, with local axes in matrix columns and their origin in its last column; ID `NODE/frame-0000`.
|
||
|
||
Canonical JSON is the Python kernel's `json.dumps(value, sort_keys=True, separators=(',', ':'), allow_nan=False)` encoded as UTF-8. These integrity hashes are for reproducibility and accidental-corruption detection, not authentication. `validate_bundle` checks the supported convention, hashes, references, finite coordinates, transforms and triangle/edge structure before import. Bundles should be generated by `build` rather than assembled manually. A consumer only needs the evaluated geometry and matrices to reproduce the shape; it does not need the expression evaluator or custom operators.
|
||
|
||
Blender natively uses the same axis convention. Unity/Godot/custom-engine adapters must explicitly convert basis/units and triangle winding if their chosen basis changes handedness. No such engine adapter is included yet.
|