IMMERSE Show File (.ishow) โ Schema Reference¶
Schema version: 0.5.0
Producer: IMMERSE Studio
Consumer: IMMERSE Runtime (this document is the Runtime team's target)
Format: UTF-8 JSON
This document describes the persistent format of an IMMERSE Show file. Files produced by IMMERSE Studio Save and Save As conform to this schema. Runtime is expected to load, validate, and play shows that conform to this version.
1. Top-level structure¶
{
"schema": "0.5.0",
"projectName": "Main Stage Opening Night",
"currentRoomId": "room-1",
"nodes": { /* NodeDB */ },
"sceneTree": { /* SceneTree */ },
"sceneTreeOrder": [ /* ordered tree ids */ ]
}
| Field | Type | Notes |
|---|---|---|
schema |
string | Always "0.5.0" for this version. Runtime should refuse other values or migrate. |
projectName |
string | User-visible show name. |
currentRoomId |
string | Which room the editor was last viewing. Runtime may ignore. |
nodes |
object | Global registry of compute nodes, keyed by node id. |
sceneTree |
object | Tree of show / rooms / scenes, keyed by entity id. |
sceneTreeOrder |
array | Display order of sceneTree entries. |
There is one global nodes registry; each room references node ids but does not own them. Rooms own their own cueLists, timelines, lighting looks, devices, logic graph, etc. โ see below.
2. The Scene Tree¶
A forest rooted at a single show-1 entity. Rooms are children of show-1. Other scene entities (scenes, arbitrary subfolders) may also appear.
2.1 Show entity¶
{
"type": "show",
"name": "Untitled Show",
"description": "",
"parent": null,
"icon": "๐",
"author": "",
"version": "1.0",
"notes": ""
}
2.2 Room entity¶
{
"type": "room",
"name": "Main Room",
"description": "",
"parent": "show-1",
"icon": "๐ ",
"widthM": 18,
"heightM": 9,
"canvasNodes": [],
"logic": { /* LogicGraph */ },
"logicWires": [ /* LogicWire */ ],
"patches": { /* legacy โ may be empty */ },
"patchOrder": [],
"devices": { /* DeviceInstances */ },
"deviceOrder": [],
"lightingLooks":{ /* Looks */ },
"lookOrder": [],
"shapes": { /* Shapes */ },
"shapeOrder": [],
"cueLists": { /* CueLists */ },
"cueListOrder": [],
"timelines": { /* Timelines */ },
"timelineOrder":[]
}
widthM / heightM are physical room dimensions in meters. Used for rendering the floor plan; Runtime may ignore if not using a spatial layer.
3. Nodes (global registry)¶
Keyed by node id (e.g. "aud-1", "vid-2", "gpio-1", "dmx-1").
"aud-1": {
"id": "aud-1",
"name": "Audio Node 1",
"roleClass": "audio",
"ip": "10.0.0.12",
"model": "IMMERSE A-1",
"gen": "V1",
"status": "online",
"cpu": 12,
"temp": 42,
"gpioDirs": {}
}
roleClass is one of audio | video | gpio | dmx. Runtime uses this to dispatch cue actions to the correct subsystem.
gpioDirs is a mapping { "gp1": "out", "gp2": "in" } for GPIO nodes only. Informational; Runtime may use this to validate cue channel references.
status/cpu/temp are authoring-time placeholders. Runtime should observe the actual device state at runtime and ignore these fields.
4. Devices (per-room)¶
devices is a map of device instances in the room, keyed by instance id. Each instance references a device-library template by type, and carries its physical position, optional rotation/label, and a patches object mapping library-defined port ids to node:channel targets.
"dev-1": {
"id": "dev-1",
"type": "MovingHead",
"name": "Moving Head L",
"x": 420, "y": 180, "rotation": 0,
"patches": {
"dmx-in": "dmx-1:ch-1",
"trigger-in":"gpio-1:gp4"
}
}
The set of available device types is defined in Studio's device library. Runtime doesn't need this library; it only needs the patches to resolve cue targets.
5. Lighting Looks (per-room)¶
"look-1": {
"id": "look-1",
"name": "Sunrise",
"durationMs": 5000,
"keyframes": [
{ "tMs": 0, "values": { "dev-1:ch-1": 0, "dev-1:ch-2": 64 } },
{ "tMs": 2500, "values": { "dev-1:ch-1": 200, "dev-1:ch-2": 255 } },
{ "tMs": 5000, "values": { "dev-1:ch-1": 255, "dev-1:ch-2": 255 } }
]
}
Each keyframe's values is a sparse map of device:channel keys to 0-255 DMX values. Runtime interpolates linearly between consecutive keyframes that both define a given channel. Channels not mentioned in a keyframe hold their previous value.
6. Cue Lists (per-room)¶
A room has zero or more cue lists. Each list is a flat ordered sequence of cues that an operator fires in order.
"cl-1": {
"name": "Act I",
"cues": { /* keyed by cue id */ },
"cueOrder": [ /* ordered cue ids */ ]
}
6.1 Cue fields (common to all types)¶
| Field | Type | Notes |
|---|---|---|
num |
string | Cue number shown in the list (e.g. "1.0", "12.5"). Not guaranteed numeric. |
type |
string | One of the 10 types below. |
name |
string | Human-readable label. |
dur |
string | Duration in seconds, text form (e.g. "5.00"). Parse with parseFloat. |
preWait |
string | Pre-wait in seconds. |
mode |
string | "MANUAL" \| "AUTO" \| "AUTO-FOLLOW". Controls sequence advance. |
indent |
number | Presentation-only indent level (0, 1, 2โฆ). |
6.2 Per-type fields¶
| Type | Additional fields | What Runtime does |
|---|---|---|
go |
(none) | Manual beat / spacer. No side-effect. |
group |
(none) | Container for nested cues. |
audio |
audioFile, audioNodeId |
Play audioFile on the node whose id is audioNodeId. |
video |
videoFile, videoNodeId |
Play videoFile on the node whose id is videoNodeId. |
dmx |
lookId |
Fire the Lighting Look with id lookId (lookup across any room). |
gpio |
gpioNodeId, gpioChannel, gpioAction ("pulse"\|"set"\|"clear") |
Drive the GPIO channel on the given node. |
fade |
fadeCurve ("linear"\|"ease-in"\|"ease-out"\|"ease-inout") |
Placeholder in v0.1.0 โ holds for dur. Runtime may decide to treat as wait, or leave room for v1.1 semantics. |
tc |
tcAction ("start"\|"stop"\|"goto"), tcGotoMs (number) |
Control the timecode transport. |
wait |
(none) | Hold for dur seconds. |
trigger |
triggerId |
Fire the logic node with id triggerId (same room only). |
For the Runtime team: All cue fields are present regardless of type; per-type fields are empty strings or default values when not relevant. Defensive Runtime code should feature-check the field it cares about rather than asserting shape based on type.
7. Timelines (per-room)¶
A room has zero or more timelines. Each timeline has a duration, a set of tracks, and a set of clips.
"tl-1": {
"name": "Main Show",
"durationMs": 60000,
"tracks": [
{ "id": "tr-1", "kind": "audio", "name": "Ambient", "color": "var(--r-audio)" },
{ "id": "tr-2", "kind": "dmx", "name": "Lighting", "color": "var(--r-dmx)" }
],
"clips": {
"clip-1": {
"id": "clip-1",
"trackId": "tr-2",
"tMs": 1000,
"durationMs": 5000,
"label": "Sunrise",
"targetId": "look-1"
}
},
"clipOrder": ["clip-1"]
}
7.1 Track kinds¶
audio | video | dmx | gpio | logic. Each clip on a track of a given kind is expected to resolve targetId in the context of that kind:
| Kind | targetId points at |
|---|---|
audio |
(free-text filename in v0.1.0 โ no targetId validation yet) |
video |
(free-text filename in v0.1.0) |
dmx |
lookId (any room's lightingLooks) |
gpio |
(free-text channel in v0.1.0) |
logic |
logic node id in the same room |
Runtime plays a timeline by sweeping a playhead from 0 to durationMs at 25 fps and firing each clip when its start edge is crossed. Clips are one-shot fire-on-cross; Runtime does not hold / loop / sustain clips unless extended semantics are added in future schema versions.
8. Logic Graph (per-room)¶
A room has a directed graph of logic nodes wired together.
"logic": {
"ln-1": { "id":"ln-1", "kind":"trigger", "label":"Start Show", "x": 100, "y": 80 },
"ln-2": { "id":"ln-2", "kind":"transport", "label":"TC Start", "x": 260, "y": 80,
"transportAction": "start" },
"ln-3": { "id":"ln-3", "kind":"dmx", "label":"Fire Sunrise", "x": 420, "y": 80,
"lookId": "look-1" }
},
"logicWires": [
{ "from": "ln-1", "to": "ln-2" },
{ "from": "ln-1", "to": "ln-3" }
]
8.1 Logic node kinds¶
| Kind | Purpose | Key fields |
|---|---|---|
trigger |
Entry point. Fired by trigger-type cues or external input. |
label |
condition |
Free-text expression gate. In v0.1.0 Runtime treats as always-true passthrough. | label, body (expression string) |
transport |
Drives the TC transport. | transportAction (start\|stop\|pause\|goto), optionally tcGotoMs |
audio |
Play audio on a node. | audioNodeId, audioFile |
video |
Play video on a node. | videoNodeId, videoFile |
dmx |
Fire a Lighting Look. | lookId |
gpio |
Drive a GPIO channel. | gpioNodeId, gpioChannel, gpioAction |
delay |
Hold for delayMs, then propagate. |
delayMs |
Runtime should walk the graph breadth-first from the fired entry-point node, applying each node's side-effect and propagating to wired successors. This matches the in-app fireLogicNode() semantics.
9. File identity & file extension¶
- Extension:
.ishow - MIME type (proposed):
application/vnd.immerse.show+json - Magic bytes: None. It's plain JSON. First non-whitespace byte is
{. - Runtime can distinguish
.ishowfrom other JSON by checking top-levelschemastarts with a version string that Runtime recognizes.
10. Migration notes for Runtime¶
If Runtime encounters schema values it doesn't know:
< "0.5.0": Runtime should refuse and ask the user to open + re-save the file in Studio. Studio auto-migrates on open.> "0.5.0": Runtime should refuse and warn that the file was produced by a newer Studio. Forward compatibility is not promised.
11. Known limitations in v0.1.0 (producer side)¶
These are things Studio does not yet emit, so Runtime doesn't need to handle them yet:
- Audio/video file references are free-text (no asset library, no checksums).
- GPIO channel names are free-text (no enumeration).
fadecues are placeholders โ thefadeCurvefield is set, but there's no semantic definition of what's being faded.- No operator-UI layout (deferred to v1.1).
- No security / signing / show hash.
These will be added in later schema versions. Runtime should not assume they exist.
12. Validation checklist for Runtime¶
Before playing a show, Runtime should validate:
- Every cue's
audioNodeId/videoNodeId/gpioNodeIdresolves to a node in the globalnodesregistry. - Every cue's
lookIdresolves to a look in some room'slightingLooks. - Every cue's
triggerIdresolves to a logic node in the same room the cue belongs to. - Every logic wire's
fromandtoresolve to logic nodes in the same room. - Every timeline clip's
trackIdresolves to a track in the same timeline. - Every timeline clip's
targetIdresolves in the context of its track'skind(see ยง7.1).
Studio's built-in validator (Ctrl+8) already flags these issues before save. A well-formed file from Studio should pass all Runtime checks. If Runtime sees a validation failure, it should blame Studio (bug report), not the user.