Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "lumen", "id": "counter",
"state": { "count": { "type": "int", "min": 0, "init": 0 } },
"transitions": { "inc": { "set": { "count": { "+": [ { "state": "count" }, { "lit": 1 } ] } } } },
"view": { "lit": { "type": "text", "content": "tap to count" } },
"events": [ { "on": "tap", "run": "inc" } ]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"type": "lumen", "id": "map-viz",
"state": { "tiles": { "type": "dataRef" }, "sel": { "type": "string", "maxLength": 64, "init": "" } },
"transitions": { "pick": { "set": { "sel": { "event": "id" } } } },
"view": { "lit": { "type": "scene", "width": 256, "height": 256, "draw": [] } },
"events": [ { "on": "tap", "run": "pick" } ],
"cadence": "reactive",
"capabilities": [
{ "cap": "loadData", "scope": { "dataRef": "tiles" } },
{ "cap": "tiles", "effect": "internal", "scope": { "provider": "osm" } }
],
"ports": [ { "name": "selection", "dir": "out", "type": "selection" } ],
"expose": [ { "name": "selection", "type": "selection" } ],
"preset": { "id": "preset-0123456789abcdef", "parent": "preset-fedcba9876543210", "params": { "zoom": 4 } }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"type": "lumen", "id": "pong",
"state": {
"x": { "type": "number", "min": 0, "max": 320, "init": 16 },
"vx": { "type": "number", "init": 2 },
"score": { "type": "int", "min": 0, "init": 0 },
"mode": { "type": "enum", "values": [ "run", "over" ], "init": "run" }
},
"transitions": {
"step": { "set": { "x": { "+": [ { "state": "x" }, { "state": "vx" } ] } } },
"left": { "set": { "vx": { "-": [ { "lit": 0 }, { "lit": 2 } ] } } }
},
"view": { "lit": { "type": "scene", "width": 320, "height": 200, "draw": [ { "kind": "circle", "cx": 16, "cy": 100, "r": 8, "fill": "accent" } ] } },
"events": [
{ "on": "tick", "rate": 60, "run": "step" },
{ "on": "key", "key": "ArrowLeft", "run": "left" }
],
"cadence": { "tick": 60 }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"type": "lumen", "id": "life",
"state": { "board": { "type": "grid", "w": 16, "h": 16, "of": { "type": "bool", "init": false } } },
"transitions": { "toggle": { "set": { "board": { "lit": true } } } },
"view": { "lit": { "type": "scene", "width": 256, "height": 256, "draw": [] } },
"events": [ { "on": "tap", "run": "toggle" }, { "on": "tick", "rate": 8, "run": "toggle" } ],
"cadence": { "tick": 8 }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "lumen", "id": "x", "state": {}, "transitions": {}, "view": { "lit": 1 }, "events": [], "capabilities": [ { "cap": "exec" } ] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "lumen", "id": "x", "state": {}, "transitions": {}, "view": { "lit": 1 }, "events": [], "preset": { "id": "my-preset" } }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "lumen", "id": "x", "state": { "n": { "type": "int" } }, "transitions": {}, "view": { "lit": 1 }, "events": [] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "lumen", "id": "x", "state": {}, "transitions": {}, "view": { "while": [ { "lit": 1 } ] }, "events": [] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "lumen", "id": "x", "state": {}, "transitions": {}, "view": { "lit": 1 }, "events": [], "script": "alert(1)" }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "lumen", "id": "x", "state": {}, "transitions": {}, "events": [] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "lumen", "id": "x", "state": {}, "transitions": {}, "view": { "lit": 1 }, "events": [ { "on": "tick", "rate": 120, "run": "step" } ] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "lumen", "id": "x", "state": {}, "transitions": {}, "view": { "lit": 1 }, "events": [ { "on": "scroll", "run": "step" } ] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "+": [ { "lit": 1 }, { "state": "score" } ] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "call": "map", "args": [ { "state": "cells" }, { "call": "clamp", "args": [ { "event": "v" }, { "lit": 0 }, { "lit": 9 } ] } ] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "call": "map", "args": [ { "state": "rows" }, { "get": { "var": "it" }, "key": { "lit": "label" } } ] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "get": { "record": { "x": { "lit": 10 }, "y": { "lit": 20 } } }, "key": { "lit": "x" } }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "state": "board", "at": [ { "event": "x" }, { "event": "y" } ] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "if": { ">": [ { "state": "x" }, { "lit": 0 } ] }, "then": { "lit": "pos" }, "else": { "lit": "nonpos" } }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "let": { "n": { "state": "count" } }, "in": { "*": [ { "lit": 2 }, { "lit": 3 } ] } }
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{ "call": "fold", "args": [
{ "call": "map", "args": [ { "state": "cells" }, { "*": [ { "var": "it" }, { "lit": 2 } ] } ] },
{ "lit": 0 },
{ "+": [ { "var": "acc" }, { "var": "it" } ] }
] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "match": { "state": "mode" }, "cases": [ { "when": { "lit": "run" }, "then": { "lit": 1 } } ], "else": { "lit": 0 } }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "record": { "x": { "lit": 1 }, "y": { "state": "y" } } }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "set": { "score": { "+": [ { "state": "score" }, { "lit": 1 } ] } } }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "/": [ { "lit": 1 } ] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "call": "eval", "args": [ { "lit": "1+1" } ] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "lit": 1, "sneaky": 2 }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "get": { "lit": [1,2,3] } }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "if": { "lit": true }, "then": { "lit": 1 } }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"state.score + 1"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "+": [ { "lit": 1 }, { "lit": 2 } ], "-": [ { "lit": 3 }, { "lit": 4 } ] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "while": [ { "lit": true }, { "lit": 1 } ] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "scene", "width": 10, "height": 10, "draw": [] }
12 changes: 12 additions & 0 deletions middleware/packages/canvas-core/fixtures/scene/accept/shapes.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{ "type": "scene", "id": "s1", "width": 320, "height": 200,
"camera": { "x": 0, "y": 0, "zoom": 1 },
"draw": [
{ "kind": "rect", "x": 8, "y": 8, "w": 64, "h": 32, "r": 6, "fill": "surface-raised", "stroke": "accent", "strokeW": 2, "id": "card" },
{ "kind": "circle", "cx": 160, "cy": 100, "r": 24, "fill": "accent.glow", "id": "ball" },
{ "kind": "line", "x1": 0, "y1": 0, "x2": 320, "y2": 200, "stroke": "text-faint" },
{ "kind": "path", "points": [ [0,0], [10,20], [20,0] ], "closed": true, "fill": "success" },
{ "kind": "text", "x": 12, "y": 24, "text": "Score 42", "size": 14, "weight": 600, "register": "mono", "fill": "text", "id": "score" },
{ "kind": "group", "transform": { "x": 100, "y": 100, "scale": 1.5, "rotate": 0 }, "children": [
{ "kind": "rect", "x": 0, "y": 0, "w": 8, "h": 8, "fill": "danger" }
] }
] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "scene", "width": 10, "height": 10, "draw": [ { "kind": "circle", "cx": 1, "cy": 1, "r": 1, "onClick": "x" } ] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "scene", "width": 10, "height": 10, "draw": [ { "kind": "rect", "x": 0, "y": 0, "w": 1, "h": 1, "fill": "#ff0000" } ] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "scene", "draw": [] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "scene", "width": 10, "height": 10, "draw": [ { "kind": "polygon", "points": [ [0,0] ] } ] }
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "type": "canvas", "width": 10, "height": 10, "draw": [] }
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://omadia.ai/protocol/1.1/capability-manifest.schema.json",
"title": "Capability manifest — the mediated doors",
"description": "omadia-canvas-protocol/1.1 (lumens-spec.md §6): default-deny. Each capability is declared, effect-classified (local/internal/external-effect), granted by Tier 2, and BROKERED — a Lumen never performs the effect directly. The agent owns capability REQUESTS; grants are Tier-2 policy + user consent (§0.5) — a patch can ask, never self-grant. Imported/shared Lumens surface this manifest for consent before first run.",

"$ref": "#/$defs/capabilityList",

"$defs": {
"capabilityName": {
"description": "lumens-spec.md §6 catalog",
"enum": ["persist", "loadData", "writeData", "tiles", "fetch", "generateAsset", "clipboard", "share", "savePreset"]
},

"effectClass": {
"description": "CONCEPT.md §Security Surface effect classes. Egress carrying state/DataRef-derived data is external-effect (per-call confirmation) unless pre-approved at grant (§6).",
"enum": ["local", "internal", "external-effect"]
},

"capabilityRequest": {
"type": "object", "additionalProperties": false, "required": ["cap"],
"properties": {
"cap": { "$ref": "#/$defs/capabilityName" },
"effect": { "$ref": "#/$defs/effectClass", "description": "agent's declared/expected class; Tier 2 re-derives and may upgrade (never downgrade)" },
"scope": {
"type": "object",
"description": "per-capability scope (spike-tunable). e.g. {namespace} for persist; {dataRef} for loadData; {endpoints:[...], shape} for fetch; {provider} for tiles; {kind} for generateAsset; {writeCapabilities} for writeData.",
"additionalProperties": true
}
}
},

"capabilityList": {
"type": "array",
"items": { "$ref": "#/$defs/capabilityRequest" }
}
}
}
96 changes: 96 additions & 0 deletions middleware/packages/canvas-core/schema/lumen.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://omadia.ai/protocol/1.1/lumen.schema.json",
"title": "Lumen — Live Interactivity unit",
"description": "omadia-canvas-protocol/1.1 (lumens-spec.md §1): a self-contained interactive unit on the canvas — declarative DATA, not code. Delivered as tree content inside an ordinary surface_snapshot/surface_patch (no new transport). A Lumen is valid iff its state conforms to §1.1, every LXNode passes the §2 AST whitelist + static bounds check, every EventBinding names a declared transition + §4 event, every CapabilityRequest names a §6 catalog capability, and every PortSpec/ExposeSpec is §7-typed. Any failure ⇒ rejected wholesale with surface_error (it never partially renders). This schema enforces the STRUCTURAL contract; the L1 static validator enforces semantics JSON Schema cannot (path resolution, gas/iteration bounds, transition/event coherence).",

"$ref": "#/$defs/lumen",

"$defs": {
"lumen": {
"type": "object",
"additionalProperties": false,
"required": ["type", "id", "state", "transitions", "view", "events"],
"properties": {
"type": { "const": "lumen" },
"id": { "type": "string", "description": "stable; patches/wires/beam target it" },
"state": { "$ref": "#/$defs/stateSchema" },
"transitions": {
"type": "object",
"description": "TransitionName → pure (state,event)->state LX expression",
"additionalProperties": { "$ref": "https://omadia.ai/protocol/1.1/lx-ast.schema.json" }
},
"view": {
"$ref": "https://omadia.ai/protocol/1.1/lx-ast.schema.json",
"description": "pure state -> primitive/scene tree (an LX expression; a static view is {lit: <tree>})"
},
"events": { "type": "array", "items": { "$ref": "#/$defs/eventBinding" } },
"cadence": { "$ref": "#/$defs/cadenceSpec" },
"capabilities": { "$ref": "https://omadia.ai/protocol/1.1/capability-manifest.schema.json#/$defs/capabilityList" },
"ports": { "$ref": "https://omadia.ai/protocol/1.1/ports-wires.schema.json#/$defs/portsList" },
"expose": { "$ref": "https://omadia.ai/protocol/1.1/ports-wires.schema.json#/$defs/exposeList" },
"preset": { "$ref": "#/$defs/presetRef" }
}
},

"stateSchema": {
"type": "object",
"description": "a typed, CLOSED record (§1.1). Total serialised size is capped (default 256 KB, spike-tunable) — enforced by L1.",
"additionalProperties": { "$ref": "#/$defs/stateLeaf" }
},

"stateLeaf": {
"type": "object",
"oneOf": [
{ "additionalProperties": false, "required": ["type", "init"],
"properties": { "type": { "enum": ["int", "number"] }, "min": { "type": "number" }, "max": { "type": "number" }, "init": { "type": "number" } } },
{ "additionalProperties": false, "required": ["type", "init"],
"properties": { "type": { "const": "bool" }, "init": { "type": "boolean" } } },
{ "additionalProperties": false, "required": ["type", "maxLength", "init"],
"properties": { "type": { "const": "string" }, "maxLength": { "type": "integer", "minimum": 0 }, "init": { "type": "string" } } },
{ "additionalProperties": false, "required": ["type", "values", "init"],
"properties": { "type": { "const": "enum" }, "values": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, "init": { "type": "string" } } },
{ "additionalProperties": false, "required": ["type", "of", "maxLen", "init"],
"properties": { "type": { "const": "list" }, "of": { "$ref": "#/$defs/stateLeaf" }, "maxLen": { "type": "integer", "minimum": 0 }, "init": { "type": "array" } } },
{ "additionalProperties": false, "required": ["type", "fields", "init"],
"properties": { "type": { "const": "record" }, "fields": { "$ref": "#/$defs/stateSchema" }, "init": { "type": "object" } } },
{ "additionalProperties": false, "required": ["type", "w", "h", "of"],
"properties": { "type": { "const": "grid" }, "w": { "type": "integer", "minimum": 1 }, "h": { "type": "integer", "minimum": 1 }, "of": { "$ref": "#/$defs/stateLeaf" }, "init": {} } },
{ "additionalProperties": false, "required": ["type"],
"properties": { "type": { "const": "dataRef" }, "init": { "$ref": "https://omadia.ai/protocol/1.0/data-ref.schema.json" } } }
]
},

"eventBinding": {
"type": "object", "additionalProperties": false, "required": ["on", "run"],
"properties": {
"on": { "enum": ["tap", "longPress", "drag", "pinch", "swipe", "pointerMove", "key", "tick", "timer", "wire"] },
"target": { "$ref": "https://omadia.ai/protocol/1.0/target-ref.schema.json" },
"key": { "type": "string", "description": "for 'key' — declared keys only (e.g. 'ArrowLeft','Space')" },
"rate": { "type": "number", "exclusiveMinimum": 0, "maximum": 60, "description": "for 'tick' — declared, capped ≤60 Hz (§5)" },
"everyMs": { "type": "number", "exclusiveMinimum": 0, "description": "for 'timer' — enforced minimum period; combined tick+timer wakeup budget is capped (§4)" },
"captureLongPress": { "type": "boolean", "description": "claim longPress over host context-invoke (§4)" },
"run": { "type": "string", "description": "the transition to evaluate" }
}
},

"cadenceSpec": {
"description": "declared per node/region, not globally (§5). default 'reactive'.",
"oneOf": [
{ "enum": ["static", "reactive"] },
{ "type": "object", "additionalProperties": false, "required": ["tick"],
"properties": { "tick": { "type": "number", "exclusiveMinimum": 0, "maximum": 60, "description": "Hz, ≤60" } } }
]
},

"presetRef": {
"type": "object", "additionalProperties": false, "required": ["id"],
"description": "provenance if instantiated/forked (§8)",
"properties": {
"id": { "type": "string", "pattern": "^preset-[0-9a-f]{16}$", "description": "content-addressed preset-<sha256(spec)[:16]>" },
"parent": { "type": "string", "pattern": "^preset-[0-9a-f]{16}$", "description": "fork lineage" },
"params": { "type": "object", "additionalProperties": true }
}
}
}
}
Loading
Loading