Files
xrwise-datastructure/data-structure-block-coding.md
T
2026-07-01 09:49:09 +02:00

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 Supabase rooms table — same column as the old node-graph format; the schema is distinguished by the presence of scripts (block coding) vs nodes/connections (legacy).
  • Save: the Zustand blockCoding store value is JSON-stringified and sent as graphical_coding in the FormData of PATCH /api/save-room/[id], which writes it directly to the graphical_coding column.
  • Load: roomData.graphical_coding is read in creator.tsx and hydrated into setBlockCoding(gc) in the Zustand store.
  • Local cache: Zustand's persist middleware also writes the value to localStorage under 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.tsx as TriggerBlock, EffectBlock, and BlockScript.