feat(visual): add the slice 4g challenge fixtures and reference exhibits

Fourteen visual challenge fixtures and the first visuals for reference exhibits
A through D, all executing without a line of subject-specific renderer code —
which is the claim slice 4g exists to test. A subject the engine needs special
handling for is a subject the format cannot express.

The standalone CLI validator no longer disagrees with the production one. It
had been falling through to ERR_UNSUPPORTED_TARGET for every `visuals.*` binding
target, so legal exhibits — including the committed minimal-visual fixture —
failed the CLI while passing the runtime. The four section 8.1 visual target
families are now recognized in both, and a test runs the CLI validator across
every exhibit and challenge fixture so the two paths cannot drift apart again.

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01ShxxFqFmCUDQnQvFNm4TKy
This commit is contained in:
2026-09-06 21:53:38 +00:00
co-authored by Claude Opus 5
parent a579b8e41f
commit d5d7091289
22 changed files with 2616 additions and 1 deletions
@@ -0,0 +1,11 @@
# Slice 4g: challenge fixtures and first exhibit visuals
Implemented September 6, 2026. `tools/visual-challenge-fixtures.mjs` authors all fourteen PRD 130 challenge compositions and first visuals for Exhibits AD. Generated `.xzbt` files are under `exhibits/visual-challenges` and `exhibits/exhibit-{a,b,c,d}.xzbt`.
Each composition uses only existing generic primitives, systems, fields, behaviors, bindings and effects. No subject-specific renderer branch was added. The challenge suite validates every document, executes 120 logical ticks twice with different draw frequencies, verifies finite geometry and nonempty frame plans, compares final plans, and verifies cleanup. A nineteenth test checks deterministic standalone generation, embedded fixture identity and JavaScript syntax.
The standalone `prototypes/phase4/XZBT-visual-acceptance.html` embeds production code and all eighteen fixtures. It provides fixture selection, pause/resume, seed restart, transient spawning, synthetic audio/state sliders and user observation export. Rebuild with `npm run build:visual-acceptance`.
Exhibit D uses static text labels and state-driven geometry/layer presentation under the 0.1 contract. Live numeric string formatting was not added. The audio-reactive fixture uses the shared signal-binding surface; its review-page slider supplies an explicitly synthetic signal. Full AD audio, cadence, scenario and final reference-suite obligations remain assigned to their later phases.
The PRD 130 visual judgment is still a user-observed gate, and this artifact is not the 4h benchmark. No browser/display judgment or measured GC6 result is claimed by these tests.
+110
View File
@@ -0,0 +1,110 @@
{
"xzbt": "0.1",
"meta": {
"id": "exhibit-a",
"name": "Exhibit A — Procedural Machine",
"version": "0.1.0",
"description": "First visual composition; full reference exhibit acceptance remains Phase 9."
},
"runtime": {
"seed": 42
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"systems": {
"wheel": {
"type": "graphic",
"content": {
"outer": {
"type": "ring",
"position": {
"x": 480,
"y": 270
},
"radius": 160,
"innerRadius": 158,
"style": {
"fill": "#72c4bd"
}
},
"inner": {
"type": "ring",
"position": {
"x": 480,
"y": 270
},
"radius": 125,
"innerRadius": 123,
"style": {
"fill": "#e1bd7c"
}
},
"hub": {
"type": "ring",
"position": {
"x": 480,
"y": 270
},
"radius": 38,
"innerRadius": 36,
"style": {
"fill": "#e1bd7c"
}
}
}
},
"spokes": {
"type": "repeater",
"count": 12,
"distribution": {
"type": "point",
"position": {
"x": 480,
"y": 270
}
},
"repeat": {
"type": "group",
"transform": {
"rotation": {
"op": "multiply",
"args": [
{
"ref": "repeat.fraction"
},
330
]
}
},
"behaviors": [
{
"type": "rotate",
"speed": 12
}
],
"children": {
"bar": {
"type": "rectangle",
"position": {
"x": 40,
"y": -4
},
"size": {
"width": 85,
"height": 8
},
"style": {
"fill": "#e1bd7c"
}
}
}
}
}
}
}
}
+178
View File
@@ -0,0 +1,178 @@
{
"xzbt": "0.1",
"meta": {
"id": "exhibit-b",
"name": "Exhibit B — Deep Abstract Field",
"version": "0.1.0",
"description": "First visual composition; full reference exhibit acceptance remains Phase 9."
},
"runtime": {
"seed": 42
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"systems": {
"network": {
"type": "particles",
"count": 65,
"capacity": 96,
"distribution": {
"type": "rectangle",
"center": {
"x": 480,
"y": 270
},
"size": {
"width": 800,
"height": 410
}
},
"render": {
"type": "point",
"style": {
"fill": "#d8e9f5",
"pointSize": 4
}
},
"links": {
"rule": "nearest",
"count": 3,
"maxDistance": 180,
"maxLinks": 160,
"fadeWithDistance": true,
"style": {
"stroke": "#6899b7",
"strokeWidth": 1
}
},
"behaviors": [
{
"type": "noise-displace",
"amplitude": {
"x": 25,
"y": 25
},
"scale": 120,
"speed": 0.1
}
]
},
"morph": {
"type": "graphic",
"content": {
"shape": {
"type": "spline",
"points": [
{
"x": 100,
"y": 250
},
{
"x": 195,
"y": 344.2081569929845
},
{
"x": 290,
"y": 225.72359530745103
},
{
"x": 385,
"y": 162.0476051788654
},
{
"x": 480,
"y": 296.94076835816776
},
{
"x": 575,
"y": 325.85627569923156
},
{
"x": 670,
"y": 183.51190467861346
},
{
"x": 765,
"y": 191.27697433748185
},
{
"x": 860,
"y": 331.6203724113671
}
],
"style": {
"stroke": "#ecbf85",
"strokeWidth": 4
},
"behaviors": [
{
"type": "morph",
"to": "target",
"duration": "6s",
"loop": "ping-pong"
}
]
},
"target": {
"type": "spline",
"points": [
{
"x": 100,
"y": 420
},
{
"x": 195,
"y": 363.24149524059965
},
{
"x": 290,
"y": 235.91968579603693
},
{
"x": 385,
"y": 134.38917869744083
},
{
"x": 480,
"y": 135.48623754987796
},
{
"x": 575,
"y": 238.38063008538305
},
{
"x": 670,
"y": 365.2039313913952
},
{
"x": 765,
"y": 419.97879545751226
},
{
"x": 860,
"y": 361.25269717983815
}
],
"style": {
"stroke": "#82b7c7",
"strokeWidth": 2
},
"visible": false
}
}
}
},
"effects": [
{
"type": "bloom",
"radius": 5,
"intensity": 0.5
}
]
}
}
+175
View File
@@ -0,0 +1,175 @@
{
"xzbt": "0.1",
"meta": {
"id": "exhibit-c",
"name": "Exhibit C — Natural Environment",
"version": "0.1.0",
"description": "First visual composition; full reference exhibit acceptance remains Phase 9."
},
"runtime": {
"seed": 42
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"systems": {
"landscape": {
"type": "graphic",
"content": {
"sky": {
"type": "rectangle",
"size": {
"width": 960,
"height": 540
},
"style": {
"fill": {
"type": "linear-gradient",
"from": {
"x": 0,
"y": 0
},
"to": {
"x": 0,
"y": 540
},
"stops": [
{
"offset": 0,
"color": "#aabcb8"
},
{
"offset": 1,
"color": "#eddcb0"
}
]
}
}
},
"sun": {
"type": "ellipse",
"position": {
"x": 735,
"y": 120
},
"radius": 48,
"style": {
"fill": "#fff1c6"
}
},
"far": {
"type": "polygon",
"points": [
{
"x": 0,
"y": 390
},
{
"x": 220,
"y": 150
},
{
"x": 470,
"y": 340
},
{
"x": 660,
"y": 200
},
{
"x": 960,
"y": 410
},
{
"x": 960,
"y": 540
},
{
"x": 0,
"y": 540
}
],
"style": {
"fill": "#667e72"
}
},
"near": {
"type": "spline",
"closed": true,
"points": [
{
"x": 0,
"y": 450
},
{
"x": 250,
"y": 320
},
{
"x": 580,
"y": 480
},
{
"x": 960,
"y": 380
},
{
"x": 960,
"y": 600
},
{
"x": 0,
"y": 600
}
],
"style": {
"fill": "#314c41"
}
}
}
},
"rain": {
"type": "particles",
"count": 240,
"capacity": 256,
"distribution": {
"type": "uniform",
"min": {
"x": 0,
"y": 0
},
"max": {
"x": 960,
"y": 540
}
},
"render": {
"type": "line",
"to": {
"x": -3,
"y": 15
},
"style": {
"stroke": "#90acba",
"strokeWidth": 1,
"opacity": 0.6
}
},
"velocity": {
"x": -35,
"y": 220
},
"behaviors": [
{
"type": "wrap",
"bounds": "scene"
}
]
}
}
}
}
+172
View File
@@ -0,0 +1,172 @@
{
"xzbt": "0.1",
"meta": {
"id": "exhibit-d",
"name": "Exhibit D — Instrument Display",
"version": "0.1.0",
"description": "First visual composition; full reference exhibit acceptance remains Phase 9."
},
"runtime": {
"seed": 42
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"systems": {
"rings": {
"type": "graphic",
"content": {
"a": {
"type": "ring",
"position": {
"x": 480,
"y": 270
},
"radius": 70,
"innerRadius": 68,
"style": {
"fill": "#72c4bd"
}
},
"b": {
"type": "ring",
"position": {
"x": 480,
"y": 270
},
"radius": 130,
"innerRadius": 128,
"style": {
"fill": "#72c4bd"
}
},
"c": {
"type": "ring",
"position": {
"x": 480,
"y": 270
},
"radius": 190,
"innerRadius": 188,
"style": {
"fill": "#72c4bd"
}
},
"label": {
"type": "text",
"text": "FIELD / 04",
"position": {
"x": 35,
"y": 45
},
"size": 18,
"style": {
"fill": "#a7d3c4"
}
},
"sweep": {
"type": "group",
"position": {
"x": 480,
"y": 270
},
"behaviors": [
{
"type": "rotate",
"speed": 40
}
],
"children": {
"ray": {
"type": "line",
"to": {
"x": 188,
"y": 0
},
"style": {
"stroke": "#ddf6a0",
"strokeWidth": 3
}
}
}
}
},
"layer": "display"
},
"ticks": {
"type": "repeater",
"count": 48,
"distribution": {
"type": "ring",
"center": {
"x": 480,
"y": 270
},
"radius": 210,
"innerRadius": 209,
"mode": "even"
},
"repeat": {
"type": "point",
"style": {
"fill": "#789f95",
"pointSize": 3
}
},
"layer": "display"
},
"contacts": {
"type": "particles",
"count": 18,
"capacity": 32,
"distribution": {
"type": "ellipse",
"center": {
"x": 480,
"y": 270
},
"radius": 170
},
"render": {
"type": "point",
"style": {
"fill": "#d8e6a7",
"pointSize": 5
}
},
"behaviors": [
{
"type": "twinkle",
"min": 0.2,
"max": 1,
"rate": 0.6
}
],
"layer": "display"
}
},
"layers": {
"display": {}
}
},
"state": {
"level": {
"type": "number",
"initial": 0.7,
"min": 0,
"max": 1
}
},
"bindings": [
{
"source": "state.level",
"target": "visuals.layers.display.opacity",
"scale": 0.7,
"offset": 0.3
}
]
}
@@ -0,0 +1,91 @@
{
"xzbt": "0.1",
"meta": {
"id": "audio-reactive",
"name": "Audio-reactive visualization",
"version": "1.0.0",
"description": "PRD 130 challenge 12; generic visual primitives only."
},
"runtime": {
"seed": 4211
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"layers": {
"field": {}
},
"systems": {
"network": {
"type": "particles",
"count": 65,
"capacity": 96,
"distribution": {
"type": "rectangle",
"center": {
"x": 480,
"y": 270
},
"size": {
"width": 800,
"height": 410
}
},
"render": {
"type": "point",
"style": {
"fill": "#d8e9f5",
"pointSize": 4
}
},
"links": {
"rule": "nearest",
"count": 3,
"maxDistance": 180,
"maxLinks": 160,
"fadeWithDistance": true,
"style": {
"stroke": "#6899b7",
"strokeWidth": 1
}
},
"behaviors": [
{
"type": "noise-displace",
"amplitude": {
"x": 25,
"y": 25
},
"scale": 120,
"speed": 0.1
}
],
"layer": "field"
}
},
"effects": [
{
"type": "bloom",
"intensity": 0.4
}
]
},
"bindings": [
{
"source": "signals.audio.energy",
"target": "visuals.layers.field.opacity",
"scale": 0.8,
"offset": 0.2
},
{
"source": "signals.audio.low",
"target": "visuals.camera.zoom",
"scale": 0.25,
"offset": 1
}
]
}
@@ -0,0 +1,67 @@
{
"xzbt": "0.1",
"meta": {
"id": "constellation-network",
"name": "Constellation network",
"version": "1.0.0",
"description": "PRD 130 challenge 8; generic visual primitives only."
},
"runtime": {
"seed": 4207
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"systems": {
"network": {
"type": "particles",
"count": 65,
"capacity": 96,
"distribution": {
"type": "rectangle",
"center": {
"x": 480,
"y": 270
},
"size": {
"width": 800,
"height": 410
}
},
"render": {
"type": "point",
"style": {
"fill": "#d8e9f5",
"pointSize": 4
}
},
"links": {
"rule": "nearest",
"count": 3,
"maxDistance": 180,
"maxLinks": 160,
"fadeWithDistance": true,
"style": {
"stroke": "#6899b7",
"strokeWidth": 1
}
},
"behaviors": [
{
"type": "noise-displace",
"amplitude": {
"x": 25,
"y": 25
},
"scale": 120,
"speed": 0.1
}
]
}
}
}
}
@@ -0,0 +1,113 @@
{
"xzbt": "0.1",
"meta": {
"id": "deep-parallax-starfield",
"name": "Deep parallax starfield",
"version": "1.0.0",
"description": "PRD 130 challenge 1; generic visual primitives only."
},
"runtime": {
"seed": 4200
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"layers": {
"far": {
"parallax": 0.2
},
"near": {
"parallax": 1
}
},
"camera": {
"projection": "perspective",
"focalLength": 1000
},
"automation": [
{
"target": "camera.x",
"loop": {
"mode": "ping-pong"
},
"interpolation": "smooth",
"points": [
{
"at": "0ms",
"value": 400
},
{
"at": "12s",
"value": 570
}
]
}
],
"systems": {
"far": {
"type": "particles",
"count": 250,
"capacity": 256,
"distribution": {
"type": "uniform",
"min": {
"x": 0,
"y": 0
},
"max": {
"x": 960,
"y": 540
}
},
"render": {
"type": "point",
"style": {
"fill": "#8c9ebf",
"pointSize": 2
}
},
"layer": "far",
"z": {
"random": {
"min": 300,
"max": 1200
}
}
},
"near": {
"type": "particles",
"count": 90,
"capacity": 256,
"distribution": {
"type": "uniform",
"min": {
"x": 0,
"y": 0
},
"max": {
"x": 960,
"y": 540
}
},
"render": {
"type": "point",
"style": {
"fill": "#ecdfc1",
"pointSize": 3
}
},
"layer": "near",
"z": {
"random": {
"min": 0,
"max": 200
}
}
}
}
}
}
@@ -0,0 +1,71 @@
{
"xzbt": "0.1",
"meta": {
"id": "flow-field",
"name": "Fog or smoke-like flow field",
"version": "1.0.0",
"description": "PRD 130 challenge 2; generic visual primitives only."
},
"runtime": {
"seed": 4201
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"fields": {
"flow": {
"type": "noise",
"mode": "curl",
"scale": 160,
"amplitude": 25,
"speed": 0.12
}
},
"systems": {
"flow": {
"type": "particles",
"count": 150,
"capacity": 256,
"distribution": {
"type": "uniform",
"min": {
"x": 0,
"y": 0
},
"max": {
"x": 960,
"y": 540
}
},
"render": {
"type": "ellipse",
"radius": 20,
"style": {
"fill": "#b5c1c0",
"opacity": 0.025
}
},
"fields": [
"flow"
],
"drag": 0.2,
"behaviors": [
{
"type": "wrap",
"bounds": "scene"
}
]
}
},
"effects": [
{
"type": "blur",
"radius": 5
}
]
}
}
@@ -0,0 +1,150 @@
{
"xzbt": "0.1",
"meta": {
"id": "instrument-display",
"name": "Instrument and radar display",
"version": "1.0.0",
"description": "PRD 130 challenge 7; generic visual primitives only."
},
"runtime": {
"seed": 4206
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"systems": {
"rings": {
"type": "graphic",
"content": {
"a": {
"type": "ring",
"position": {
"x": 480,
"y": 270
},
"radius": 70,
"innerRadius": 68,
"style": {
"fill": "#72c4bd"
}
},
"b": {
"type": "ring",
"position": {
"x": 480,
"y": 270
},
"radius": 130,
"innerRadius": 128,
"style": {
"fill": "#72c4bd"
}
},
"c": {
"type": "ring",
"position": {
"x": 480,
"y": 270
},
"radius": 190,
"innerRadius": 188,
"style": {
"fill": "#72c4bd"
}
},
"label": {
"type": "text",
"text": "FIELD / 04",
"position": {
"x": 35,
"y": 45
},
"size": 18,
"style": {
"fill": "#a7d3c4"
}
},
"sweep": {
"type": "group",
"position": {
"x": 480,
"y": 270
},
"behaviors": [
{
"type": "rotate",
"speed": 40
}
],
"children": {
"ray": {
"type": "line",
"to": {
"x": 188,
"y": 0
},
"style": {
"stroke": "#ddf6a0",
"strokeWidth": 3
}
}
}
}
}
},
"ticks": {
"type": "repeater",
"count": 48,
"distribution": {
"type": "ring",
"center": {
"x": 480,
"y": 270
},
"radius": 210,
"innerRadius": 209,
"mode": "even"
},
"repeat": {
"type": "point",
"style": {
"fill": "#789f95",
"pointSize": 3
}
}
},
"contacts": {
"type": "particles",
"count": 18,
"capacity": 32,
"distribution": {
"type": "ellipse",
"center": {
"x": 480,
"y": 270
},
"radius": 170
},
"render": {
"type": "point",
"style": {
"fill": "#d8e6a7",
"pointSize": 5
}
},
"behaviors": [
{
"type": "twinkle",
"min": 0.2,
"max": 1,
"rate": 0.6
}
]
}
}
}
}
@@ -0,0 +1,110 @@
{
"xzbt": "0.1",
"meta": {
"id": "mechanical-abstraction",
"name": "Rotating mechanical abstraction",
"version": "1.0.0",
"description": "PRD 130 challenge 5; generic visual primitives only."
},
"runtime": {
"seed": 4204
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"systems": {
"wheel": {
"type": "graphic",
"content": {
"outer": {
"type": "ring",
"position": {
"x": 480,
"y": 270
},
"radius": 160,
"innerRadius": 158,
"style": {
"fill": "#72c4bd"
}
},
"inner": {
"type": "ring",
"position": {
"x": 480,
"y": 270
},
"radius": 125,
"innerRadius": 123,
"style": {
"fill": "#e1bd7c"
}
},
"hub": {
"type": "ring",
"position": {
"x": 480,
"y": 270
},
"radius": 38,
"innerRadius": 36,
"style": {
"fill": "#e1bd7c"
}
}
}
},
"spokes": {
"type": "repeater",
"count": 12,
"distribution": {
"type": "point",
"position": {
"x": 480,
"y": 270
}
},
"repeat": {
"type": "group",
"transform": {
"rotation": {
"op": "multiply",
"args": [
{
"ref": "repeat.fraction"
},
330
]
}
},
"behaviors": [
{
"type": "rotate",
"speed": 12
}
],
"children": {
"bar": {
"type": "rectangle",
"position": {
"x": 40,
"y": -4
},
"size": {
"width": 85,
"height": 8
},
"style": {
"fill": "#e1bd7c"
}
}
}
}
}
}
}
}
@@ -0,0 +1,126 @@
{
"xzbt": "0.1",
"meta": {
"id": "morphing-art",
"name": "Morphing geometric art",
"version": "1.0.0",
"description": "PRD 130 challenge 11; generic visual primitives only."
},
"runtime": {
"seed": 4210
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"systems": {
"morph": {
"type": "graphic",
"content": {
"shape": {
"type": "spline",
"points": [
{
"x": 100,
"y": 250
},
{
"x": 195,
"y": 344.2081569929845
},
{
"x": 290,
"y": 225.72359530745103
},
{
"x": 385,
"y": 162.0476051788654
},
{
"x": 480,
"y": 296.94076835816776
},
{
"x": 575,
"y": 325.85627569923156
},
{
"x": 670,
"y": 183.51190467861346
},
{
"x": 765,
"y": 191.27697433748185
},
{
"x": 860,
"y": 331.6203724113671
}
],
"style": {
"stroke": "#ecbf85",
"strokeWidth": 4
},
"behaviors": [
{
"type": "morph",
"to": "target",
"duration": "6s",
"loop": "ping-pong"
}
]
},
"target": {
"type": "spline",
"points": [
{
"x": 100,
"y": 420
},
{
"x": 195,
"y": 363.24149524059965
},
{
"x": 290,
"y": 235.91968579603693
},
{
"x": 385,
"y": 134.38917869744083
},
{
"x": 480,
"y": 135.48623754987796
},
{
"x": 575,
"y": 238.38063008538305
},
{
"x": 670,
"y": 365.2039313913952
},
{
"x": 765,
"y": 419.97879545751226
},
{
"x": 860,
"y": 361.25269717983815
}
],
"style": {
"stroke": "#82b7c7",
"strokeWidth": 2
},
"visible": false
}
}
}
}
}
}
@@ -0,0 +1,179 @@
{
"xzbt": "0.1",
"meta": {
"id": "natural-abstraction",
"name": "Natural meadow abstraction",
"version": "1.0.0",
"description": "PRD 130 challenge 14; generic visual primitives only."
},
"runtime": {
"seed": 4213
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"systems": {
"landscape": {
"type": "graphic",
"content": {
"sky": {
"type": "rectangle",
"size": {
"width": 960,
"height": 540
},
"style": {
"fill": {
"type": "linear-gradient",
"from": {
"x": 0,
"y": 0
},
"to": {
"x": 0,
"y": 540
},
"stops": [
{
"offset": 0,
"color": "#aabcb8"
},
{
"offset": 1,
"color": "#eddcb0"
}
]
}
}
},
"sun": {
"type": "ellipse",
"position": {
"x": 735,
"y": 120
},
"radius": 48,
"style": {
"fill": "#fff1c6"
}
},
"far": {
"type": "polygon",
"points": [
{
"x": 0,
"y": 390
},
{
"x": 220,
"y": 150
},
{
"x": 470,
"y": 340
},
{
"x": 660,
"y": 200
},
{
"x": 960,
"y": 410
},
{
"x": 960,
"y": 540
},
{
"x": 0,
"y": 540
}
],
"style": {
"fill": "#667e72"
}
},
"near": {
"type": "spline",
"closed": true,
"points": [
{
"x": 0,
"y": 450
},
{
"x": 250,
"y": 320
},
{
"x": 580,
"y": 480
},
{
"x": 960,
"y": 380
},
{
"x": 960,
"y": 600
},
{
"x": 0,
"y": 600
}
],
"style": {
"fill": "#314c41"
}
}
}
},
"seeds": {
"type": "particles",
"count": 70,
"capacity": 256,
"distribution": {
"type": "uniform",
"min": {
"x": 0,
"y": 0
},
"max": {
"x": 960,
"y": 540
}
},
"render": {
"type": "point",
"style": {
"fill": "#e8daa5",
"pointSize": 3
}
},
"velocity": {
"x": 12,
"y": -4
},
"behaviors": [
{
"type": "wrap",
"bounds": "scene"
},
{
"type": "noise-displace",
"amplitude": {
"x": 12,
"y": 24
},
"scale": 100,
"speed": 0.1
}
]
}
}
}
}
@@ -0,0 +1,102 @@
{
"xzbt": "0.1",
"meta": {
"id": "organic-pulse",
"name": "Organic pulsing structure",
"version": "1.0.0",
"description": "PRD 130 challenge 6; generic visual primitives only."
},
"runtime": {
"seed": 4205
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"systems": {
"organic": {
"type": "graphic",
"content": {
"body": {
"type": "spline",
"closed": true,
"points": [
{
"x": 590,
"y": 270
},
{
"x": 595.1813787033303,
"y": 332.5
},
{
"x": 558,
"y": 378.25317547305485
},
{
"x": 480,
"y": 395
},
{
"x": 413.5,
"y": 378.25317547305485
},
{
"x": 344.90003700962757,
"y": 332.5
},
{
"x": 370,
"y": 270
},
{
"x": 364.8186212966696,
"y": 207.50000000000003
},
{
"x": 401.99999999999994,
"y": 161.7468245269452
},
{
"x": 480,
"y": 145
},
{
"x": 546.5,
"y": 161.74682452694518
},
{
"x": 615.0999629903724,
"y": 207.49999999999994
}
],
"style": {
"fill": "#537a63",
"stroke": "#acd2a0",
"strokeWidth": 3
},
"behaviors": [
{
"type": "point-wander",
"amplitude": {
"x": 28,
"y": 28
},
"rate": 0.15
},
{
"type": "pulse",
"property": "style.opacity",
"amplitude": -0.35,
"frequency": 0.2
}
]
}
}
}
}
}
}
@@ -0,0 +1,137 @@
{
"xzbt": "0.1",
"meta": {
"id": "persistent-landscape",
"name": "Persistent landscape",
"version": "1.0.0",
"description": "PRD 130 challenge 9; generic visual primitives only."
},
"runtime": {
"seed": 4208
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"systems": {
"landscape": {
"type": "graphic",
"content": {
"sky": {
"type": "rectangle",
"size": {
"width": 960,
"height": 540
},
"style": {
"fill": {
"type": "linear-gradient",
"from": {
"x": 0,
"y": 0
},
"to": {
"x": 0,
"y": 540
},
"stops": [
{
"offset": 0,
"color": "#aabcb8"
},
{
"offset": 1,
"color": "#eddcb0"
}
]
}
}
},
"sun": {
"type": "ellipse",
"position": {
"x": 735,
"y": 120
},
"radius": 48,
"style": {
"fill": "#fff1c6"
}
},
"far": {
"type": "polygon",
"points": [
{
"x": 0,
"y": 390
},
{
"x": 220,
"y": 150
},
{
"x": 470,
"y": 340
},
{
"x": 660,
"y": 200
},
{
"x": 960,
"y": 410
},
{
"x": 960,
"y": 540
},
{
"x": 0,
"y": 540
}
],
"style": {
"fill": "#667e72"
}
},
"near": {
"type": "spline",
"closed": true,
"points": [
{
"x": 0,
"y": 450
},
{
"x": 250,
"y": 320
},
{
"x": 580,
"y": 480
},
{
"x": 960,
"y": 380
},
{
"x": 960,
"y": 600
},
{
"x": 0,
"y": 600
}
],
"style": {
"fill": "#314c41"
}
}
}
}
}
}
}
@@ -0,0 +1,381 @@
{
"xzbt": "0.1",
"meta": {
"id": "spline-network",
"name": "Evolving spline network",
"version": "1.0.0",
"description": "PRD 130 challenge 3; generic visual primitives only."
},
"runtime": {
"seed": 4202
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"systems": {
"curves": {
"type": "graphic",
"content": {
"c0": {
"type": "spline",
"points": [
{
"x": 100,
"y": 250
},
{
"x": 195,
"y": 344.2081569929845
},
{
"x": 290,
"y": 225.72359530745103
},
{
"x": 385,
"y": 162.0476051788654
},
{
"x": 480,
"y": 296.94076835816776
},
{
"x": 575,
"y": 325.85627569923156
},
{
"x": 670,
"y": 183.51190467861346
},
{
"x": 765,
"y": 191.27697433748185
},
{
"x": 860,
"y": 331.6203724113671
}
],
"style": {
"stroke": "#82b7c7",
"strokeWidth": 2
},
"position": {
"x": 0,
"y": -105
},
"behaviors": [
{
"type": "point-wander",
"amplitude": {
"x": 30,
"y": 45
},
"rate": 0.13
}
]
},
"c1": {
"type": "spline",
"points": [
{
"x": 100,
"y": 250
},
{
"x": 195,
"y": 344.2081569929845
},
{
"x": 290,
"y": 225.72359530745103
},
{
"x": 385,
"y": 162.0476051788654
},
{
"x": 480,
"y": 296.94076835816776
},
{
"x": 575,
"y": 325.85627569923156
},
{
"x": 670,
"y": 183.51190467861346
},
{
"x": 765,
"y": 191.27697433748185
},
{
"x": 860,
"y": 331.6203724113671
}
],
"style": {
"stroke": "#82b7c7",
"strokeWidth": 2
},
"position": {
"x": 0,
"y": -70
},
"behaviors": [
{
"type": "point-wander",
"amplitude": {
"x": 30,
"y": 45
},
"rate": 0.13
}
]
},
"c2": {
"type": "spline",
"points": [
{
"x": 100,
"y": 250
},
{
"x": 195,
"y": 344.2081569929845
},
{
"x": 290,
"y": 225.72359530745103
},
{
"x": 385,
"y": 162.0476051788654
},
{
"x": 480,
"y": 296.94076835816776
},
{
"x": 575,
"y": 325.85627569923156
},
{
"x": 670,
"y": 183.51190467861346
},
{
"x": 765,
"y": 191.27697433748185
},
{
"x": 860,
"y": 331.6203724113671
}
],
"style": {
"stroke": "#82b7c7",
"strokeWidth": 2
},
"position": {
"x": 0,
"y": -35
},
"behaviors": [
{
"type": "point-wander",
"amplitude": {
"x": 30,
"y": 45
},
"rate": 0.13
}
]
},
"c3": {
"type": "spline",
"points": [
{
"x": 100,
"y": 250
},
{
"x": 195,
"y": 344.2081569929845
},
{
"x": 290,
"y": 225.72359530745103
},
{
"x": 385,
"y": 162.0476051788654
},
{
"x": 480,
"y": 296.94076835816776
},
{
"x": 575,
"y": 325.85627569923156
},
{
"x": 670,
"y": 183.51190467861346
},
{
"x": 765,
"y": 191.27697433748185
},
{
"x": 860,
"y": 331.6203724113671
}
],
"style": {
"stroke": "#82b7c7",
"strokeWidth": 2
},
"position": {
"x": 0,
"y": 0
},
"behaviors": [
{
"type": "point-wander",
"amplitude": {
"x": 30,
"y": 45
},
"rate": 0.13
}
]
},
"c4": {
"type": "spline",
"points": [
{
"x": 100,
"y": 250
},
{
"x": 195,
"y": 344.2081569929845
},
{
"x": 290,
"y": 225.72359530745103
},
{
"x": 385,
"y": 162.0476051788654
},
{
"x": 480,
"y": 296.94076835816776
},
{
"x": 575,
"y": 325.85627569923156
},
{
"x": 670,
"y": 183.51190467861346
},
{
"x": 765,
"y": 191.27697433748185
},
{
"x": 860,
"y": 331.6203724113671
}
],
"style": {
"stroke": "#82b7c7",
"strokeWidth": 2
},
"position": {
"x": 0,
"y": 35
},
"behaviors": [
{
"type": "point-wander",
"amplitude": {
"x": 30,
"y": 45
},
"rate": 0.13
}
]
},
"c5": {
"type": "spline",
"points": [
{
"x": 100,
"y": 250
},
{
"x": 195,
"y": 344.2081569929845
},
{
"x": 290,
"y": 225.72359530745103
},
{
"x": 385,
"y": 162.0476051788654
},
{
"x": 480,
"y": 296.94076835816776
},
{
"x": 575,
"y": 325.85627569923156
},
{
"x": 670,
"y": 183.51190467861346
},
{
"x": 765,
"y": 191.27697433748185
},
{
"x": 860,
"y": 331.6203724113671
}
],
"style": {
"stroke": "#82b7c7",
"strokeWidth": 2
},
"position": {
"x": 0,
"y": 70
},
"behaviors": [
{
"type": "point-wander",
"amplitude": {
"x": 30,
"y": 45
},
"rate": 0.13
}
]
}
}
}
}
}
}
@@ -0,0 +1,78 @@
{
"xzbt": "0.1",
"meta": {
"id": "transient-impact",
"name": "Transient impact burst",
"version": "1.0.0",
"description": "PRD 130 challenge 10; generic visual primitives only."
},
"runtime": {
"seed": 4209
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"systems": {
"burst": {
"type": "particles",
"lifecycle": "spawned",
"spawn": {
"lifetime": "2s",
"release": "1s"
},
"count": 120,
"capacity": 128,
"distribution": {
"type": "point",
"position": {
"x": 480,
"y": 270
}
},
"velocity": {
"x": {
"random": {
"min": -160,
"max": 160
}
},
"y": {
"random": {
"min": -160,
"max": 160
}
}
},
"lifetime": "3s",
"size": {
"from": 1.5,
"to": 0.1
},
"opacity": {
"from": 1,
"to": 0
},
"render": {
"type": "point",
"style": {
"fill": "#f5c276",
"pointSize": 4
}
},
"trail": {
"length": 20,
"mode": "line",
"width": 2,
"style": {
"stroke": "#d98963",
"strokeWidth": 2
}
}
}
}
}
}
@@ -0,0 +1,60 @@
{
"xzbt": "0.1",
"meta": {
"id": "weather-particles",
"name": "Rain particles",
"version": "1.0.0",
"description": "PRD 130 challenge 4; generic visual primitives only."
},
"runtime": {
"seed": 4203
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"systems": {
"rain": {
"type": "particles",
"count": 240,
"capacity": 256,
"distribution": {
"type": "uniform",
"min": {
"x": 0,
"y": 0
},
"max": {
"x": 960,
"y": 540
}
},
"render": {
"type": "line",
"to": {
"x": -3,
"y": 15
},
"style": {
"stroke": "#90acba",
"strokeWidth": 1,
"opacity": 0.6
}
},
"velocity": {
"x": -35,
"y": 220
},
"behaviors": [
{
"type": "wrap",
"bounds": "scene"
}
]
}
}
}
}
@@ -0,0 +1,130 @@
{
"xzbt": "0.1",
"meta": {
"id": "window-traffic",
"name": "Window containing procedural traffic",
"version": "1.0.0",
"description": "PRD 130 challenge 13; generic visual primitives only."
},
"runtime": {
"seed": 4212
},
"visuals": {
"scene": {
"coordinateSpace": "virtual",
"width": 960,
"height": 540,
"background": "#101d25"
},
"systems": {
"background": {
"type": "graphic",
"content": {
"wall": {
"type": "rectangle",
"size": {
"width": 960,
"height": 540
},
"style": {
"fill": "#c8b69c"
}
},
"window": {
"type": "rectangle",
"position": {
"x": 150,
"y": 90
},
"size": {
"width": 660,
"height": 360
},
"style": {
"fill": "#273f49"
}
}
}
},
"traffic": {
"type": "repeater",
"count": 14,
"distribution": {
"type": "grid",
"columns": 7,
"rows": 2,
"origin": {
"x": 185,
"y": 235
},
"spacing": {
"x": 88,
"y": 75
}
},
"repeat": {
"type": "rectangle",
"size": {
"width": 24,
"height": 8
},
"style": {
"fill": "#eed092"
},
"behaviors": [
{
"type": "drift",
"velocity": {
"x": 20,
"y": 0
}
},
{
"type": "wrap",
"bounds": {
"x": -30,
"y": -30,
"width": 60,
"height": 60
}
}
]
}
},
"frame": {
"type": "graphic",
"content": {
"mullion": {
"type": "rectangle",
"position": {
"x": 470,
"y": 85
},
"size": {
"width": 12,
"height": 370
},
"style": {
"fill": "#d8c8af"
}
},
"border": {
"type": "rectangle",
"position": {
"x": 145,
"y": 85
},
"size": {
"width": 670,
"height": 370
},
"style": {
"stroke": "#e8d8bf",
"strokeWidth": 12
}
}
}
}
}
}
}
+55
View File
@@ -0,0 +1,55 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { visualChallenges, visualExhibits } from '../tools/visual-challenge-fixtures.mjs';
import { validateExhibit } from '../src/runtime/validator.js';
import { VisualEngine } from '../src/runtime/visual-engine.js';
import { ResolutionEngine } from '../src/runtime/resolution.js';
import { SeededRNG } from '../src/runtime/rng.js';
import { Script } from 'node:vm';
import { readFileSync } from 'node:fs';
import { buildVisualAcceptance } from '../tools/build-visual-acceptance.mjs';
for (const fixture of [...visualChallenges, ...visualExhibits]) test(`4g ${fixture.id}: validates, executes, draws, and reproduces across frame rates`, () => {
assert.deepEqual(validateExhibit(fixture.document).errors, []);
const run = cadence => {
const rng = new SeededRNG(fixture.document.runtime.seed);
const resolution = new ResolutionEngine(fixture.document, rng);
const engine = new VisualEngine(fixture.document, { rng, resolution });
if (fixture.id === 'transient-impact') engine.spawn('burst');
let plan;
for (let i = 0; i < 120; i++) {
resolution.signals.set('signals.audio.energy', (Math.sin(i / 20) + 1) / 2);
resolution.signals.set('signals.audio.low', (Math.cos(i / 30) + 1) / 2);
resolution.advance(1000 / 60); engine.advance(1000 / 60);
if (i % cadence === 0 || i === 119) plan = engine.planFrame({ width: 960, height: 540 });
}
assert.equal(plan.deferred.length, 0);
assert.ok(plan.layers.some(layer => layer.nodes.length > 0));
const finite = object => {
if (typeof object === 'number') assert.ok(Number.isFinite(object));
else if (object && typeof object === 'object') for (const value of Object.values(object)) finite(value);
};
finite(plan.layers);
engine.dispose(); assert.equal(engine.instances.size, 0); assert.equal(resolution.automation.size, 0);
return plan.layers;
};
assert.deepEqual(run(1), run(4));
});
test('4g standalone acceptance build is deterministic, contains every fixture and parses as JavaScript', () => {
const first = buildVisualAcceptance(), second = buildVisualAcceptance();
assert.equal(first.html, second.html); assert.equal(first.count, 18);
const script = /<script>([\s\S]*)<\/script>/.exec(first.html)[1];
assert.doesNotThrow(() => new Script(script));
assert.ok(!/<script[^>]+src=|<link[^>]+href=/.test(first.html));
for (const fixture of visualChallenges) assert.deepEqual(JSON.parse(readFileSync(new URL(`../exhibits/visual-challenges/${fixture.id}.xzbt`, import.meta.url))), fixture.document);
});
test('C6: standalone CLI validator accepts all visual challenges and exhibits', async () => {
const { ExhibitValidator } = await import('../tools/validate-exhibit.mjs');
for (const fixture of [...visualChallenges, ...visualExhibits]) {
const validator = new ExhibitValidator(fixture.document, `${fixture.id}.xzbt`);
const result = validator.validate();
assert.deepEqual(result.errors, [], `CLI validator errors on ${fixture.id}: ${JSON.stringify(result.errors)}`);
}
});
+29 -1
View File
@@ -9,6 +9,9 @@
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import { validateAudioSubsystem } from '../src/runtime/audio-graph.js';
import { validateCadenceSubsystem } from '../src/runtime/cadence-validation.js';
import { matchVisualTarget } from '../src/runtime/visual-contract.js';
import { validateVisualSubsystem } from '../src/runtime/visual-validation.js';
const ID_REGEX = /^[a-z][a-z0-9_-]*$/;
const REF_PATH_REGEX = /^[a-z][a-z0-9_-]*(\.[a-z][a-z0-9_-]*)+$/;
@@ -159,6 +162,19 @@ export class ExhibitValidator {
pushError: (errors, code, path, message) => errors.push({ code, path, message })
});
// 8. Visual subsystem (Format Specification sections 17-19)
validateVisualSubsystem(this.doc, this.errors, {
validateValueSpec: (unusedDocument, spec, path, unusedErrors, scope) => this.validateValueSpec(spec, path, scope),
pushError: (errors, code, path, message) => errors.push({ code, path, message })
});
// 9. Cadence and Event subsystems (Format Specification section 20)
validateCadenceSubsystem(this.doc, this.errors, {
validateValueSpec: (unusedDocument, spec, path, unusedErrors, scope) => this.validateValueSpec(spec, path, scope),
validateCondition: (unusedDocument, cond, path, unusedErrors) => this.validateConditionSpec(cond, path),
pushError: (errors, code, path, message) => errors.push({ code, path, message })
});
return this.getResult();
}
@@ -449,7 +465,7 @@ export class ExhibitValidator {
this.resolveReference(binding.source, `${path}.source`);
}
if (typeof binding.target !== 'string' || !REF_PATH_REGEX.test(binding.target)) {
if (typeof binding.target !== 'string') {
this.addError('ERR_INVALID_REFERENCE', `${path}.target`, `Invalid target reference: '${binding.target}'.`);
} else {
this.validateBindingTarget(binding.target, `${path}.target`);
@@ -569,6 +585,16 @@ export class ExhibitValidator {
return;
}
const visual = matchVisualTarget(this.doc, refPath);
if (visual) {
if (visual.reason === 'reference') {
this.addError('ERR_INVALID_REFERENCE', location, `Binding target '${refPath}' does not resolve.`);
} else if (visual.reason === 'unsupported') {
this.addError('ERR_UNSUPPORTED_TARGET', location, `Binding target '${refPath}' is not exposed. Per-object visual properties are not externally addressable in 0.1.`);
}
return;
}
this.addError('ERR_UNSUPPORTED_TARGET', location, `Target '${refPath}' is not exposed by the shared 0.1 target registry.`);
}
@@ -580,6 +606,8 @@ export class ExhibitValidator {
if (parts[0] === 'audio' && parts[1] === 'buses' && parts[3] === 'gain') return 'number';
if (parts[0] === 'signals') return RUNTIME_SIGNAL_TYPES.get(refPath) || null;
if (parts[0] === 'modulators') return 'number';
const visual = matchVisualTarget(this.doc, refPath);
if (visual && !visual.reason) return visual.spec?.type || 'number';
return null;
}
+91
View File
@@ -0,0 +1,91 @@
// Authored exhibit data only. Subject names occur here, never in renderer dispatch.
const random = (min, max) => ({ random: { min, max } });
const dot = (color = '#cfe8ff', size = 3) => ({ type: 'point', style: { fill: color, pointSize: size } });
const lineStyle = { stroke: '#82b7c7', strokeWidth: 2 };
const graphic = content => ({ type: 'graphic', content });
const ring = (radius, color = '#72c4bd') => ({ type: 'ring', position: { x: 480, y: 270 }, radius, innerRadius: radius - 2, style: { fill: color } });
const auto = (target, from, to, duration = '12s') => ({ target, loop: { mode: 'ping-pong' }, interpolation: 'smooth', points: [{ at: '0ms', value: from }, { at: duration, value: to }] });
const uniform = { type: 'uniform', min: { x: 0, y: 0 }, max: { x: 960, y: 540 } };
const particles = (extra = {}) => ({ type: 'particles', count: 180, capacity: 256, distribution: uniform, render: dot(), ...extra });
const splinePoints = Array.from({ length: 9 }, (_, i) => ({ x: 100 + i * 95, y: 250 + Math.sin(i * 1.7) * 95 }));
const curve = { type: 'spline', points: splinePoints, style: lineStyle };
const wrap = { type: 'wrap', bounds: 'scene' };
const rain = particles({ count: 240, velocity: { x: -35, y: 220 }, render: { type: 'line', to: { x: -3, y: 15 }, style: { stroke: '#90acba', strokeWidth: 1, opacity: 0.6 } }, behaviors: [wrap] });
const landscape = graphic({
sky: { type: 'rectangle', size: { width: 960, height: 540 }, style: { fill: { type: 'linear-gradient', from: { x: 0, y: 0 }, to: { x: 0, y: 540 }, stops: [{ offset: 0, color: '#aabcb8' }, { offset: 1, color: '#eddcb0' }] } } },
sun: { type: 'ellipse', position: { x: 735, y: 120 }, radius: 48, style: { fill: '#fff1c6' } },
far: { type: 'polygon', points: [{ x: 0, y: 390 }, { x: 220, y: 150 }, { x: 470, y: 340 }, { x: 660, y: 200 }, { x: 960, y: 410 }, { x: 960, y: 540 }, { x: 0, y: 540 }], style: { fill: '#667e72' } },
near: { type: 'spline', closed: true, points: [{ x: 0, y: 450 }, { x: 250, y: 320 }, { x: 580, y: 480 }, { x: 960, y: 380 }, { x: 960, y: 600 }, { x: 0, y: 600 }], style: { fill: '#314c41' } }
});
const machine = {
wheel: graphic({ outer: ring(160), inner: ring(125, '#e1bd7c'), hub: ring(38, '#e1bd7c') }),
spokes: { type: 'repeater', count: 12, distribution: { type: 'point', position: { x: 480, y: 270 } }, repeat: {
type: 'group', transform: { rotation: { op: 'multiply', args: [{ ref: 'repeat.fraction' }, 330] } }, behaviors: [{ type: 'rotate', speed: 12 }],
children: { bar: { type: 'rectangle', position: { x: 40, y: -4 }, size: { width: 85, height: 8 }, style: { fill: '#e1bd7c' } } }
} }
};
const radar = {
rings: graphic({ a: ring(70), b: ring(130), c: ring(190),
label: { type: 'text', text: 'FIELD / 04', position: { x: 35, y: 45 }, size: 18, style: { fill: '#a7d3c4' } },
sweep: { type: 'group', position: { x: 480, y: 270 }, behaviors: [{ type: 'rotate', speed: 40 }], children: { ray: { type: 'line', to: { x: 188, y: 0 }, style: { stroke: '#ddf6a0', strokeWidth: 3 } } } }
}),
ticks: { type: 'repeater', count: 48, distribution: { type: 'ring', center: { x: 480, y: 270 }, radius: 210, innerRadius: 209, mode: 'even' }, repeat: dot('#789f95', 3) },
contacts: particles({ count: 18, capacity: 32, distribution: { type: 'ellipse', center: { x: 480, y: 270 }, radius: 170 }, render: dot('#d8e6a7', 5), behaviors: [{ type: 'twinkle', min: 0.2, max: 1, rate: 0.6 }] })
};
const organic = graphic({ body: { type: 'spline', closed: true,
points: Array.from({ length: 12 }, (_, i) => ({ x: 480 + Math.cos(i * Math.PI / 6) * (110 + i % 3 * 23), y: 270 + Math.sin(i * Math.PI / 6) * 125 })),
style: { fill: '#537a63', stroke: '#acd2a0', strokeWidth: 3 },
behaviors: [{ type: 'point-wander', amplitude: { x: 28, y: 28 }, rate: 0.15 }, { type: 'pulse', property: 'style.opacity', amplitude: -0.35, frequency: 0.2 }]
} });
const network = particles({ count: 65, capacity: 96, distribution: { type: 'rectangle', center: { x: 480, y: 270 }, size: { width: 800, height: 410 } },
links: { rule: 'nearest', count: 3, maxDistance: 180, maxLinks: 160, fadeWithDistance: true, style: { stroke: '#6899b7', strokeWidth: 1 } },
behaviors: [{ type: 'noise-displace', amplitude: { x: 25, y: 25 }, scale: 120, speed: 0.1 }], render: dot('#d8e9f5', 4) });
const morph = graphic({
shape: { ...curve, style: { stroke: '#ecbf85', strokeWidth: 4 }, behaviors: [{ type: 'morph', to: 'target', duration: '6s', loop: 'ping-pong' }] },
target: { ...curve, visible: false, points: splinePoints.map((p, i) => ({ x: p.x, y: 270 + Math.cos(i * 0.9) * 150 })) }
});
const burst = { type: 'particles', lifecycle: 'spawned', spawn: { lifetime: '2s', release: '1s' }, count: 120, capacity: 128,
distribution: { type: 'point', position: { x: 480, y: 270 } }, velocity: { x: random(-160, 160), y: random(-160, 160) },
lifetime: '3s', size: { from: 1.5, to: 0.1 }, opacity: { from: 1, to: 0 }, render: dot('#f5c276', 4),
trail: { length: 20, mode: 'line', width: 2, style: { stroke: '#d98963', strokeWidth: 2 } }
};
const definitions = [
['deep-parallax-starfield', 'Deep parallax starfield', { layers: { far: { parallax: 0.2 }, near: { parallax: 1 } }, camera: { projection: 'perspective', focalLength: 1000 }, automation: [auto('camera.x', 400, 570)], systems: {
far: particles({ layer: 'far', count: 250, z: random(300, 1200), render: dot('#8c9ebf', 2) }), near: particles({ layer: 'near', count: 90, z: random(0, 200), render: dot('#ecdfc1', 3) }) } }],
['flow-field', 'Fog or smoke-like flow field', { fields: { flow: { type: 'noise', mode: 'curl', scale: 160, amplitude: 25, speed: 0.12 } }, systems: { flow: particles({ count: 150, fields: ['flow'], drag: 0.2, render: { type: 'ellipse', radius: 20, style: { fill: '#b5c1c0', opacity: 0.025 } }, behaviors: [wrap] }) }, effects: [{ type: 'blur', radius: 5 }] }],
['spline-network', 'Evolving spline network', { systems: { curves: graphic(Object.fromEntries(Array.from({ length: 6 }, (_, i) => [`c${i}`, { ...curve, position: { x: 0, y: (i - 3) * 35 }, behaviors: [{ type: 'point-wander', amplitude: { x: 30, y: 45 }, rate: 0.13 }] }]))) } }],
['weather-particles', 'Rain particles', { systems: { rain } }],
['mechanical-abstraction', 'Rotating mechanical abstraction', { systems: machine }],
['organic-pulse', 'Organic pulsing structure', { systems: { organic } }],
['instrument-display', 'Instrument and radar display', { systems: radar }],
['constellation-network', 'Constellation network', { systems: { network } }],
['persistent-landscape', 'Persistent landscape', { systems: { landscape } }],
['transient-impact', 'Transient impact burst', { systems: { burst } }],
['morphing-art', 'Morphing geometric art', { systems: { morph } }],
['audio-reactive', 'Audio-reactive visualization', { layers: { field: {} }, systems: { network: { ...network, layer: 'field' } }, effects: [{ type: 'bloom', intensity: 0.4 }] }, { bindings: [{ source: 'signals.audio.energy', target: 'visuals.layers.field.opacity', scale: 0.8, offset: 0.2 }, { source: 'signals.audio.low', target: 'visuals.camera.zoom', scale: 0.25, offset: 1 }] }],
['window-traffic', 'Window containing procedural traffic', { systems: {
background: graphic({ wall: { type: 'rectangle', size: { width: 960, height: 540 }, style: { fill: '#c8b69c' } }, window: { type: 'rectangle', position: { x: 150, y: 90 }, size: { width: 660, height: 360 }, style: { fill: '#273f49' } } }),
traffic: { type: 'repeater', count: 14, distribution: { type: 'grid', columns: 7, rows: 2, origin: { x: 185, y: 235 }, spacing: { x: 88, y: 75 } }, repeat: { type: 'rectangle', size: { width: 24, height: 8 }, style: { fill: '#eed092' }, behaviors: [{ type: 'drift', velocity: { x: 20, y: 0 } }, { type: 'wrap', bounds: { x: -30, y: -30, width: 60, height: 60 } }] } },
frame: graphic({ mullion: { type: 'rectangle', position: { x: 470, y: 85 }, size: { width: 12, height: 370 }, style: { fill: '#d8c8af' } }, border: { type: 'rectangle', position: { x: 145, y: 85 }, size: { width: 670, height: 370 }, style: { stroke: '#e8d8bf', strokeWidth: 12 } } })
} }],
['natural-abstraction', 'Natural meadow abstraction', { systems: { landscape, seeds: particles({ count: 70, velocity: { x: 12, y: -4 }, render: dot('#e8daa5', 3), behaviors: [wrap, { type: 'noise-displace', amplitude: { x: 12, y: 24 }, scale: 100, speed: 0.1 }] }) } }]
];
export const visualChallenges = definitions.map(([id, name, visuals, extra], index) => ({
id, challenge: index + 1, document: { xzbt: '0.1', meta: { id, name, version: '1.0.0', description: `PRD 130 challenge ${index + 1}; generic visual primitives only.` }, runtime: { seed: 4200 + index },
visuals: { scene: { coordinateSpace: 'virtual', width: 960, height: 540, background: '#101d25' }, ...visuals }, ...extra }
}));
export const visualExhibits = [
['exhibit-a', 'Exhibit A — Procedural Machine', { systems: machine }],
['exhibit-b', 'Exhibit B — Deep Abstract Field', { systems: { network, morph }, effects: [{ type: 'bloom', radius: 5, intensity: 0.5 }] }],
['exhibit-c', 'Exhibit C — Natural Environment', { systems: { landscape, rain } }],
['exhibit-d', 'Exhibit D — Instrument Display', { systems: radar, layers: { display: {} } }]
].map(([id, name, visuals]) => {
const document = { xzbt: '0.1', meta: { id, name, version: '0.1.0', description: 'First visual composition; full reference exhibit acceptance remains Phase 9.' }, runtime: { seed: 42 }, visuals: { scene: { coordinateSpace: 'virtual', width: 960, height: 540, background: '#101d25' }, ...structuredClone(visuals) } };
if (id === 'exhibit-d') {
for (const system of Object.values(document.visuals.systems)) system.layer = 'display';
document.state = { level: { type: 'number', initial: 0.7, min: 0, max: 1 } };
document.bindings = [{ source: 'state.level', target: 'visuals.layers.display.opacity', scale: 0.7, offset: 0.3 }];
}
return { id, document };
});