@field/cascade 0.3.0 → 0.4.0

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 (75) hide show
  1. package/AGENTS.md +14 -9
  2. package/ARCHITECTURE.md +22 -6
  3. package/CHANGELOG.md +69 -1
  4. package/CONTRIBUTING.md +71 -0
  5. package/DESIGN.md +19 -13
  6. package/README.md +42 -11
  7. package/dist/assets/{CodeEditor-BADFbTJS.js → CodeEditor-BNOJIDzL.js} +4 -4
  8. package/dist/assets/{CodePanel-faK6PRfz.js → CodePanel-2wp2G0Fj.js} +2 -2
  9. package/dist/assets/{CustomNodeDialog-DhlKuviy.js → CustomNodeDialog-DNqaVBqA.js} +1 -1
  10. package/dist/assets/{ProjectSettings-D6a6kjqR.js → ProjectSettings-DcdYF2E1.js} +1 -1
  11. package/dist/assets/{SettingsDialog-DJZdIvLC.js → SettingsDialog-D2xVvyiR.js} +1 -1
  12. package/dist/assets/{VersionHistoryDialog-C1X3HOhc.js → VersionHistoryDialog-DW288ykF.js} +1 -1
  13. package/dist/assets/{core-CiuiuWZi.js → core-B1y38i95.js} +1 -1
  14. package/dist/assets/{cssMode-D-NwZSMJ.js → cssMode-BLucnaln.js} +1 -1
  15. package/dist/assets/{editor.api-DT3WEvBd.js → editor.api-B3Et3Pph.js} +1 -1
  16. package/dist/assets/{freemarker2-eKNYQaiz.js → freemarker2-DVlPoano.js} +1 -1
  17. package/dist/assets/geo-DhyFdBXX.js +1 -0
  18. package/dist/assets/{handlebars-C2w1ggK2.js → handlebars-B5FZBAMR.js} +1 -1
  19. package/dist/assets/{html-DQb41jyo.js → html-FodD8KbR.js} +1 -1
  20. package/dist/assets/{htmlMode-IhNlh6Lv.js → htmlMode-CsG57VCD.js} +1 -1
  21. package/dist/assets/{image-DMCXBY-_.js → image-B3F-nq25.js} +1 -1
  22. package/dist/assets/index-CC6YQw2n.js +212 -0
  23. package/dist/assets/index-Y2ock1cw.css +1 -0
  24. package/dist/assets/{javascript-BIT6jMLC.js → javascript-B3gonF_H.js} +1 -1
  25. package/dist/assets/{jsonMode-CNfyB1ro.js → jsonMode-Y3w1ahZg.js} +1 -1
  26. package/dist/assets/{liquid-CmSmJmOG.js → liquid-CTpWXIYO.js} +1 -1
  27. package/dist/assets/{lspLanguageFeatures-BqMm3uMP.js → lspLanguageFeatures-CODBdKEZ.js} +1 -1
  28. package/dist/assets/{mdx-6r6YgOFw.js → mdx-CDAQJZIz.js} +1 -1
  29. package/dist/assets/{python-x1H0TQuI.js → python-LOIlxJU-.js} +1 -1
  30. package/dist/assets/{razor-Dzl1vZFm.js → razor-CllPQSHo.js} +1 -1
  31. package/dist/assets/{tsMode-n6DMMe3a.js → tsMode-CO28ut8t.js} +1 -1
  32. package/dist/assets/{typescript-ziEz65xN.js → typescript-ruU9wKQ_.js} +1 -1
  33. package/dist/assets/{workers-D-qUdp-r.js → workers-Bc1Ywp4-.js} +1 -1
  34. package/dist/assets/{xml-DMZjt5lE.js → xml-DoXP2Dh1.js} +1 -1
  35. package/dist/assets/{yaml-DFe5qZSO.js → yaml-D9YPyGiJ.js} +1 -1
  36. package/dist/cli/index.js +1240 -158
  37. package/dist/cli/runtime/gpu.ts +147 -0
  38. package/dist/contracts/camera.d.ts +70 -0
  39. package/dist/contracts/camera.js +27 -0
  40. package/dist/contracts/capabilities.d.ts +69 -6
  41. package/dist/contracts/definition.d.ts +61 -2
  42. package/dist/contracts/index.d.ts +2 -0
  43. package/dist/contracts/index.js +2 -0
  44. package/dist/contracts/schema.js +33 -7
  45. package/dist/contracts/series.d.ts +75 -0
  46. package/dist/contracts/series.js +2 -0
  47. package/dist/contracts/validate.js +29 -4
  48. package/dist/contracts/values.d.ts +3 -2
  49. package/dist/contracts/values.js +1 -0
  50. package/dist/gpu.d.ts +88 -0
  51. package/dist/gpu.js +113 -0
  52. package/dist/index.html +2 -2
  53. package/dist/runtime/builtins/core/camera.d.ts +252 -0
  54. package/dist/runtime/builtins/core/camera.js +149 -0
  55. package/dist/runtime/builtins/core/index.d.ts +2 -1
  56. package/dist/runtime/builtins/core/index.js +3 -1
  57. package/dist/runtime/camera/index.d.ts +60 -0
  58. package/dist/runtime/camera/index.js +234 -0
  59. package/dist/runtime/definition/architecture.js +36 -1
  60. package/dist/runtime/gpu.d.ts +33 -0
  61. package/dist/runtime/gpu.js +218 -0
  62. package/dist/runtime/index.d.ts +3 -0
  63. package/dist/runtime/index.js +3 -0
  64. package/dist/runtime/runtime.d.ts +23 -3
  65. package/dist/runtime/runtime.js +181 -30
  66. package/dist/runtime/series/index.d.ts +41 -0
  67. package/dist/runtime/series/index.js +167 -0
  68. package/dist/runtime/types.d.ts +3 -3
  69. package/doc/HEADLESS_GPU.md +160 -0
  70. package/doc/NODE_REFERENCE.md +36 -0
  71. package/doc/PROJECT_AUTHORING.md +106 -20
  72. package/package.json +14 -2
  73. package/dist/assets/geo-DUvVbLnx.js +0 -1
  74. package/dist/assets/index-BDV5xGBZ.css +0 -1
  75. package/dist/assets/index-HTCN44kj.js +0 -212
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
 
@@ -73,7 +73,7 @@ Project panels are trusted Studio extensions, not graph/runtime modules. Put the
73
73
 
74
74
  ## Create a deterministic node
75
75
 
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.
76
+ 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
77
 
78
78
  A definition-v1 module looks like this:
79
79
 
@@ -107,6 +107,9 @@ Definition rules:
107
107
  and have the host registration select the executor. Never expose execution
108
108
  location as an artist parameter; parity-test the shared contract.
109
109
  - Declare every capability used. File, Python, and shell access are server-only; WebGL is browser-only.
110
+ - `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.
111
+ - 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.
112
+ - 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
113
  - 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
114
  - 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
115
  - 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 +127,7 @@ Use the runtime-native core vocabulary before creating a project wrapper:
124
127
  - `cascade.core.Null` passes any value through unchanged so downstream wiring can remain stable while upstream branches are reorganized.
125
128
  - `cascade.core.Random` maps explicit integer `seed` and `sample` inputs to a stable float in `[0, 1)`.
126
129
  - `cascade.core.Remap` maps scalar ranges and optionally clamps via its `clamp` prop.
130
+ - `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
131
 
128
132
  The geometry set is reserved the same way, under `cascade.geo.*`:
129
133
  `Rectangle`, `Circle`, `Transform`, `Merge`, `CopyToPoints`, and `SvgExport`.
@@ -146,13 +150,13 @@ type system knows what a `vec2` is; nothing tells it that `offset_x` and
146
150
 
147
151
  ## Animation, expressions, and parameters
148
152
 
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.
153
+ - **`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
154
  - **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
155
  - **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
156
  - **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
157
  - 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.
158
+ - 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.
159
+ - 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
160
 
157
161
  ## Agent sessions
158
162
 
@@ -178,7 +182,7 @@ type system knows what a `vec2` is; nothing tells it that `offset_x` and
178
182
  - Contracts have no runtime dependencies.
179
183
  - Runtime depends only on contracts and contains no DOM, Svelte, Express, Node filesystem, or child-process imports.
180
184
  - Hosts inject capabilities explicitly.
181
- - Studio consumes runtime through its controller; custom frontends consume runtime directly.
185
+ - 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
186
  - User modules are trusted project code, not a sandbox. Static definitions improve tooling and portability, not isolation.
183
187
  - Keep legacy support inside the existing Studio/CLI compatibility engine; do not spread compatibility branches into the deterministic runtime.
184
188
 
@@ -198,9 +202,10 @@ Do not add dependencies without a concrete need. Do not create extra packages un
198
202
 
199
203
  ## Versioning
200
204
 
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
205
+ Cascade `0.2.0` is the 2026 architecture rework; `0.3.0` added animation and the
206
+ agent console. Read `package.json` for the checkout version and `CHANGELOG.md`
207
+ for release history and unreleased changes; a local build can contain changes
208
+ not yet in the published package. Update the changelog before a release commit. Increment the
204
209
  root package and CLI patch version for every committed feature or release
205
210
  change, keeping `package.json`, the lockfile, and CLI output aligned. A minor
206
211
  bump is for a feature large enough to need its own `CHANGELOG.md` section.
package/ARCHITECTURE.md CHANGED
@@ -30,8 +30,8 @@ Randomness is a pure function of an authored seed, never ambient process state.
30
30
 
31
31
  Hosts adapt the neutral runtime to an environment:
32
32
 
33
- - Node: files, assets, media, Python, and shell.
34
- - Browser: assets, media, and WebGL.
33
+ - Node: files, assets, media, Python, shell, and optional Dawn WebGPU in the CLI.
34
+ - Browser: assets, media, and the `gpu` capability when WebGPU is available.
35
35
  - Mixed application: an explicit bridge for serializable server stages.
36
36
 
37
37
  Capabilities are injected. A node’s literal `runsOn` and `capabilities` fields are checked before its `execute` module is loaded.
@@ -44,11 +44,19 @@ resize, composite, and encode when both Canvas/WebGL and native implementations
44
44
  exist. Both executors must obey the same definition and should share golden
45
45
  parity tests for geometry, metadata, and edge cases.
46
46
 
47
+ `packages/runtime/src/gpu.ts` owns shared device/cache lifecycle with an injected
48
+ acquisition function. Studio acquires browser WebGPU; `src/cli/headlessGpu.ts`
49
+ loads optional Dawn lazily. The runtime awaits readiness and supplies a per-node
50
+ view; the application owns disposal. `cascade/gpu` supplies explicit RGBA8
51
+ readback without encoding or colour conversion. Graph ports still exchange
52
+ images; GPU-resident intermediate connections remain future work. See
53
+ [headless GPU rendering](doc/HEADLESS_GPU.md).
54
+
47
55
  `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
56
 
49
57
  ## Applications and controllers
50
58
 
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.
59
+ 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
60
 
53
61
  Studio uses Dockview through the public `dockview` API. Code panels lazy-load
54
62
  Monaco and its native editor/TypeScript workers rather than adding Monaco to the
@@ -115,13 +123,13 @@ Execution failures resolve to a failed `RunResult`; API misuse and invalid prefl
115
123
 
116
124
  ## Animation
117
125
 
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.
126
+ 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
127
 
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.
128
+ 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
129
 
122
130
  `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
131
 
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.
132
+ 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
133
 
126
134
  ## Agent sessions
127
135
 
@@ -139,6 +147,14 @@ Document freshness is a watcher, not a poll of the agent. `server/src/graphWatch
139
147
 
140
148
  Project node modules are trusted code. Capabilities describe support and portability; they are not a sandbox.
141
149
 
150
+ Studio binds to loopback by default. Remote access requires a specific
151
+ hostname or private interface address via `--host`; wildcard remote binds are
152
+ rejected. That non-loopback host becomes the default trusted browser hostname,
153
+ and repeatable `--trusted-host` values add exact browser authorities when the
154
+ bind address and public hostname differ, including a reverse proxy to a
155
+ loopback bind. Every reachable peer on that trusted interface can access the
156
+ project APIs, so this mode is intended for an authenticated VPN or trusted LAN.
157
+
142
158
  All project HTTP APIs require an exact allowed Host. Origin is validated when
143
159
  present and hostile or null Origins are rejected; same-origin GETs may omit it.
144
160
  Filesystem resolution checks lexical paths and canonical existing targets or
package/CHANGELOG.md CHANGED
@@ -2,7 +2,22 @@
2
2
 
3
3
  Notable changes to Cascade. Newest first.
4
4
 
5
- ## Unreleased
5
+ ## 0.4.0 — 2026-09-09
6
+
7
+ ### Documentation
8
+
9
+ - Updated current guides and generated project instructions for definition-v1
10
+ animation, stored `props`, instance identity, vector metadata, and the shared
11
+ GPU capability. Clarified host requirements, Studio's remaining runtime
12
+ migration, export limitations, and the distinction between implemented
13
+ workflows and future product directions.
14
+
15
+ ### Animation
16
+
17
+ - The deterministic runtime resolves expressions and keyframe channels at an
18
+ explicit frame through the shared parameter resolver. `cascade run --frames`
19
+ can render fully definition-v1 graphs with compatible Node-host capabilities;
20
+ mixed definition-v1/dynamic graphs remain unsupported by the CLI.
6
21
 
7
22
  ### Node authoring
8
23
 
@@ -12,6 +27,8 @@ Notable changes to Cascade. Newest first.
12
27
 
13
28
  ### Authoring, continued
14
29
 
30
+ - **A prop can declare a default expression**, so a node arrives already moving — `sine-oscillator` and `ripple` shipped a static `0` once converted, where their dynamic versions baked in `$T`. It is a *default*: a document that saved a plain number keeps it and does not start animating on load. Applied once per prop, so a deleted expression is not reinstated when a retarget re-runs setup, and visible in the Inspector rather than a hidden fallback.
31
+
15
32
  - **A vector prop can declare `min`, `max` and `step`.** All six vector types were typed `never` for those three fields, so the standing "one `vec2`, not two floats" convention silently cost the Inspector its clamp and its drag granularity every time it was followed. One range across all components; matrices stay excluded.
16
33
  - **A module with no file is named, with the paths it was looked for.** `prepare()` synthesises a definition from the ports the document saved for any unresolvable module, which keeps legacy nodes loadable and also let a typo validate clean. A warning, because such a node can never run through the deterministic runtime anyway.
17
34
  - **The stray-`params` warning covers inputs as well as props** — the case the conversions produce most, since a parameter another node drives must be an input.
@@ -25,6 +42,57 @@ Notable changes to Cascade. Newest first.
25
42
 
26
43
  - **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.
27
44
 
45
+ ### Camera
46
+
47
+ - **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.
48
+ - `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.
49
+
50
+ ### Series
51
+
52
+ - **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.
53
+ - 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.
54
+
55
+ ### Capabilities
56
+
57
+ - **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.
58
+
59
+ ### Correctness
60
+
61
+ - **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.
62
+ - **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 `{}`.
63
+ - **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.
64
+ - **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.
65
+ - **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.
66
+
67
+ ### Headless GPU
68
+
69
+ - Optional pinned Dawn (`webgpu@0.6.0`) in the CLI, loaded only for GPU execution.
70
+ Browser and Node hosts reuse shared device/cache lifecycle; portable and server
71
+ definitions may declare `gpu`. Browser-only nodes remain browser-only.
72
+ - Explicit `cascade/gpu` RGBA8 texture readback, with padded-row removal and
73
+ cancellation cleanup. Graph texture transport remains outside this stage.
74
+ - `run --frames ... --json` returns an image manifest and adapter metadata;
75
+ `--timeout <ms>` runs a supervised render process for agent/test callers.
76
+ Dedicated opt-in hardware and packed-package gates exercise real GPU output.
77
+ - Documented the decision, local/unreleased status, CLI manifest contract,
78
+ verification evidence and platform limits in [Headless GPU](doc/HEADLESS_GPU.md).
79
+
80
+ ## 0.3.1
81
+
82
+ ### Fixed
83
+
84
+ - **A stored value equal to its default is no longer dropped on save.** A prop declaring a default expression would start animating on reload if you set it *back* to its default: the save filters out any parameter matching its default, so nothing was written and the expression re-applied to a number you had chosen. Shipped in 0.3.0. Diagnosed and fixed by Marcus's Codex session.
85
+
86
+ The lesson is in how it survived three tests. Every proof of "a stored value beats the default expression" used a value obviously *different* from the default — `7` against `2`, `7` against `0`, `0.4` against `0` — because a distant value reads as the stronger test. Only *equal to the default* fails, and the boundary was the case nobody tried. The regression test now saves and reloads, because the fault is in what gets written rather than in what gets read.
87
+
88
+ - **A browser-only node is refused on the run path again.** A change earlier the same day made the static checker's downgrades apply to execution too, so `cascade run` executed a browser node headlessly and failed on an undefined capability instead of reporting that it needs a browser. The run gate is now separate from static classification: only a stranded `params` value is tolerated.
89
+
90
+ - **`cascade run` reports stranded `params` values.** Previously only `cascade check` did, so a run went onto the defaults in silence.
91
+
92
+ ### Added
93
+
94
+ - **A `gpu` capability, stage one of WebGPU support.** One `GPUDevice` per page, shared by every node that declares the capability, with somewhere to keep a compiled pipeline between cooks. No `texture` port yet, so nodes still exchange images and the rendered picture is unchanged — what it removes is each node holding its own device, which is what made two GPU nodes unable to share anything. Design: `PLAN webgpu` in the vault.
95
+
28
96
  ## 0.3.0
29
97
 
30
98
  Two features carry the minor bump: an **animation system** and an **agent console**. Everything else is either a consequence of those or a fault they exposed.
@@ -0,0 +1,71 @@
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
+ - Sketch repositories own creative algorithms, providers, and project panels.
17
+
18
+ Keep provider SDKs and client-specific data in projects. Do not add dependencies
19
+ or packages without a demonstrated need and an agreed scope.
20
+
21
+ ## Develop and verify
22
+
23
+ Use Node.js 22.13 or newer. Install dependencies with `npm install`; the core
24
+ uses TypeScript 6. `npm run dev` starts the Studio development frontend.
25
+ Project-host workflows are exercised through a built CLI and a project folder.
26
+
27
+ Add a focused regression test for a behavior change, make the smallest change
28
+ at the owning layer, and run that test first. Use the applicable repository gates:
29
+
30
+ ```bash
31
+ npm run check
32
+ npm run test:run
33
+ npm --prefix server run build
34
+ npm run build
35
+ npm run build:cli
36
+ git diff --check
37
+ ```
38
+
39
+ `npm run build` also runs `build:cli` through its postbuild hook. Keep a final
40
+ CLI build after any separate Vite build because Vite refreshes `dist/`. Coordinate
41
+ rebuilds when running Studio servers serve from that checkout.
42
+
43
+ For public API or packaging changes, run `npm run test:package`, which exercises
44
+ the packed distribution from a temporary consumer. Built-in node-definition or
45
+ registry changes also require `npm run build:node-reference`; include its result.
46
+
47
+ For prose-only changes, verify source claims, links, examples, and diff hygiene.
48
+ When changing generated project instructions in `server/src/projectTemplate.ts`,
49
+ also run `npx --no-install vitest run tests/project-template.test.ts`.
50
+
51
+ ## Report useful evidence
52
+
53
+ A bug report should identify the Cascade version and whether it is a published
54
+ package or local checkout, the host/browser and relevant GPU, the smallest
55
+ reproducing graph, and expected versus observed output. Include safe fixtures
56
+ instead of credentials or private client data. A static check passing is not
57
+ proof that a graph rendered successfully.
58
+
59
+ For visual changes, preserve the inputs, seed, frame/fps, dimensions, and code
60
+ revision used for comparison. Compare decoded pixels or geometry where useful;
61
+ file size and image-wide averages do not establish visual equivalence.
62
+
63
+ ## Documentation and releases
64
+
65
+ Update current instructions alongside behavior changes. Keep historical notes
66
+ dated and mark proposals as unimplemented. Update the root
67
+ [CHANGELOG.md](CHANGELOG.md); `spec/CHANGELOG.md` preserves earlier history.
68
+ Never edit the generated [node reference](doc/NODE_REFERENCE.md) by hand.
69
+
70
+ Release/version rules live in [AGENTS.md](AGENTS.md). Publishing and deployment
71
+ are separate maintainer actions; a documentation update does not publish a release.
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)
6
+ - Last refreshed: 2026-09-08 (0.3.1)
7
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/`
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/nodes/definition/gpuCapability.ts`, `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
 
@@ -35,16 +37,16 @@
35
37
 
36
38
  - One type, one presentation contract: the same type vocabulary drives ports, Inspector, and Viewer.
37
39
  - 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.
40
+ - 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.
41
+ - 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
42
  - Project types extend by registration, not central switch statements.
41
43
  - 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
44
  - 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.
45
+ - 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
46
  - 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
47
  - 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
48
  - 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.
49
+ - 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
50
  - 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
51
  - Tradeoff: geometry editors favor transparent structured editing and previews over specialized CAD interactions in this pass.
50
52
 
@@ -53,9 +55,10 @@
53
55
  - `@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
56
  - `@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
57
  - 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.
58
+ - 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
59
  - 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.
60
+ - **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.
61
+ - **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
62
  - 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
63
  - Internal packages remain two workspaces until independent versioning or external consumption justifies separate publication. More npm packages are not a goal by themselves.
61
64
 
@@ -72,8 +75,9 @@
72
75
 
73
76
  ## Headless and deployment model
74
77
 
75
- - `createRuntime()` is the common entry point for Studio, Node services, UI-free browser embeds, tests, and custom web frontends.
78
+ - `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
79
  - 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.
80
+ - 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
81
  - 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.
78
82
  - 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
83
  - 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.
@@ -82,7 +86,7 @@
82
86
 
83
87
  - 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
88
  - 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.
89
+ - 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
90
  - Timeout, cancellation, and output limits terminate the full process tree and wait for closure before reporting completion.
87
91
 
88
92
  ## Agent workflow contract
@@ -102,12 +106,14 @@
102
106
 
103
107
  ## Components
104
108
 
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
109
+ - **Current:** `PortEditor`, `JsonTree`, `ColorPicker`, `CoreValue`, `StructuredValue`, Viewer image zoom/pan behavior, and the type renderer registry.
110
+ - **Planned:** a shared type-value presentation shell, structured JSON editing, richer image and asset inspection, geometry summaries/previews, a Viewer output list, and texture inspection after texture values exist.
107
111
  - Variants and states: `compact`, `inspect`, `view`; editable/read-only; empty/loading/error/stale; connected source; truncated/expanded
108
112
  - Token/component ownership: `coreTypes.ts` owns semantic type metadata; the presentation registry owns components; Inspector/Viewer only choose context and mode
109
113
 
110
- ### Core type presentation contract
114
+ ### Target core type presentation contract
115
+
116
+ 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
117
 
112
118
  | Family | Inspector/editor | Viewer |
113
119
  | --- | --- | --- |
package/README.md CHANGED
@@ -8,14 +8,15 @@ Created by Marcus Wendt at [FIELD.IO](https://www.field.io).
8
8
 
9
9
  - A typed, inspectable graph model with lazy execution and explicit triggers.
10
10
  - Deterministic custom-node definitions that tools can inspect without running user code.
11
- - The same runtime in Studio, a Node service, or a UI-free browser application.
11
+ - An environment-neutral runtime for Node services and UI-free browser applications.
12
+ - A Studio compatibility controller that already presents deterministic definitions alongside dynamic project nodes while its graph engine migrates to the neutral runtime.
12
13
  - Project-native `.cascade` files, assets, presets, and Git-backed version history.
13
14
  - Nested subnets with persistent hierarchy.
14
15
  - Expressions on parameters, with Houdini's variables and functions: `$F`, `$FF`, `$T`, `$FPS`, and `ch()` to read another parameter.
15
16
  - Keyframe channels on parameters, edited through a timeline panel with transport, playhead, scrubbing, and a dope sheet.
16
17
  - Offline rendering with `cascade run`, including `--frames 1-100` for a numbered image sequence, rasterised through Skia rather than a browser.
17
18
  - A coding-agent console per project, running in the project directory, with a watcher that picks up the files it rewrites without a reload.
18
- - Explicit browser and server capabilities for WebGL, files, media, Python, and allowlisted shell commands.
19
+ - Explicit browser and server capabilities for WebGPU, files, media, Python, and allowlisted shell commands.
19
20
  - A Svelte Studio with an infinite canvas, Inspector, Viewer, timeline, and project workbench.
20
21
 
21
22
  Cascade separates the generative algorithm from the platform. Custom nodes describe stages of a pipeline; the runtime schedules and validates them; hosts supply environment-specific capabilities; Studio is only one possible frontend.
@@ -29,7 +30,9 @@ npm install -g @field/cascade
29
30
  cascade --version
30
31
  ```
31
32
 
32
- That installs the `cascade` command: `cascade new` scaffolds a project, `cascade <directory>` opens it in Studio, and `cascade run` renders a graph headlessly.
33
+ That installs the latest published release and the `cascade` command: `cascade new` scaffolds a project, `cascade <directory>` opens it in Studio, and `cascade run` executes a graph headlessly. A generated project records the published package under the local alias `cascade`, so imports such as `cascade/contracts` resolve to `@field/cascade`.
34
+
35
+ The repository checkout can be ahead of the published release, even with the same version number. Use the global install to scaffold projects, then use their npm scripts or `npx --no-install cascade` to select the project-local version. For checkout development, see [Contributing](CONTRIBUTING.md). When diagnosing a difference, record the installed version and whether it resolves to a local checkout; a version match alone does not prove the same code is installed.
33
36
 
34
37
  Offline image rendering uses Skia through `@napi-rs/canvas`, an optional dependency of about 26 MB. It installs by default; if you skipped optional dependencies, add it yourself:
35
38
 
@@ -63,10 +66,15 @@ npm run build:cli
63
66
 
64
67
  ## Create a project
65
68
 
69
+ `cascade new` scaffolds a project and starts Studio. After stopping that first
70
+ server, install the project's dependencies before reopening it. The example
71
+ below assumes the default projects directory; `cascade projects` reports yours.
72
+
66
73
  ```bash
67
74
  cascade new my-artwork
68
75
  cd ~/Documents/Cascade/my-artwork
69
- cascade .
76
+ npm install
77
+ npx --no-install cascade .
70
78
  ```
71
79
 
72
80
  Studio binds to loopback by default. To use a Cascade workstation over a
@@ -81,6 +89,18 @@ both the bind target and allowed browser hostname. Use repeatable
81
89
  `--trusted-host` only when the bind address and browser hostname differ.
82
90
  Wildcard remote binds, unknown options, and invalid ports fail immediately.
83
91
 
92
+ An HTTPS reverse proxy may terminate TLS and forward to a loopback Studio. In
93
+ that case, name both sides explicitly:
94
+
95
+ ```bash
96
+ cascade . --host 127.0.0.1 --port 3030 --trusted-host cascade.example.internal
97
+ ```
98
+
99
+ The proxy must preserve the browser's exact `Host`. If the external URL uses a
100
+ non-default port, include it in `--trusted-host`. Use `--no-open` and open the
101
+ HTTPS URL yourself: automatic opening still uses an HTTP URL. This flag admits
102
+ the authority; it does not configure TLS or the proxy itself.
103
+
84
104
  A project is an ordinary directory or Git repository:
85
105
 
86
106
  ```text
@@ -152,7 +172,7 @@ Frames are written as `<out>/<node id>.<frame>.<ext>`, zero-padded to at least f
152
172
 
153
173
  Drawing offline goes through Skia rather than a browser. The optional `@napi-rs/canvas` supplies `OffscreenCanvas`, `Image`, `Path2D` and the rest as globals in the Node process, deliberately not `document`, since that is how a node detects its host. So a node that draws on an `OffscreenCanvas` needs no separate headless implementation, and the built-in `cascade.image.*` library rasterises through Skia in Node too, so a graph built from it renders headlessly with no browser involved. A run without the renderer installed still works for graphs that draw nothing, and says what is missing if a cook fails in a canvas-shaped way.
154
174
 
155
- `--frames` renders dynamic graphs. A definition-v1 graph runs through the deterministic runtime, which owns its own clock and has no parameter animation, and `cascade run` refuses the flag rather than rendering frame 1 a hundred times.
175
+ `--frames` works for an all-dynamic graph and for an all-definition-v1 graph. Definition-v1 runs resolve stored expressions and keyframe channels from the explicit `frame` and `fps` supplied to each deterministic run. A CLI graph that mixes the two node styles is rejected explicitly because there is not yet a bounded adapter between the execution engines.
156
176
 
157
177
  ## The agent console
158
178
 
@@ -219,7 +239,7 @@ host's executor, so the graph stays portable and contains no backend selector.
219
239
  This is the intended pattern for media transforms such as crop or resize; use
220
240
  shared parity tests to keep their outputs and metadata aligned.
221
241
 
222
- There is a second node style, and it is not deprecated. A **dynamic** module exports `execute(node, graph)` and declares its ports and parameters imperatively inside it, as `node.param('size', 1024, { min: 16, max: 4096 })`, running once for discovery and again on every cook. Studio cooks both styles and a Studio graph may mix them: it dispatches on what a compiled module exports, building a definition-v1 node's ports from its literal and calling `execute` with a real context, and calling a dynamic module as `execute(node, graph)`. `cascade run --frames` renders dynamic graphs, and the deterministic runtime cooks definition-v1 ones, which are what `cascade check` inspects statically. A malformed definition never falls back to dynamic execution — it is reported. A project's own `AGENTS.md`, written by `cascade new`, states which style that project expects.
242
+ There is a second node style, and it is not deprecated. A **dynamic** module exports `execute(node, graph)` and declares its ports and parameters imperatively inside it, as `node.param('size', 1024, { min: 16, max: 4096 })`, running once for discovery and again on every cook. Studio cooks both styles and a Studio graph may mix them through its compatibility controller. The CLI uses the deterministic runtime for an all-definition-v1 document and the compatibility engine for an all-dynamic document; it rejects a mixed document. `cascade check` requires definition-v1 modules because it inspects them statically. A malformed definition never falls back to dynamic execution — it is reported. A project's own `AGENTS.md`, written by `cascade new`, states which style that project expects.
223
243
 
224
244
  Provider integrations are project code, not Cascade infrastructure. A project
225
245
  can call a remote service from a Studio/browser node, invoke Python or an
@@ -262,11 +282,22 @@ cancellation, event subscriptions, output retrieval, and disposal. Hosts
262
282
  decide which capabilities exist; Cascade never silently moves a stage between
263
283
  browser and server.
264
284
 
265
- The same registration path exposes the initial `cascade.geo.*` library in
266
- Studio and headless hosts: `Rectangle`, `Circle`, `Transform`, `Merge`,
267
- `CopyToPoints`, and `SvgExport`. Their definitions, ports, and executors are
268
- owned by the runtime; Studio adapts those definitions instead of maintaining a
269
- second set of node algorithms.
285
+ The same definitions expose the initial `cascade.geo.*` library in Studio and
286
+ headless hosts: `Rectangle`, `Circle`, `Transform`, `Merge`, `CopyToPoints`,
287
+ and `SvgExport`. Their definitions, ports, and executors are runtime-owned;
288
+ Studio adapts them through its compatibility controller instead of maintaining
289
+ a second set of node algorithms.
290
+
291
+ ## Current capability boundaries
292
+
293
+ | Surface | Current status |
294
+ | --- | --- |
295
+ | Studio authoring | Supports dynamic and definition-v1 nodes in one document through the compatibility controller. |
296
+ | Headless CLI | Executes all-definition-v1 or all-dynamic documents; mixed documents are rejected. Both styles can render frame sequences. |
297
+ | Embedded runtime | `cascade/runtime` is the neutral definition-v1 API for Node and browser hosts. It does not load Studio or interpret dynamic nodes. |
298
+ | GPU | Studio and the optional Dawn CLI host provide a shared device, adapter metadata, limits, and per-node caches. Portable GPU nodes render offscreen and explicitly read RGBA8 pixels through `cascade/gpu`; graph ports still carry images. See [headless GPU rendering](doc/HEADLESS_GPU.md). |
299
+ | Standalone HTML export | The existing Studio exporter uses a separate minimal runtime and supports only a subset of graph behavior. Treat it as an experimental convenience, not as a universal deployment artifact. |
300
+ | External services | Project-owned and optional. Cascade itself requires no paid provider or model subscription. |
270
301
 
271
302
  ## Repository map
272
303