@field/cascade 0.3.1 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/AGENTS.md +32 -9
  2. package/ARCHITECTURE.md +75 -13
  3. package/CHANGELOG.md +98 -1
  4. package/CONTRIBUTING.md +104 -0
  5. package/DESIGN.md +24 -15
  6. package/README.md +121 -14
  7. package/dist/assets/{CodeEditor-D22fVi-4.js → CodeEditor-dOrU3aQg.js} +7 -7
  8. package/dist/assets/{CodePanel-DPNEYfcR.js → CodePanel-Bqy85qen.js} +2 -2
  9. package/dist/assets/{CustomNodeDialog-DeHCAvgb.js → CustomNodeDialog-DkZlOgjs.js} +1 -1
  10. package/dist/assets/{ProjectSettings-DWpVtWEx.js → ProjectSettings-D192mr6g.js} +2 -2
  11. package/dist/assets/{SettingsDialog-za00IS3L.js → SettingsDialog-BTeeIE3T.js} +1 -1
  12. package/dist/assets/{VersionHistoryDialog-DTMGhI0_.js → VersionHistoryDialog-TZQKkn3Y.js} +1 -1
  13. package/dist/assets/{core-JsyKMO1k.js → core-DwbcGL0o.js} +2 -2
  14. package/dist/assets/{cssMode-emdRheFK.js → cssMode-Dcjn356x.js} +1 -1
  15. package/dist/assets/definitions-C_SY6Bhg.js +1 -0
  16. package/dist/assets/{editor.api-xHX-fMSo.js → editor.api-D7Q83606.js} +1 -1
  17. package/dist/assets/{freemarker2-C3M8_Gs3.js → freemarker2-DCCiHlV6.js} +1 -1
  18. package/dist/assets/geo-CT-wtvaE.js +1 -0
  19. package/dist/assets/{handlebars-CBMurtFk.js → handlebars-BCxC8xu1.js} +1 -1
  20. package/dist/assets/{html-xbLQwknw.js → html-COwepzSd.js} +1 -1
  21. package/dist/assets/{htmlMode-2wKdDTon.js → htmlMode-Dpg7H0rx.js} +1 -1
  22. package/dist/assets/{image-i1j6nWKe.js → image-CMfMMxlC.js} +3 -3
  23. package/dist/assets/index-De1cIZ9N.js +212 -0
  24. package/dist/assets/index-ilgbOu6G.css +1 -0
  25. package/dist/assets/{javascript-DJaOo_2I.js → javascript-CSwWxfLr.js} +1 -1
  26. package/dist/assets/{jsonMode-Bheas8_0.js → jsonMode-BXRriTpj.js} +1 -1
  27. package/dist/assets/{liquid-BCj_BGbM.js → liquid-Cmkfyogc.js} +1 -1
  28. package/dist/assets/{lspLanguageFeatures-BfIsx_xz.js → lspLanguageFeatures-xH9JbZGO.js} +1 -1
  29. package/dist/assets/{mdx-DwiQDiVO.js → mdx-BzrNjNvK.js} +1 -1
  30. package/dist/assets/nodeTypeUtils-BDJsc2Ks.js +1 -0
  31. package/dist/assets/pop-BdKEHslJ.js +1 -0
  32. package/dist/assets/{python-BjrB5nqj.js → python-D4E9jbx7.js} +1 -1
  33. package/dist/assets/{razor-CfoBmGDs.js → razor-B3x9cIEM.js} +1 -1
  34. package/dist/assets/{tsMode-BcEoMSxp.js → tsMode-dhQYPNMZ.js} +1 -1
  35. package/dist/assets/{typescript-DIg7TEmQ.js → typescript-CITkDxAE.js} +1 -1
  36. package/dist/assets/{workers-vXYuwtPw.js → workers-BQvF9bbO.js} +1 -1
  37. package/dist/assets/{xml-DexLQIQy.js → xml-DvHlU3A8.js} +1 -1
  38. package/dist/assets/{yaml-DUnD_1dE.js → yaml-uznsLgs8.js} +1 -1
  39. package/dist/cli/index.js +16465 -12096
  40. package/dist/cli/runtime/gpu.ts +71 -0
  41. package/dist/cli/runtime/io.ts +31 -25
  42. package/dist/contracts/camera.d.ts +70 -0
  43. package/dist/contracts/camera.js +27 -0
  44. package/dist/contracts/capabilities.d.ts +6 -6
  45. package/dist/contracts/definition.d.ts +62 -4
  46. package/dist/contracts/index.d.ts +4 -0
  47. package/dist/contracts/index.js +4 -0
  48. package/dist/contracts/particles.d.ts +54 -0
  49. package/dist/contracts/particles.js +167 -0
  50. package/dist/contracts/scene.d.ts +129 -0
  51. package/dist/contracts/scene.js +73 -0
  52. package/dist/contracts/schema.js +26 -3
  53. package/dist/contracts/series.d.ts +75 -0
  54. package/dist/contracts/series.js +2 -0
  55. package/dist/contracts/validate.js +23 -5
  56. package/dist/contracts/values.d.ts +4 -2
  57. package/dist/contracts/values.js +10 -0
  58. package/dist/gpu.d.ts +17 -0
  59. package/dist/gpu.js +61 -1
  60. package/dist/index.html +3 -3
  61. package/dist/io.d.ts +4 -16
  62. package/dist/io.js +26 -8
  63. package/dist/player/app.js +810 -0
  64. package/dist/player/embed.d.ts +4 -0
  65. package/dist/player/embed.js +77 -0
  66. package/dist/player/types.d.ts +35 -0
  67. package/dist/runtime/builtins/core/camera.d.ts +252 -0
  68. package/dist/runtime/builtins/core/camera.js +149 -0
  69. package/dist/runtime/builtins/core/index.d.ts +4 -2
  70. package/dist/runtime/builtins/core/index.js +8 -2
  71. package/dist/runtime/builtins/core/structural.d.ts +168 -0
  72. package/dist/runtime/builtins/core/structural.js +175 -0
  73. package/dist/runtime/builtins/core/time.d.ts +165 -0
  74. package/dist/runtime/builtins/core/time.js +110 -0
  75. package/dist/runtime/builtins/geo/definitions.d.ts +247 -0
  76. package/dist/runtime/builtins/geo/definitions.js +70 -0
  77. package/dist/runtime/builtins/geo/index.d.ts +2 -1
  78. package/dist/runtime/builtins/geo/index.js +3 -1
  79. package/dist/runtime/builtins/geo/render.d.ts +87 -0
  80. package/dist/runtime/builtins/geo/render.js +87 -0
  81. package/dist/runtime/builtins/geo/svgExport.d.ts +11 -0
  82. package/dist/runtime/builtins/geo/svgExport.js +10 -0
  83. package/dist/runtime/builtins/index.d.ts +5 -2
  84. package/dist/runtime/builtins/index.js +13 -3
  85. package/dist/runtime/builtins/pop/definitions.d.ts +2120 -0
  86. package/dist/runtime/builtins/pop/definitions.js +815 -0
  87. package/dist/runtime/builtins/pop/index.d.ts +2 -0
  88. package/dist/runtime/builtins/pop/index.js +2 -0
  89. package/dist/runtime/builtins/scene/definitions.d.ts +356 -0
  90. package/dist/runtime/builtins/scene/definitions.js +224 -0
  91. package/dist/runtime/builtins/scene/index.d.ts +2 -0
  92. package/dist/runtime/builtins/scene/index.js +2 -0
  93. package/dist/runtime/camera/index.d.ts +60 -0
  94. package/dist/runtime/camera/index.js +234 -0
  95. package/dist/runtime/definition/architecture.js +36 -1
  96. package/dist/runtime/geometry/render.d.ts +109 -0
  97. package/dist/runtime/geometry/render.js +145 -0
  98. package/dist/runtime/geometry/svg.d.ts +29 -0
  99. package/dist/runtime/geometry/svg.js +11 -5
  100. package/dist/runtime/gpu.d.ts +33 -0
  101. package/dist/runtime/gpu.js +218 -0
  102. package/dist/runtime/index.d.ts +4 -0
  103. package/dist/runtime/index.js +4 -0
  104. package/dist/runtime/pop/cache.d.ts +27 -0
  105. package/dist/runtime/pop/cache.js +123 -0
  106. package/dist/runtime/pop/forces.d.ts +202 -0
  107. package/dist/runtime/pop/forces.js +519 -0
  108. package/dist/runtime/pop/index.d.ts +5 -0
  109. package/dist/runtime/pop/index.js +5 -0
  110. package/dist/runtime/pop/state.d.ts +136 -0
  111. package/dist/runtime/pop/state.js +283 -0
  112. package/dist/runtime/pop/trail.d.ts +62 -0
  113. package/dist/runtime/pop/trail.js +142 -0
  114. package/dist/runtime/runtime.js +284 -9
  115. package/dist/runtime/scene/index.d.ts +50 -0
  116. package/dist/runtime/scene/index.js +94 -0
  117. package/dist/runtime/series/index.d.ts +41 -0
  118. package/dist/runtime/series/index.js +167 -0
  119. package/dist/runtime/types.d.ts +1 -1
  120. package/dist/studio/panel.d.ts +68 -1
  121. package/doc/HEADLESS_GPU.md +160 -0
  122. package/doc/NODE_REFERENCE.md +408 -1
  123. package/doc/PROJECT_AUTHORING.md +118 -20
  124. package/doc/WEB_PLAYER.md +131 -0
  125. package/package.json +25 -3
  126. package/dist/assets/geo-BAR6lQp5.js +0 -1
  127. package/dist/assets/index-BDV5xGBZ.css +0 -1
  128. package/dist/assets/index-CMcH8AgP.js +0 -212
  129. package/dist/assets/nodeTypeUtils-BBA1JqHx.js +0 -1
package/AGENTS.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Cascade agent guide
2
2
 
3
- Cascade is a reusable generative-design graph runtime with an optional Studio UI. Keep authored algorithms independent from the editor so the same graph can run in Studio, on a server, or in a UI-free browser host.
3
+ Cascade is a reusable generative-design graph runtime with an optional Studio UI. Keep authored algorithms independent from the editor so a graph can run in Studio, on a server, or in a UI-free browser host when its declared execution locus and capabilities are supported.
4
4
 
5
5
  ## Start here
6
6
 
@@ -37,6 +37,15 @@ my-project/
37
37
 
38
38
  Use `cascade new <name>` to create a project and `cascade node <Name>` to scaffold a custom node in one. Run `cascade .` from a project root to open Studio, `cascade validate <graph.cascade>` for validation, `cascade check <graph.cascade>` for static definition/type checks, `cascade inspect <graph.cascade>` for a JSON summary, `cascade run <graph.cascade>` for headless execution, and `cascade run <graph.cascade> --frames 1-100` for an offline image sequence. `cascade projects` shows or sets the default projects directory.
39
39
 
40
+ `cascade build <graph.cascade> --out <new-directory>` exports a static browser
41
+ player. Use repeatable `--asset <project-relative-file>` for inputs whose paths
42
+ are computed in code. Read `doc/WEB_PLAYER.md` before exporting: server stages
43
+ and dynamic modules are not supported, assets must be explicit, and an existing
44
+ output directory is never overwritten. Serve the result over HTTP, not file://.
45
+ The player is an application host under `src/player`, not another graph engine.
46
+ Each embed owns an iframe realm, assets, IO bridge and GPU lifecycle. No Studio
47
+ imports or `/api/*` dependency may enter the static deployment.
48
+
40
49
  ## Launch Studio
41
50
 
42
51
  For a browser on the same machine, use the secure loopback default:
@@ -73,7 +82,7 @@ Project panels are trusted Studio extensions, not graph/runtime modules. Put the
73
82
 
74
83
  ## Create a deterministic node
75
84
 
76
- Two node styles exist and both are current. A **definition-v1** module exports a literal `definition` and a typed `execute(context)`; it is statically inspectable, it is what `cascade check` requires, and it runs through the deterministic runtime. A **dynamic** module exports `execute(node, graph)` and declares its ports and parameters imperatively inside it; that is what `cascade run --frames` renders. Studio cooks both, dispatching on what the compiled module exports (`src/nodes/definition/projectDefinition.ts`), so a project node written either way runs in the editor. Prefer definition-v1 for anything new inside this repository, and do not call dynamic modules "legacy" — the naming was retired in 0.3.0, and while Studio no longer blocks the migration, the existing sketches are still dynamic.
85
+ Two node styles exist and both are supported. A **definition-v1** module exports a literal `definition` and a typed `execute(context)`; it is statically inspectable and is what `cascade check` requires. A **dynamic** module exports `execute(node, graph)` and declares its ports and parameters imperatively inside it. Studio cooks both through `src/nodes/definition/projectDefinition.ts`. The CLI supports stills and frame sequences for fully deterministic graphs and for supported dynamic graphs, but rejects graphs mixing the two execution styles. Prefer definition-v1 for new nodes; inspect a project's current modules before assuming its style. Do not call dynamic modules "legacy" in user-facing guidance.
77
86
 
78
87
  A definition-v1 module looks like this:
79
88
 
@@ -107,6 +116,9 @@ Definition rules:
107
116
  and have the host registration select the executor. Never expose execution
108
117
  location as an artist parameter; parity-test the shared contract.
109
118
  - Declare every capability used. File, Python, and shell access are server-only; WebGL is browser-only.
119
+ - `context.nodeId` identifies the instance for namespaces such as `cachePath(context.nodeId, '.png')`; it does not grant access to siblings or hierarchy. A final output may instead have an artist-authored filename.
120
+ - Vector props support `min`, `max`, and `step`, shared across components. Props may declare a default `expression`; an explicitly saved value overrides that default, including when it equals the numeric default.
121
+ - WebGPU nodes declare `gpu` and use its shared device and per-node `cache`. Portable GPU nodes can run through optional Dawn in the CLI; browser-only declarations remain refused. Import constants and explicit `readTexture` (RGBA8 only) from `cascade/gpu`. Graph texture exchange remains future work. See `doc/HEADLESS_GPU.md` for bounded agent renders, diagnostics and hardware tests.
110
122
  - Treat graph wires as the primary data boundary. A node may observe only its connected inputs, its props, and declared host capabilities; it must not inspect sibling nodes or the graph to discover data.
111
123
  - Deterministic node modules may not retain module-level mutable values, access ambient state such as `globalThis`, browser storage, or `process`, run top-level effects, or import sibling node implementations. `cascade check` reports these as `architecture/*` diagnostics.
112
124
  - A cache may memoize computation from wired inputs, but it must never supply unwired data. Make cache use an explicitly labelled prop and keep cache keys derived from the complete wired input and relevant props.
@@ -124,6 +136,7 @@ Use the runtime-native core vocabulary before creating a project wrapper:
124
136
  - `cascade.core.Null` passes any value through unchanged so downstream wiring can remain stable while upstream branches are reorganized.
125
137
  - `cascade.core.Random` maps explicit integer `seed` and `sample` inputs to a stable float in `[0, 1)`.
126
138
  - `cascade.core.Remap` maps scalar ranges and optionally clamps via its `clamp` prop.
139
+ - `cascade.core.Camera` emits the one `camera` type, following Houdini's `/obj/cam`: `translate` and `rotate` (degrees, XYZ) with an optional `lookat`, and a lens given as `focal` and `aperture` in millimetres rather than as a field of view. A camera looks down its own **-Z** with **+Y** up. `resolution` is on the camera because Houdini derives the vertical aperture from the frame shape, and it is one `vec2i` rather than Houdini's `resx`/`resy` because the vec rule below is the more specific one. Every derivation — the basis, the view and projection matrices, the horizontal and vertical angles — lives in `packages/runtime/src/camera`; never derive them a second time in a renderer.
127
140
 
128
141
  The geometry set is reserved the same way, under `cascade.geo.*`:
129
142
  `Rectangle`, `Circle`, `Transform`, `Merge`, `CopyToPoints`, and `SvgExport`.
@@ -131,6 +144,15 @@ They all speak the one `geometry` type, so any output fits any input, and they
131
144
  follow Houdini's parameter names where Houdini has an equivalent node. Geometry
132
145
  is +Y up; the flip into SVG's frame lives in `SvgExport` alone.
133
146
 
147
+ `cascade.pop.*` uses geometry-native particle state; forces accumulate and the
148
+ solver integrates once. `cascade.core.Feedback` owns previous state and bounded
149
+ history, including nested loops. Trails are geometry, not a second canvas
150
+ history. A checkpoint is only an accelerator: cold and warm runs must match
151
+ complete geometry and trails. `cascade.scene.*` assembles geometry, camera and
152
+ lights; the current renderer draws wireframes/points and does not shade lights.
153
+ Read the generated reference for the complete library rather than extending
154
+ the partial vocabulary examples in this guide.
155
+
134
156
  These modules are reserved and need no file under `nodes/`. Do not override a
135
157
  `cascade.core.*` module or use ambient random/time state in a portable node.
136
158
  Time and randomness reach a parameter as an expression or a keyframe channel,
@@ -146,13 +168,13 @@ type system knows what a `vec2` is; nothing tells it that `offset_x` and
146
168
 
147
169
  ## Animation, expressions, and parameters
148
170
 
149
- - **`Node.evalParm` in `src/nodes/Node.ts` is the only place a parameter's bindings resolve**, in the order channel, expression, value. Never read `prop.value` to obtain an animated parameter, and never add a second resolution path: an expression badge and a viewer disagreeing about the same frame is exactly what one produced.
171
+ - **`resolvePropBinding` in `packages/runtime/src/params/resolve.ts` owns binding precedence:** channel, expression, value. Studio's `Node.evalParm` and the neutral runtime both call it with their own expression scope and frame. Never read `prop.value` to obtain an animated parameter or implement a second precedence rule.
150
172
  - **A parameter is one store.** `param()` declares the parameter; the value, the expression and the channel live in the prop of the same name. `NodeParameter.value` reads *resolved*; `rawParameterValue()` reads what the author typed, and is what serialization and cache keys must use. `param()` is re-declared on every cook of a dynamic node, so it must stay idempotent — it may never reset a value, an expression, or a channel.
151
173
  - **Mechanisms belong to the runtime, composition to the host.** `packages/runtime/src/expressions` owns preprocessing, scope and the maths library; `packages/runtime/src/animation` owns the channel model, sampling, interpolation, serialization and frame-range walking. Both depend only on contracts. Do not implement interpolation, a frame clock, or a second `$T` anywhere else.
152
174
  - **The serialized shape is owned by contracts** (`packages/contracts/src/animation.ts`): a channel is `{ keys: [{ frame, value, interpolation? }] }` inside the node's `props`, with `interpolation` omitted when it is the `smooth` default. There is no timeline section in the document, and adding one would need reconciling on every rename, delete and embed.
153
175
  - Bare trigonometry is **radians**, deliberately unlike Houdini; `sind`/`cosd`/`tand`/`radians()`/`degrees()` exist for formulae carried over. Only `ch()`, `chs()` and `chv()` are scanned for dependencies, so a new way to reach another parameter also needs a dependency pattern or it will not recook.
154
- - The deterministic runtime has no parameter animation. `cascade run --frames` refuses a definition-v1 graph rather than rendering frame 1 repeatedly. Extending animation to that runtime is a migration step; do not add a compatibility branch to Studio for it.
155
- - Studio's timeline panel holds its own frame range, loop and playhead. Only fps reaches the engine clock. Nothing about playback is saved with the document.
176
+ - The deterministic runtime resolves parameter animation through `setFrame`, `setFps`, and `run({ frame, fps })`. `cascade run --frames` supports fully definition-v1 graphs when the Node host can supply their capabilities. A browser-only node still cannot run in that host.
177
+ - Studio's timeline supplies the playhead and fps to the engine; its range and loop setting are panel state. Parameter channels are saved in the document, but playback settings are not.
156
178
 
157
179
  ## Agent sessions
158
180
 
@@ -178,7 +200,7 @@ type system knows what a `vec2` is; nothing tells it that `offset_x` and
178
200
  - Contracts have no runtime dependencies.
179
201
  - Runtime depends only on contracts and contains no DOM, Svelte, Express, Node filesystem, or child-process imports.
180
202
  - Hosts inject capabilities explicitly.
181
- - Studio consumes runtime through its controller; custom frontends consume runtime directly.
203
+ - Studio uses `StudioGraphController` over its compatibility `Graph`/`Node` engine and reuses runtime mechanisms. Custom frontends consume the neutral runtime directly; full Studio migration remains incomplete.
182
204
  - User modules are trusted project code, not a sandbox. Static definitions improve tooling and portability, not isolation.
183
205
  - Keep legacy support inside the existing Studio/CLI compatibility engine; do not spread compatibility branches into the deterministic runtime.
184
206
 
@@ -198,9 +220,10 @@ Do not add dependencies without a concrete need. Do not create extra packages un
198
220
 
199
221
  ## Versioning
200
222
 
201
- Cascade `0.2.0` is the 2026 architecture rework. The current release is `0.3.0`,
202
- which added the animation system and the agent console; `CHANGELOG.md` records
203
- what changed and is the file to update before a release commit. Increment the
223
+ Cascade `0.2.0` is the 2026 architecture rework; `0.3.0` added animation and the
224
+ agent console. Read `package.json` for the checkout version and `CHANGELOG.md`
225
+ for release history and unreleased changes; a local build can contain changes
226
+ not yet in the published package. Update the changelog before a release commit. Increment the
204
227
  root package and CLI patch version for every committed feature or release
205
228
  change, keeping `package.json`, the lockfile, and CLI output aligned. A minor
206
229
  bump is for a feature large enough to need its own `CHANGELOG.md` section.
package/ARCHITECTURE.md CHANGED
@@ -20,18 +20,19 @@ Contracts contain no DOM, Svelte, Express, filesystem, process, or implementatio
20
20
 
21
21
  The runtime is environment-neutral. It works in Node and browsers without importing either platform’s APIs, and it never imports Studio. Registration is sealed after the first graph load. Each graph permits one active run and has explicit lifecycle states.
22
22
 
23
- The reserved `cascade.core.*` registry is owned here. `Subnet`, `Input`,
24
- `Output`, `Switch`, `Merge`, `Select`, `Null`, seeded `Random`, and `Remap` resolve
25
- without a project module loader. Named, typed root Input/Output nodes form an
26
- explicit headless graph interface; typed child Input/Output nodes form a subnet interface.
27
- Randomness is a pure function of an authored seed, never ambient process state.
23
+ Reserved built-ins are registered once in `packages/runtime/src/builtins`:
24
+ core hierarchy/routing/time/camera, geometry operations, particle simulation,
25
+ and scene assembly. They need no project module file. The generated
26
+ [node reference](doc/NODE_REFERENCE.md) owns the complete port/parameter list.
27
+ Named, typed root Input/Output nodes form the public graph interface; child
28
+ Input/Output nodes form a subnet interface. Randomness takes an authored seed.
28
29
 
29
30
  ## Hosts
30
31
 
31
32
  Hosts adapt the neutral runtime to an environment:
32
33
 
33
- - Node: files, assets, media, Python, and shell.
34
- - Browser: assets, media, and WebGL.
34
+ - Node: files, assets, media, Python, shell, and optional Dawn WebGPU in the CLI.
35
+ - Browser: assets, media, and the `gpu` capability when WebGPU is available.
35
36
  - Mixed application: an explicit bridge for serializable server stages.
36
37
 
37
38
  Capabilities are injected. A node’s literal `runsOn` and `capabilities` fields are checked before its `execute` module is loaded.
@@ -44,11 +45,19 @@ resize, composite, and encode when both Canvas/WebGL and native implementations
44
45
  exist. Both executors must obey the same definition and should share golden
45
46
  parity tests for geometry, metadata, and edge cases.
46
47
 
48
+ `packages/runtime/src/gpu.ts` owns shared device/cache lifecycle with an injected
49
+ acquisition function. Studio acquires browser WebGPU; `src/cli/headlessGpu.ts`
50
+ loads optional Dawn lazily. The runtime awaits readiness and supplies a per-node
51
+ view; the application owns disposal. `cascade/gpu` supplies explicit RGBA8
52
+ readback without encoding or colour conversion. Graph ports still exchange
53
+ images; GPU-resident intermediate connections remain future work. See
54
+ [headless GPU rendering](doc/HEADLESS_GPU.md).
55
+
47
56
  `server/` is the project-scoped Node application host. It owns project paths, compilation, HTTP transport, media serving, Python workers, shell policy, and credentials. It is separately manifested and is not a third contracts/runtime workspace.
48
57
 
49
58
  ## Applications and controllers
50
59
 
51
- Studio’s Svelte components under `src/editor` own rendering, selection, panels, and interaction state. Its compatibility graph now has one graph-owned cook scheduler, while `StudioGraphController` centralizes an increasing set of structural mutations and publishes view snapshots. Compatibility adapters still present runtime-owned built-ins in Studio; collapse/extract and the remaining legacy nodes must migrate before Studio can consume `packages/runtime` directly.
60
+ Studio’s Svelte components under `src/editor` own rendering, selection, panels, and interaction state. Its compatibility graph now has one graph-owned cook scheduler, while `StudioGraphController` centralizes an increasing set of structural mutations and publishes view snapshots. Compatibility adapters still present runtime-owned built-ins in Studio; collapse/extract and the remaining dynamic compatibility nodes must migrate before Studio can consume `packages/runtime` directly.
52
61
 
53
62
  Studio uses Dockview through the public `dockview` API. Code panels lazy-load
54
63
  Monaco and its native editor/TypeScript workers rather than adding Monaco to the
@@ -59,9 +68,12 @@ Custom server applications and browser frontends use `cascade/runtime` directly
59
68
 
60
69
  ## Distribution
61
70
 
62
- The repository has exactly two internal npm workspaces: `@cascade/contracts` and `@cascade/runtime`. The root `cascade` package is the only published package and the only owner of the executable.
71
+ The repository has exactly two internal npm workspaces: `@cascade/contracts` and `@cascade/runtime`. The root `@field/cascade` package, normally installed under the alias `cascade` in projects, is the only published package and executable owner.
63
72
 
64
- Public subpaths are `cascade/contracts`, `cascade/contracts/schema`, `cascade/runtime`, `cascade/runtime/node`, `cascade/runtime/browser`, `cascade/runtime/expressions`, `cascade/runtime/animation`, `cascade/runtime/definition/extract`, `cascade/io`, `cascade/net`, `cascade/stage`, and the compatibility `cascade/shell`.
73
+ Public subpaths include contracts/schema, runtime and its Node/browser,
74
+ expression, animation, camera, render, scene and definition-extraction entries,
75
+ plus `cascade/io`, `cascade/gpu`, `cascade/net`, `cascade/stage`,
76
+ `cascade/shell`, and `cascade/player`. `package.json` is the exact export map.
65
77
 
66
78
  Studio-only project extensions use the type-only `cascade/studio/panel` contract. They are compiled and loaded only by Studio; the neutral runtime and headless hosts never discover or import them.
67
79
 
@@ -113,15 +125,57 @@ Data runs follow graph dependencies. Explicit triggers use a FIFO queue, authore
113
125
 
114
126
  Execution failures resolve to a failed `RunResult`; API misuse and invalid preflight reject. Cancellation propagates through capability calls. Inspection and output values are immutable snapshots; browser-only live resources remain host-owned handles.
115
127
 
128
+ ### Geometry, simulation and feedback
129
+
130
+ Geometry is a shared typed value with point/vertex/primitive attributes,
131
+ topology and groups, not an editor object. POP uses that same value for
132
+ particle state. Forces accumulate acceleration; the solver integrates once
133
+ per timestep. Trails are geometry and can feed the ordinary render/export nodes.
134
+
135
+ `cascade.core.Feedback` is an explicit stateful container within the data DAG.
136
+ Its children run per step; nested Feedback owns its own descendants. Previous
137
+ state and bounded history are wired values, not sibling lookups. Result and
138
+ history use normal output staging and cancellation, with transient loop state
139
+ released even when a child throws.
140
+
141
+ POP checkpoints accelerate deterministic re-simulation; clearing them must not
142
+ change particles **or trails**. The sparse derived cache is module-local, has a
143
+ 64-checkpoint bound across keys, and copies snapshots at its boundary. It does
144
+ not define simulation state. CLI `--frames` already reuses a loaded runtime,
145
+ so it can benefit from checkpoints within the sequence. Separate CLI launches
146
+ do not share that cache.
147
+
148
+ A `scene` contains geometry, an optional camera and lights. A missing camera
149
+ means the viewer supplies its view; an explicit render requires an authored
150
+ camera. The current shared CPU renderer draws wireframes and points, not lit
151
+ surfaces. Camera derivations belong to `packages/runtime/src/camera`; Studio's
152
+ 3D view and offline rendering use that convention rather than separate matrices.
153
+
154
+ ### Browser player
155
+
156
+ The player is a browser application host under `src/player`, not another graph
157
+ engine or package. Static export compiles definition-v1 project modules into
158
+ browser ESM and supplies assets locally. Studio, Python, shell and project
159
+ server routes are not deployment dependencies. Unsupported server operations
160
+ fail explicitly during export. See [browser player](doc/WEB_PLAYER.md) for the
161
+ build/embed contract and current limitations.
162
+
163
+ Each embed has its own iframe realm, runtime, IO bridge, assets and GPU host.
164
+ This isolates existing ambient `cascade/io` imports without swapping global
165
+ transports between asynchronous runs. Shared browser GPU acquisition lives in
166
+ `src/browser/gpu.ts`, also used by Studio. A future migration to explicit
167
+ capability-only IO could permit direct DOM mounts; that is not implemented by
168
+ the iframe player.
169
+
116
170
  ## Animation
117
171
 
118
- A parameter carries up to three bindings: a raw value, an expression, and a keyframe channel. They resolve in exactly one place, `Node.evalParm` in the compatibility engine (`src/nodes/Node.ts`), in the order channel, expression, value. A channel that samples takes precedence and leaves the expression stored but inert, so emptying the channel restores it. Nothing else in Studio may read a prop's `value` directly to obtain an animated parameter; a second resolution path is how an expression badge and a viewer disagree about the same frame.
172
+ A parameter carries up to three bindings: a raw value, an expression, and a keyframe channel. `packages/runtime/src/params/resolve.ts` owns their shared resolution rule: channel, expression, value. A channel that samples takes precedence and leaves the expression stored but inert, so emptying the channel restores it. Studio invokes the resolver from `Node.evalParm`; the deterministic runtime invokes it through `PropAnimator`. Nothing else in Studio may read a prop's `value` directly to obtain an animated parameter; a second rule is how an expression badge and a viewer disagree about the same frame.
119
173
 
120
- The mechanisms are runtime-owned and the composition is not. `packages/runtime/src/expressions` owns preprocessing (`$F`, `$FF`, `$T`, `$FPS` rewritten to plain identifiers), the evaluation scope, and the maths library; `packages/runtime/src/animation` owns the channel model, sampling, interpolation, serialization, and frame-range walking. Both depend only on contracts, so `cascade run` and Studio animate a dynamic graph through the same code rather than two implementations of Hermite interpolation.
174
+ The mechanisms are runtime-owned and the composition is host-specific. `packages/runtime/src/expressions` owns preprocessing (`$F`, `$FF`, `$T`, `$FPS` rewritten to plain identifiers), the evaluation scope, and the maths library; `packages/runtime/src/animation` owns the channel model, sampling, interpolation, serialization, and frame-range walking; `packages/runtime/src/params` owns binding resolution and deterministic graph-wide animation. These modules depend only on contracts or other runtime modules. Studio supplies its compatibility graph scope, while `PropAnimator` supplies the neutral runtime scope, including lazy `ch()` dependency resolution.
121
175
 
122
176
  `packages/contracts/src/animation.ts` owns the serialized shape. A channel lives inside the node's `props`, not in a separate timeline object, because a parameter's animation belongs to the parameter; a document with a timeline section would need reconciling every time a node was renamed, deleted, or embedded.
123
177
 
124
- The deterministic runtime has no parameter animation. A definition-v1 graph owns its own clock, so `cascade run --frames` refuses it explicitly rather than producing a hundred copies of frame 1. Extending animation to the deterministic runtime is a migration step, not a compatibility branch to add in Studio.
178
+ The deterministic runtime has parameter animation and an explicit graph clock. `setFrame(frame)` and `setFps(fps)` re-resolve bound props without cooking, so inspection can scrub deterministically. `run({ frame, fps })` resolves every bound prop before node execution; the same graph at the same authored state, frame, and fps receives the same parameter values. `cascade run --frames` uses this path for definition-v1 graphs and passes each requested frame and fps into the run. The runtime never reads wall-clock time.
125
179
 
126
180
  ## Agent sessions
127
181
 
@@ -139,6 +193,14 @@ Document freshness is a watcher, not a poll of the agent. `server/src/graphWatch
139
193
 
140
194
  Project node modules are trusted code. Capabilities describe support and portability; they are not a sandbox.
141
195
 
196
+ Studio binds to loopback by default. Remote access requires a specific
197
+ hostname or private interface address via `--host`; wildcard remote binds are
198
+ rejected. That non-loopback host becomes the default trusted browser hostname,
199
+ and repeatable `--trusted-host` values add exact browser authorities when the
200
+ bind address and public hostname differ, including a reverse proxy to a
201
+ loopback bind. Every reachable peer on that trusted interface can access the
202
+ project APIs, so this mode is intended for an authenticated VPN or trusted LAN.
203
+
142
204
  All project HTTP APIs require an exact allowed Host. Origin is validated when
143
205
  present and hostile or null Origins are rejected; same-origin GETs may omit it.
144
206
  Filesystem resolution checks lexical paths and canonical existing targets or
package/CHANGELOG.md CHANGED
@@ -2,7 +2,69 @@
2
2
 
3
3
  Notable changes to Cascade. Newest first.
4
4
 
5
- ## Unreleased
5
+ ## 0.5.1 — 2026-09-09
6
+
7
+ - Prepared the 0.5 browser-player release for npm, with updated README and
8
+ cascade.field.io documentation covering web embeds, geometry, subnets,
9
+ particles, Feedback, scenes, animation and bounded Dawn renders for agents.
10
+ - Clarified browser/server execution limits, current wireframe/point rendering,
11
+ explicit asset packaging and same-origin player controls. The npm homepage
12
+ now points to cascade.field.io.
13
+
14
+ ## 0.5.0 — 2026-09-09
15
+
16
+ ### Browser player
17
+
18
+ - `cascade build <graph> --out <new-directory>` exports definition-v1 graphs as
19
+ static pages with a lightweight iframe embed API. Browser execution supports
20
+ assets and WebGPU; server capabilities and dynamic modules are rejected at
21
+ build time. No Studio server is required. See [Web player](doc/WEB_PLAYER.md).
22
+ - Each embed owns its runtime, IO bridge and generated assets. Playback and
23
+ edits serialize, failed cooks pause playback, and disposal releases resources.
24
+ Generated images have immutable paths and explicit retention limits.
25
+ - Browser image loading now decodes bridged assets correctly, including SVG
26
+ bitmaps. Studio and the player share browser GPU acquisition.
27
+
28
+ ### Runtime correctness and performance
29
+
30
+ - POP checkpoint caching enforces its 64-entry bound even for one simulation,
31
+ copies mutable particle state at the boundary, and replays the trail window
32
+ so warm and cold renders agree. Malformed field and trail data report errors.
33
+ - Nested Feedback runs children only in their owning loop, orders dependencies
34
+ across container boundaries, publishes history consistently, and clears
35
+ transient state after failures or cancellation.
36
+
37
+ ### Documentation and verification
38
+
39
+ - Updated architecture, authoring and agent guides for geometry, simulations,
40
+ scenes and static deployment. Added real-browser embed and packed-consumer
41
+ checks alongside focused runtime and IO regressions.
42
+ - Retired archived Quill examples with a recoverable backup; removed incidental
43
+ Quill examples from current guidance while retaining removed-node rejection tests.
44
+ - Streamlined shared player image decoding, MIME inference and cleanup error
45
+ handling without changing the public player contract.
46
+ - Removed unused Studio component props and consolidated CLI execution-style
47
+ checks. Empty/dynamic fallback and mixed-graph rejection remain unchanged.
48
+ - Deleted the unreachable WindowManager UI and its private window/tab components;
49
+ Dockview remains Studio's sole layout host. Removed the commented-out Canvas
50
+ sample initializer. The active Graph/Node compatibility engine is unchanged.
51
+
52
+ ## 0.4.0 — 2026-09-09
53
+
54
+ ### Documentation
55
+
56
+ - Updated current guides and generated project instructions for definition-v1
57
+ animation, stored `props`, instance identity, vector metadata, and the shared
58
+ GPU capability. Clarified host requirements, Studio's remaining runtime
59
+ migration, export limitations, and the distinction between implemented
60
+ workflows and future product directions.
61
+
62
+ ### Animation
63
+
64
+ - The deterministic runtime resolves expressions and keyframe channels at an
65
+ explicit frame through the shared parameter resolver. `cascade run --frames`
66
+ can render fully definition-v1 graphs with compatible Node-host capabilities;
67
+ mixed definition-v1/dynamic graphs remain unsupported by the CLI.
6
68
 
7
69
  ### Node authoring
8
70
 
@@ -27,6 +89,41 @@ Notable changes to Cascade. Newest first.
27
89
 
28
90
  - **The CLI build resolves `@cascade/runtime/params`.** `src/nodes/Node.ts` imports `resolvePropBinding` from it, the browser build resolved it through `vite.config.ts`, and the CLI build had no alias — so the CLI, which is what the sketches actually run, was the broken half.
29
91
 
92
+ ### Camera
93
+
94
+ - **A camera is a core type, and it is Houdini's camera.** `camera` joins `CORE_TYPES`, `cascade.core.Camera` emits one, and every derivation — basis, view and projection matrices, horizontal and vertical angle — lives in `cascade/runtime/camera` so no renderer derives it twice. Following `/obj/cam` costs the two things the obvious design would have done instead: there is **no field of view** (`focal` and `aperture` in millimetres, angle derived — Houdini's 50 mm on 41.4214 mm is exactly 45°), and the orientation is **`translate` and `rotate`** rather than eye-and-target, looking down its own **-Z** with **+Y** up, with look-at layered on top as an override. `resolution` is on the camera because Houdini derives the vertical aperture from the frame shape; it is one `vec2i` rather than `resx`/`resy` because the vec rule is the more specific one. Matching a frame is therefore always one number, never two.
95
+ - `rotate.z` is a roll about the camera's own view direction. The first two rotation orders tried were indistinguishable from this one by every test in the suite — with `rotate.z` at zero all three agree exactly — so the test that separates them asserts that roll changes the up and leaves the view direction alone.
96
+
97
+ ### Series
98
+
99
+ - **A series is a graph plus an ordered list of parameter sets** (`CascadeSeries`, `runSeries`), cooked once per set and addressed by **record id, never index**, because a filter change reorders a set and a judgement pinned to a position silently becomes a different picture. `CascadePreset` and `applyPreset` already were the parameter set and had no callers. There is no marked region: the affected subgraph is derived from the overrides, so nothing can be marked wrongly.
100
+ - A parameter set is **sparse**, so every instance cooks from a baseline captured before the first `applyPreset` — otherwise an instance that overrides nothing inherits the previous one's values, which is accidental feedback in a mechanism specified as having none, and it presents as a flaky renderer rather than as a bug. `first` reorders the work and never the results, so a gallery fills in as instances land without the list reshuffling under a selection.
101
+
102
+ ### Capabilities
103
+
104
+ - **Studio can reach the shell.** The server has had an allowlist-gated `/api/shell` for a while and Studio never wired it as a node capability, so a definition declaring `capabilities: ['shell']` ran through `cascade run` and threw in the browser — a node marked `runsOn: 'portable'` that runs in one host is what `runsOn` exists to prevent. A `CascadeAbortSignal` is bridged to a DOM one rather than serialised; a 403 re-handshakes exactly once and then reports, naming the Allowed Commands editor rather than a status code.
105
+
106
+ ### Correctness
107
+
108
+ - **A `vec3` prop stays a `vec3`.** `isColorValue` answers true for any three- or four-number array and the deserialise path had no `type === 'color'` guard, so every vector prop in every sketch was rewritten on load — `[0.55, 0.12, 1.95]` reached `execute` as a colour object, coerced and divided by 255. A guard existed one branch away and never ran, because a **project** module's definition arrives asynchronously and `node.parameters` is empty at load. Coercion is now decided by ambiguity: objects and strings still normalise, arrays only where the prop is already declared a colour.
109
+ - **An error in the log says what it is.** The Log panel `JSON.stringify`s any object and `Error.message` is non-enumerable, so a `TypeError` and a `GPUPipelineError` were equally invisible as `{}`.
110
+ - **Selecting a failing node no longer cooks it forever.** The Viewer's rAF pump is throttled to 100 ms and polls its watched node while dirty; an execute that throws never reaches `clean`, so it ran a full `scheduler.flush()` ten times a second, re-fetching inputs over the network, at 61 fps and never looking wrong. `Node.hasSettledFailure` is what the poll now skips — deliberately not folded into `isDirty`, because an explicit `requestOutput` still retries and that is the transient GPU and network case.
111
+ - **Renaming a node is a double click.** The name label sits in the middle of the node body and a single click opened the rename editor, so aiming at a node to select it renamed it instead, in memory only and discarded on reload.
112
+ - **A proxied Studio can save.** `https` origins are accepted and default ports matched, so a reverse-proxied or Tailscale-served Studio can POST — which is also what unblocks WebGPU, the clipboard and the microphone, all of which need a secure context.
113
+
114
+ ### Headless GPU
115
+
116
+ - Optional pinned Dawn (`webgpu@0.6.0`) in the CLI, loaded only for GPU execution.
117
+ Browser and Node hosts reuse shared device/cache lifecycle; portable and server
118
+ definitions may declare `gpu`. Browser-only nodes remain browser-only.
119
+ - Explicit `cascade/gpu` RGBA8 texture readback, with padded-row removal and
120
+ cancellation cleanup. Graph texture transport remains outside this stage.
121
+ - `run --frames ... --json` returns an image manifest and adapter metadata;
122
+ `--timeout <ms>` runs a supervised render process for agent/test callers.
123
+ Dedicated opt-in hardware and packed-package gates exercise real GPU output.
124
+ - Documented the decision, local/unreleased status, CLI manifest contract,
125
+ verification evidence and platform limits in [Headless GPU](doc/HEADLESS_GPU.md).
126
+
30
127
  ## 0.3.1
31
128
 
32
129
  ### Fixed
@@ -0,0 +1,104 @@
1
+ # Contributing to Cascade
2
+
3
+ Cascade is a free, MIT-licensed creative graph platform. Contributions can be
4
+ bug reports, reproducible sketches, documentation, tests, or code. Core
5
+ development does not require an AI provider or a paid service account.
6
+
7
+ ## Find the owning layer
8
+
9
+ Read [AGENTS.md](AGENTS.md) for repository conventions, [DESIGN.md](DESIGN.md)
10
+ for product decisions, and [ARCHITECTURE.md](ARCHITECTURE.md) for dependencies.
11
+
12
+ - `packages/contracts/` owns public types and serialized formats.
13
+ - `packages/runtime/` owns environment-neutral execution mechanisms.
14
+ - `server/` owns project files, compilation, processes, and host transports.
15
+ - `src/editor/` owns Studio interactions and presentation.
16
+ - `src/player/` owns the standalone browser host and embed controls.
17
+ - Sketch repositories own creative algorithms, providers, and project panels.
18
+
19
+ Keep provider SDKs and client-specific data in projects. Do not add dependencies
20
+ or packages without a demonstrated need and an agreed scope.
21
+
22
+ ## Develop and verify
23
+
24
+ Use Node.js 22.13 or newer. Install dependencies with `npm install`; the core
25
+ uses TypeScript 6. `npm run dev` starts the Studio development frontend.
26
+ Project-host workflows are exercised through a built CLI and a project folder.
27
+
28
+ Add a focused regression test for a behavior change, make the smallest change
29
+ at the owning layer, and run that test first. Use the applicable repository gates:
30
+
31
+ ```bash
32
+ npm run check
33
+ npm run test:run
34
+ npm --prefix server run build
35
+ npm run build
36
+ npm run build:cli
37
+ git diff --check
38
+ ```
39
+
40
+ `npm run build` also runs `build:cli` through its postbuild hook. Keep a final
41
+ CLI build after any separate Vite build because Vite refreshes `dist/`. Coordinate
42
+ rebuilds when running Studio servers serve from that checkout.
43
+ Do not run package builds concurrently with tests that read generated package
44
+ files: the builds replace those directories while tests may be importing them.
45
+
46
+ For public API or packaging changes, run `npm run test:package`, which exercises
47
+ the packed distribution from a temporary consumer. Built-in node-definition or
48
+ registry changes also require `npm run build:node-reference`; include its result.
49
+
50
+ For player changes, run `npm run test:player` after building the CLI. It opens
51
+ an isolated headless Chrome profile and checks actual pixels, multiple embeds,
52
+ playback and disposal on a static server. Set `CASCADE_CHROME` to the Chrome
53
+ executable on non-macOS systems. `CASCADE_TEST_PLAYER=1 npm run test:package`
54
+ also runs that proof against the installed tarball. GPU package verification
55
+ is opt-in separately with `CASCADE_TEST_DAWN=1`.
56
+
57
+ For prose-only changes, verify source claims, links, examples, and diff hygiene.
58
+ When changing generated project instructions in `server/src/projectTemplate.ts`,
59
+ also run `npx --no-install vitest run tests/project-template.test.ts`.
60
+
61
+ ## Report useful evidence
62
+
63
+ A bug report should identify the Cascade version and whether it is a published
64
+ package or local checkout, the host/browser and relevant GPU, the smallest
65
+ reproducing graph, and expected versus observed output. Include safe fixtures
66
+ instead of credentials or private client data. A static check passing is not
67
+ proof that a graph rendered successfully.
68
+
69
+ For visual changes, preserve the inputs, seed, frame/fps, dimensions, and code
70
+ revision used for comparison. Compare decoded pixels or geometry where useful;
71
+ file size and image-wide averages do not establish visual equivalence.
72
+
73
+ ## Documentation and releases
74
+
75
+ Update current instructions alongside behavior changes. Keep historical notes
76
+ dated and mark proposals as unimplemented. Update the root
77
+ [CHANGELOG.md](CHANGELOG.md); `spec/CHANGELOG.md` preserves earlier history.
78
+ Never edit the generated [node reference](doc/NODE_REFERENCE.md) by hand.
79
+
80
+ Release/version rules live in [AGENTS.md](AGENTS.md). Publishing and deployment
81
+ are separate maintainer actions; a documentation update does not publish a release.
82
+
83
+ With an explicit release request, update the README, feature guides, changelog,
84
+ root package/lock version and `site/index.html` together. Run the checks above
85
+ and `CASCADE_TEST_PLAYER=1 CASCADE_TEST_DAWN=1 npm run test:package` on a supported
86
+ GPU machine before publishing. The packed test checks a fresh consumer, browser
87
+ embeds, native GPU output and the optional-renderer-absent path.
88
+
89
+ The public package is `@field/cascade` (`npm publish --access public`). Check
90
+ `npm whoami` and `npm view @field/cascade dist-tags` first; verify the published
91
+ version and a fresh installation afterward. Git push, npm publication and the
92
+ website deployment are separate operations, not an automatic release pipeline.
93
+
94
+ The documentation website is the static **`site/` directory**, not Studio's
95
+ `dist/`. Its existing Vercel project is `field-io/cascade`:
96
+
97
+ ```sh
98
+ vercel link --cwd site --project cascade --scope field-io --yes
99
+ vercel deploy --cwd site --scope field-io --prod --yes
100
+ ```
101
+
102
+ Confirm the linked project before deployment and check `https://cascade.field.io`
103
+ afterward. Do not deploy the repository root or expose a Studio server as the
104
+ public site. `.vercel` is local deployment metadata and stays ignored.
package/DESIGN.md CHANGED
@@ -3,9 +3,11 @@
3
3
  ## Source of truth
4
4
 
5
5
  - Status: Active
6
- - Last refreshed: 2026-09-08 (0.3.0)
7
- - Primary product surfaces: reusable graph runtime, optional Studio workbench, headless Node/browser hosts, Inspector, Viewer, Timeline, agent console, node ports, project-defined workbenches
8
- - Evidence reviewed: `VISION.md`, `ARCHITECTURE.md`, `CHANGELOG.md`, `spec/CASCADE_SUBNET_AND_SHELL_SPEC.md`, `src/types/coreTypes.ts`, `src/editor/Inspector.svelte`, `src/editor/Viewer.svelte`, `src/editor/panels/TimelinePanel.svelte`, `src/editor/panels/AgentPanel.svelte`, `src/editor/components/PortEditor.svelte`, `src/editor/components/typeRenderers.ts`, `packages/runtime/src/expressions/`, `packages/runtime/src/animation/`, `server/src/agent/`, and the approved plans under `.omx/plans/`
6
+ - Last refreshed: 2026-09-09 (0.4.0 checkout; player work is unreleased)
7
+ - Primary product surfaces: reusable graph runtime, optional Studio workbench, headless Node/browser hosts, static browser player, Inspector, 2D/3D Viewer, Timeline, agent console, node ports, project-defined workbenches
8
+ - Evidence reviewed: `VISION.md`, `ARCHITECTURE.md`, `CHANGELOG.md`, `spec/CASCADE_SUBNET_AND_SHELL_SPEC.md`, `src/types/coreTypes.ts`, `src/editor/Inspector.svelte`, `src/editor/Viewer.svelte`, `src/editor/panels/TimelinePanel.svelte`, `src/editor/panels/AgentPanel.svelte`, `src/editor/components/PortEditor.svelte`, `src/editor/components/typeRenderers.ts`, `src/browser/gpu.ts`, `src/player/`, `packages/runtime/src/runtime.ts`, `packages/runtime/src/params/`, `packages/runtime/src/expressions/`, `packages/runtime/src/animation/`, `server/src/agent/`, `server/src/security.ts`, and `server/src/cliCommands.ts`
9
+
10
+ This document contains both current product rules and intended direction. Sections labelled **Current** describe implemented behavior in the repository. Sections labelled **Target** or **Planned** describe design direction and are not a release commitment. Open questions remain undecided until accepted in a specification or implementation plan.
9
11
 
10
12
  ## Brand
11
13
 
@@ -29,22 +31,23 @@
29
31
 
30
32
  - Primary navigation: canvas selection determines Inspector and Viewer context
31
33
  - Core screens: Graph, Inspector, Viewer, Timeline, Definition, Agent console, Logs/diagnostics
34
+ - The standalone player presents the artwork and minimal playback/error controls, not the graph editor. It launches as a static page or embeds in an iframe. Programmatic controls are same-origin; a cross-origin iframe is display/playback only.
32
35
  - Content hierarchy: value preview first, type and shape metadata second, expandable raw structure last
33
36
 
34
37
  ## Design principles
35
38
 
36
39
  - One type, one presentation contract: the same type vocabulary drives ports, Inspector, and Viewer.
37
40
  - Progressive disclosure: compact summaries in dense panels; richer previews and metadata in Viewer; raw JSON only on demand.
38
- - Edit only what can be authored honestly: inputs may edit portable values; connected inputs and outputs are read-only; live GPU textures are inspected, not fabricated through form fields.
39
- - Expensive context changes stay explicit: texture readback, server materialization, and file writes are actions or nodes, never invisible UI coercions.
41
+ - Edit only what can be authored honestly: inputs may edit portable values; connected inputs and outputs are read-only. Future live GPU texture values should be inspected rather than fabricated through form fields.
42
+ - Expensive context changes stay explicit: server materialization, file writes and GPU readback are requested operations, never invisible UI coercions. Graph texture connections remain future work.
40
43
  - Project types extend by registration, not central switch statements.
41
44
  - The graph runtime is a product surface independent from Studio. Headless hosts consume it now; Studio's compatibility graph has one scheduler/controller boundary but still requires a deliberate built-in and structural-command migration before it consumes the neutral runtime directly.
42
45
  - Node metadata is deterministic. A literal exported definition declares ports, properties, types, execution locus, and capabilities; `execute` performs computation only.
43
- - A parameter is one store with three bindings. A value, an expression, and a keyframe channel live on the same parameter and resolve in one place in a fixed order: channel, then expression, then value. Two stores is what 0.3.0 removed — `param()` wrote to one and every binding read the other, so no parameter a sketch actually declared could carry an expression or a key, and nothing errored. A stronger binding hides a weaker one rather than destroying it, so emptying a channel returns the expression that was already there.
46
+ - A parameter is one store with three bindings. A value, an expression, and a keyframe channel live on the same parameter and use the shared `resolvePropBinding` rule in a fixed order: channel, then expression, then value. Studio calls that rule from `Node.evalParm`; the neutral runtime calls it through `PropAnimator`. Two stores is what 0.3.0 removed — `param()` wrote to one and every binding read the other, so no parameter a sketch actually declared could carry an expression or a key, and nothing errored. A stronger binding hides a weaker one rather than destroying it, so emptying a channel returns the expression that was already there.
44
47
  - Time is an expression, not a node. A parameter holding `sin($T) * 40` is the whole of an oscillator, which is why there is no oscillator node and why portable nodes still must not read ambient time or randomness themselves. The variables and the function names are Houdini's, because the people this is for already have them in their hands; the one deliberate divergence is that bare trigonometry is in radians, with `sind`/`cosd`/`tand` provided for formulae carried across.
45
48
  - An agent run belongs to the server, not to the browser looking at it. Closing a tab detaches a reader; the transcript is buffered with sequence numbers so reopening replays what was missed and says how much it dropped. The alternative — a run owned by an HTTP request — kills the agent mid-edit on a reload, which is what 0.3.0 fixed.
46
49
  - Rendering offline stops at a numbered image sequence. Handing frames to an encoder is a separate decision with its own dependency, and a directory of frames is the input every encoder already takes.
47
- - Hosts provide explicit capabilities. File, Python, media, WebGL, and shell access are never ambient runtime assumptions. Provider-specific AI abstractions belong to projects or embedding hosts, not Cascade core.
50
+ - Hosts provide explicit capabilities. File, Python, media, GPU, and shell access are never ambient runtime assumptions. Provider-specific AI abstractions belong to projects or embedding hosts, not Cascade core.
48
51
  - Neutral-runtime graph loads are atomic. Compatibility Studio collapse/extract are a known migration gap and must move behind transactional structural commands before that guarantee applies to every editor operation.
49
52
  - Tradeoff: geometry editors favor transparent structured editing and previews over specialized CAD interactions in this pass.
50
53
 
@@ -53,9 +56,10 @@
53
56
  - `@cascade/contracts` is the dependency-free source of truth for graph documents, core and namespaced types, deterministic node definitions, diagnostics, run results, capabilities, and schemas.
54
57
  - `@cascade/runtime` is the deterministic environment-neutral graph loader, validator, scheduler, serializer, trigger engine, and hierarchy implementation. It depends only on contracts; dynamic compatibility remains in Studio/CLI during migration.
55
58
  - The root `cascade` package is the sole published distribution and CLI owner. It exposes `cascade/contracts`, `cascade/contracts/schema`, `cascade/runtime`, `cascade/runtime/node`, `cascade/runtime/browser`, `cascade/runtime/expressions`, `cascade/runtime/animation`, `cascade/runtime/definition/extract`, `cascade/io`, `cascade/net`, `cascade/stage`, and the compatibility `cascade/shell` entry point.
56
- - Node and browser hosts inject only the capabilities they support. Browser-only WebGL and server-only file, Python, and shell capabilities make portability constraints explicit before execution.
59
+ - Node and browser hosts inject only the capabilities they support. GPU can be supplied by browser WebGPU or optional Dawn; file, Python and shell remain server-only. A portable declaration still requires compatible capabilities.
57
60
  - The Studio owns canvas/view classes and a single `StudioGraphController`; its compatibility `Graph`/`Node` engine is still being reduced. Custom frontends and backend services use the neutral runtime directly and do not load editor code.
58
- - **Web technology is the default renderer, and Python is the exception.** Canvas 2D, WebGL and WebGPU first; reach for a Python stage only for work that genuinely cannot be pushed to the browser — exotic ML libraries and the like. Marcus's ruling, 2026-09-07: *"Cascade should prefer web tech canvas/webgpu to keep things smooth and fast. only use Python for exotic ML libraries and similar things that can't be easily pushed to the browser."* The reason is interaction rather than taste: a Python stage costs a process spawn and a round trip per cook, which is invisible on one still frame and fatal to dragging a parameter or playing an animation. It also tends to be more faithful, not less — a gradient drawn with `createRadialGradient` is the same primitive the source artwork carries, where a per-pixel reimplementation is a guess about what that primitive means.
61
+ - **Current GPU stage:** Studio and the optional Dawn CLI host share device/cache lifecycle through the neutral runtime. Each declaring node gets a cache namespace. Explicit RGBA8 readback supports image export in either host; graph ports still exchange images. GPU-resident intermediate connections remain a later stage.
62
+ - **Web technology is the default renderer, and Python is the exception.** Canvas 2D, WebGL and WebGPU first; reach for a Python stage for libraries or tools that cannot reasonably run in the browser. Marcus's ruling, 2026-09-07: *"Cascade should prefer web tech canvas/webgpu to keep things smooth and fast. only use Python for exotic ML libraries and similar things that can't be easily pushed to the browser."* The reason is interaction: process startup, transport, and serialization can dominate a cook. Persistent workers avoid repeated process/model startup, but still have transfer costs. Existing project Python renderers need deliberate parity-tested migrations; this direction does not mean those implementations are already gone.
59
63
  - Python interoperability remains a host capability for exotic libraries and compute stages. Exchange values cross explicit typed node boundaries rather than leaking Python process details into the neutral runtime.
60
64
  - Internal packages remain two workspaces until independent versioning or external consumption justifies separate publication. More npm packages are not a goal by themselves.
61
65
 
@@ -72,9 +76,11 @@
72
76
 
73
77
  ## Headless and deployment model
74
78
 
75
- - `createRuntime()` is the common entry point for Studio, Node services, UI-free browser embeds, tests, and custom web frontends.
79
+ - `createRuntime()` is the common entry point for deterministic Node services, UI-free browser embeds, tests, and custom frontends. Studio still runs through its compatibility `Graph`/`Node` engine and controller while that migration continues.
76
80
  - Registration is sealed after the first graph load. A loaded graph supports inspect, input/property/preset mutation, trigger, run, cancel, subscription, output retrieval, and disposal without editor dependencies.
81
+ - A loaded deterministic graph owns an explicit caller-controlled clock. `setFrame()` and `setFps()` re-resolve animated props for inspection without cooking; `run({ frame, fps })` resolves the same bindings before execution. The runtime never reads ambient time.
77
82
  - One run is active per graph; there is no hidden run queue. API misuse rejects, while graph execution resolves to an explicit success/failure/cancelled result.
83
+ - Browser-player playback coalesces requested frames; it must not queue unbounded work. Failure pauses playback and exposes its diagnostic. Static assets and generated images are realm-owned; immutable image references preserve Feedback history, and explicit resource limits prevent unbounded retention.
78
84
  - A graph may run wholly in a backend, wholly in a compatible browser, or across an explicitly designed bridge. The runtime never silently moves a stage between hosts.
79
85
  - File loading/saving, format versioning, presets, project paths, and workspace conveniences belong to stable platform services around the neutral runtime, not to individual generative algorithms.
80
86
 
@@ -82,7 +88,7 @@
82
88
 
83
89
  - User node modules are trusted project code, not a sandbox. Deterministic definitions and architecture checks prevent common hidden-state designs and improve inspection, tooling, and portability; hard isolation would additionally require a separate realm or worker per node instance.
84
90
  - Shell is a server-only capability backed by one project-scoped service. Projects invoke configured aliases as a fixed executable plus argument array with `shell: false`; arbitrary executables, interpolation, unsafe working directories, dangerous request-time environment overrides, and unbounded output are rejected. The subprocess inherits the server environment before project and allowlisted request overrides are applied.
85
- - Browser shell transport is loopback-only, uses exact Host and Origin checks plus a process-lifetime random capability token, has route-local request limits, and never logs tokens, paths, arguments, environment, stdin, stdout, or stderr.
91
+ - Sensitive browser transport is enabled for loopback and for an explicitly configured exact trusted host. Every request passes exact Host validation and Origin validation when present; sensitive routes also require a process-lifetime random capability token, apply route-local request limits, and avoid logging tokens, paths, arguments, environment, stdin, stdout, or stderr. Remote Studio rejects wildcard binds and grants every peer that can reach the trusted private interface the same project access.
86
92
  - Timeout, cancellation, and output limits terminate the full process tree and wait for closure before reporting completion.
87
93
 
88
94
  ## Agent workflow contract
@@ -102,12 +108,14 @@
102
108
 
103
109
  ## Components
104
110
 
105
- - Existing components to reuse: `PortEditor`, `JsonTree`, `ColorPicker`, Viewer image zoom/pan behavior, type renderer registry
106
- - New/changed components: shared `TypeValue` presentation shell, structured JSON editor, image/texture inspector, geometry summary/preview, asset inspector, Viewer output list
111
+ - **Current:** `PortEditor`, `JsonTree`, `ColorPicker`, `CoreValue`, `StructuredValue`, Viewer image zoom/pan, geometry summaries/previews, `SceneViewport` with orbit/track/dolly camera controls, and the type renderer registry. Scene rendering currently shows wireframes and points; lights are represented but do not imply shaded rendering.
112
+ - **Planned:** a shared type-value presentation shell, structured JSON editing, richer image/asset inspection, a Viewer output list, and texture inspection after texture values exist.
107
113
  - Variants and states: `compact`, `inspect`, `view`; editable/read-only; empty/loading/error/stale; connected source; truncated/expanded
108
114
  - Token/component ownership: `coreTypes.ts` owns semantic type metadata; the presentation registry owns components; Inspector/Viewer only choose context and mode
109
115
 
110
- ### Core type presentation contract
116
+ ### Target core type presentation contract
117
+
118
+ This table defines the intended presentation contract. Individual rows may be only partially implemented; it does not imply that texture ports or every specialized editor currently exists.
111
119
 
112
120
  | Family | Inspector/editor | Viewer |
113
121
  | --- | --- | --- |
@@ -135,6 +143,7 @@
135
143
  - Supported breakpoints/devices: desktop-first; Inspector remains usable from 240px width; Viewer adapts to Dockview panel size
136
144
  - Layout adaptations: vector/matrix fields wrap or scroll; Viewer metadata collapses beneath previews; structured trees virtualize or truncate large collections
137
145
  - Touch/hover differences: no essential information exists only in hover tooltips
146
+ - Player embeds fit their container; resize changes the view size, not authored graph resolution. Start paused unless autoplay is requested. Controls need native keyboard semantics and errors remain readable over the artwork.
138
147
 
139
148
  ## Interaction states
140
149
 
@@ -161,6 +170,6 @@
161
170
 
162
171
  ## Open questions
163
172
 
164
- - [ ] Whether mesh Viewer should gain an interactive WebGL orbit view after the lightweight projected preview proves useful / product / medium impact
173
+ - [ ] Whether scene rendering needs shaded GPU surfaces beyond the current CPU wireframe/point view / product / medium impact
165
174
  - [ ] Whether project packages can eventually ship Svelte renderers directly rather than app-side registration / architecture / high impact
166
175
  - [ ] Whether large structured values need virtualization beyond bounded initial expansion / performance / medium impact