5.5 KiB
5.5 KiB
Block Coding — Database Save Format
This document describes the JSON structure stored in the Supabase rooms table under the graphical_coding column for the block coding system (replacing the old node-graph format).
Top-level shape
{
"scripts": [ ...BlockScript ]
}
The entire block coding state is one JSON blob — a flat array of scripts. Each script is self-contained (trigger + effects) with no cross-script references.
BlockScript
{
"id": "bl-1-1234567890",
"trigger": { ...TriggerBlock },
"effects": [ ...EffectBlock ]
}
| Field | Type | Description |
|---|---|---|
id |
string |
Unique script identifier, format bl-<index>-<timestamp> |
trigger |
TriggerBlock |
The single trigger block at the top of the script |
effects |
EffectBlock[] |
Ordered list of effect blocks stacked below the trigger |
TriggerBlock
{
"id": "bl-2-1234567890",
"event": "clicked",
"sourceItemId": 3,
"radius": 5,
"exitRadius": 5,
"cooldown": 500
}
| Field | Type | Description |
|---|---|---|
id |
string |
Unique block identifier |
event |
"clicked" | "proximity_enter" | "proximity_exit" |
The interaction event to watch for |
sourceItemId |
number | null |
Scene item ID to watch (null = no item selected yet) |
radius |
number |
Proximity enter radius in metres (only used when event is "proximity_enter") |
exitRadius |
number |
Proximity exit radius in metres (only used when event is "proximity_exit") |
cooldown |
number |
Minimum milliseconds between consecutive firings |
EffectBlock
All fields are always present regardless of effectProp. Fields that are irrelevant to the chosen property are stored but ignored at runtime.
{
"id": "bl-3-1234567890",
"effectProp": "color",
"targetObjectType": "item",
"targetItemId": 7,
"targetColor": "#ff3366",
"positionAxis": "x",
"targetPositionValue": 0,
"rotationAxis": "x",
"targetRotationValue": 0,
"targetScale": 1,
"targetVisibility": true,
"toggle": true
}
| Field | Type | Description |
|---|---|---|
id |
string |
Unique block identifier |
effectProp |
"color" | "position" | "rotation" | "scale" | "visibility" |
Which property this block modifies |
targetObjectType |
"item" | "sky" |
Whether to target a scene item or the sky color |
targetItemId |
number | null |
Scene item ID (only relevant when targetObjectType is "item") |
targetColor |
string |
Target hex color (used when effectProp is "color") |
positionAxis |
"x" | "y" | "z" |
Axis to move along (used when effectProp is "position") |
targetPositionValue |
number |
Target position on the chosen axis in world units |
rotationAxis |
"x" | "y" | "z" |
Axis to rotate around (used when effectProp is "rotation") |
targetRotationValue |
number |
Target rotation angle in degrees |
targetScale |
number |
Uniform scale multiplier (used when effectProp is "scale") |
targetVisibility |
boolean |
true = visible, false = hidden (used when effectProp is "visibility") |
toggle |
boolean |
When true, each trigger alternates between current state and target value instead of always applying the target. Not available for "visibility". |
Full example
A script that changes a cube's color and moves it along X when a visitor clicks it, using toggle mode so each click alternates between states:
{
"scripts": [
{
"id": "bl-1-1700000000001",
"trigger": {
"id": "bl-2-1700000000002",
"event": "clicked",
"sourceItemId": 4,
"radius": 5,
"exitRadius": 5,
"cooldown": 300
},
"effects": [
{
"id": "bl-3-1700000000003",
"effectProp": "color",
"targetObjectType": "item",
"targetItemId": 4,
"targetColor": "#c05580",
"positionAxis": "x",
"targetPositionValue": 0,
"rotationAxis": "x",
"targetRotationValue": 0,
"targetScale": 1,
"targetVisibility": true,
"toggle": true
},
{
"id": "bl-4-1700000000004",
"effectProp": "position",
"targetObjectType": "item",
"targetItemId": 4,
"targetColor": "#ffffff",
"positionAxis": "x",
"targetPositionValue": 3.0,
"rotationAxis": "x",
"targetRotationValue": 0,
"targetScale": 1,
"targetVisibility": true,
"toggle": true
}
]
}
]
}
Persistence notes
- Column:
graphical_coding(JSONB) in the Supabaseroomstable — same column as the old node-graph format; the schema is distinguished by the presence ofscripts(block coding) vsnodes/connections(legacy). - Save: the Zustand
blockCodingstore value is JSON-stringified and sent asgraphical_codingin theFormDataofPATCH /api/save-room/[id], which writes it directly to thegraphical_codingcolumn. - Load:
roomData.graphical_codingis read increator.tsxand hydrated intosetBlockCoding(gc)in the Zustand store. - Local cache: Zustand's
persistmiddleware also writes the value tolocalStorageunder the key"scene-storage", so edits survive a page refresh before an explicit save. - TypeScript types: defined inline in
components/creator/graphical-coding/graphical-coding-panel.tsxasTriggerBlock,EffectBlock, andBlockScript.