@field/cascade 0.8.0 → 0.11.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 (195) hide show
  1. package/AGENTS.md +36 -3
  2. package/CHANGELOG.md +401 -0
  3. package/DESIGN.md +14 -0
  4. package/README.md +41 -26
  5. package/dist/assets/CodeEditor-4O7FQ__R.js +623 -0
  6. package/dist/assets/CodePanel-BU-autmq.js +2 -0
  7. package/dist/assets/{CustomNodeDialog-BQbEhIwL.js → CustomNodeDialog-BRpDfOV5.js} +1 -1
  8. package/dist/assets/OpenGraphDialog-BwbRlC0X.js +1 -0
  9. package/dist/assets/ProjectSettings-DLOXLxcA.js +2 -0
  10. package/dist/assets/SettingsDialog-Bz8JxISH.js +1 -0
  11. package/dist/assets/{VersionHistoryDialog-D6VBzSQ0.js → VersionHistoryDialog-D5Z0nJ5-.js} +2 -2
  12. package/dist/assets/{core-BInLG4gw.js → core-Yqi0Ni61.js} +8 -8
  13. package/dist/assets/{cssMode-DfR2qmYG.js → cssMode-CxUzc4vp.js} +1 -1
  14. package/dist/assets/definitions-GreEMXLV.js +1 -0
  15. package/dist/assets/{editor.api-Ck8_vgQV.js → editor.api-BNFb25CX.js} +1 -1
  16. package/dist/assets/{freemarker2-fVn10Wn3.js → freemarker2-0ZDnWxeM.js} +1 -1
  17. package/dist/assets/geo-u0n_jOsD.js +1 -0
  18. package/dist/assets/{handlebars-BCSchLT2.js → handlebars-Cy18MoaD.js} +1 -1
  19. package/dist/assets/{html-CVpSv_k9.js → html-B-2Dx7nq.js} +1 -1
  20. package/dist/assets/{htmlMode-Da4ESTv0.js → htmlMode-DUAc9B_d.js} +1 -1
  21. package/dist/assets/{image-BLn--oSF.js → image-cAa-Nu9O.js} +3 -3
  22. package/dist/assets/index-5ZtDAuy2.js +220 -0
  23. package/dist/assets/index-7vae6YFC.css +1 -0
  24. package/dist/assets/index-client-DqYmKstU.js +1 -0
  25. package/dist/assets/{javascript-BpX0Gvcf.js → javascript-DeQsDqP5.js} +1 -1
  26. package/dist/assets/{jsonMode-CsLqaou7.js → jsonMode-BiFwJVSk.js} +1 -1
  27. package/dist/assets/legacy-CTEeXeqF.js +2 -0
  28. package/dist/assets/{liquid-efUz51Wf.js → liquid-BLoHH68a.js} +1 -1
  29. package/dist/assets/{lspLanguageFeatures-DCi5-K0n.js → lspLanguageFeatures-CNFgm1Kv.js} +1 -1
  30. package/dist/assets/math-DioIQOPJ.js +1 -0
  31. package/dist/assets/{mdx-DP_sjGVy.js → mdx-CFXQVNfs.js} +1 -1
  32. package/dist/assets/pop-DC_TQG9t.js +1 -0
  33. package/dist/assets/{python-aAuP3LUi.js → python-Cf7S7p2E.js} +1 -1
  34. package/dist/assets/{razor-7M6sMmC5.js → razor-CMHBcG-g.js} +1 -1
  35. package/dist/assets/studioScenes-8sq9FfFg.js +1 -0
  36. package/dist/assets/{tsMode-Bf4CnoYK.js → tsMode-BEih0GDj.js} +1 -1
  37. package/dist/assets/{typescript-ddhYBGyT.js → typescript-COEKYD_a.js} +1 -1
  38. package/dist/assets/{workers-X5la8DDT.js → workers-BNhAhMNn.js} +1 -1
  39. package/dist/assets/{xml-BzbXa3Ps.js → xml-CPiMpnPl.js} +1 -1
  40. package/dist/assets/{yaml-CXs-VzxL.js → yaml-Bgp1ITLR.js} +1 -1
  41. package/dist/cli/Graph-ZJJTRQTM.js +2975 -0
  42. package/dist/cli/chunk-2KXB47FP.js +115 -0
  43. package/dist/cli/chunk-35D343DC.js +1447 -0
  44. package/dist/cli/chunk-36P5K3SD.js +631 -0
  45. package/dist/cli/chunk-3JTJHF7V.js +267 -0
  46. package/dist/cli/chunk-4UDFYF5G.js +132 -0
  47. package/dist/cli/chunk-53NMBJAO.js +35 -0
  48. package/dist/cli/chunk-A4OAMOZH.js +310 -0
  49. package/dist/cli/chunk-BIJO5OFS.js +71 -0
  50. package/dist/cli/chunk-BP7UKF36.js +376 -0
  51. package/dist/cli/chunk-CKS2FQWR.js +89 -0
  52. package/dist/cli/chunk-CO22XHNG.js +593 -0
  53. package/dist/cli/chunk-D6BUOHUG.js +634 -0
  54. package/dist/cli/chunk-DEQSEFFH.js +153 -0
  55. package/dist/cli/chunk-DUIUFVU2.js +241 -0
  56. package/dist/cli/chunk-EUIAC3U3.js +3006 -0
  57. package/dist/cli/chunk-FCDXJ6EK.js +2208 -0
  58. package/dist/cli/chunk-GFS6W3C5.js +308 -0
  59. package/dist/cli/chunk-HFHWYL55.js +139 -0
  60. package/dist/cli/chunk-HSNOBIVT.js +263 -0
  61. package/dist/cli/chunk-ICH7N5PN.js +26 -0
  62. package/dist/cli/chunk-J7VK7MNF.js +418 -0
  63. package/dist/cli/chunk-KH4MUBKF.js +1551 -0
  64. package/dist/cli/chunk-MIIEFUGG.js +623 -0
  65. package/dist/cli/chunk-OWWBYLHC.js +136 -0
  66. package/dist/cli/chunk-POMMNKZZ.js +672 -0
  67. package/dist/cli/chunk-QBBKRNGY.js +90 -0
  68. package/dist/cli/chunk-QQPA2ZHH.js +273 -0
  69. package/dist/cli/chunk-RLCAJBVR.js +224 -0
  70. package/dist/cli/chunk-RQZ4SX5R.js +1125 -0
  71. package/dist/cli/chunk-RUU3YWXU.js +99 -0
  72. package/dist/cli/chunk-RXDIMXN5.js +98 -0
  73. package/dist/cli/chunk-SGJAET2L.js +197 -0
  74. package/dist/cli/chunk-VVGSLVSF.js +151 -0
  75. package/dist/cli/chunk-WD62JIP6.js +118 -0
  76. package/dist/cli/chunk-WIH4TEIS.js +104 -0
  77. package/dist/cli/chunk-WKURDVYP.js +1119 -0
  78. package/dist/cli/chunk-WPUDGEFY.js +20 -0
  79. package/dist/cli/chunk-XWDSKG7N.js +1301 -0
  80. package/dist/cli/chunk-YAT5Y25U.js +121 -0
  81. package/dist/cli/chunk-ZL4JTG5Y.js +37 -0
  82. package/dist/cli/cliCommands-UQSFGEHF.js +3464 -0
  83. package/dist/cli/commands-Q23M26QM.js +1292 -0
  84. package/dist/cli/definitions-HF2FTHYU.js +32 -0
  85. package/dist/cli/doctorCommand-B7BPQMN6.js +76 -0
  86. package/dist/cli/edit-JHCPTQFT.js +28 -0
  87. package/dist/cli/editorCommands-UIF5YLUZ.js +33 -0
  88. package/dist/cli/encode-HAUZTYPT.js +17 -0
  89. package/dist/cli/frames-LSAUBZ7P.js +16 -0
  90. package/dist/cli/geo-4RNK3QVN.js +43 -0
  91. package/dist/cli/graphCommands-6BMAKGQE.js +184 -0
  92. package/dist/cli/graphFile-VPSQ6OF7.js +286 -0
  93. package/dist/cli/headlessCanvas-5XLDZT7M.js +15 -0
  94. package/dist/cli/helpCommand-3VRE3KVO.js +155 -0
  95. package/dist/cli/index.js +106 -14207
  96. package/dist/cli/math-ZRMLKU2D.js +16 -0
  97. package/dist/cli/mcp-ZLEEMYGF.js +164 -0
  98. package/dist/cli/parity-KINARCP2.js +328 -0
  99. package/dist/cli/pop-USDFXB7H.js +39 -0
  100. package/dist/cli/project-K3QIPGBB.js +12 -0
  101. package/dist/cli/projectDefinition-DMTZN2NE.js +27 -0
  102. package/dist/cli/projectRuntime-Z5PJOH47.js +48 -0
  103. package/dist/cli/registerStandardNodes-S2VLMF6J.js +3081 -0
  104. package/dist/cli/render-YURAPPUI.js +436 -0
  105. package/dist/cli/runCommand-PI764LEG.js +198 -0
  106. package/dist/cli/runner-RA6UKEPD.js +37 -0
  107. package/dist/cli/runtime/image.ts +277 -0
  108. package/dist/cli/runtime/stage.ts +74 -11
  109. package/dist/cli/stageRunner-KUNIMQKJ.js +10 -0
  110. package/dist/cli/verbs-RCE3K4VQ.js +19 -0
  111. package/dist/cli/webBuild-GT4PZT5D.js +37 -0
  112. package/dist/contracts/bundle.d.ts +75 -0
  113. package/dist/contracts/bundle.js +112 -0
  114. package/dist/contracts/definition.d.ts +67 -4
  115. package/dist/contracts/document.d.ts +29 -0
  116. package/dist/contracts/documentFormat.d.ts +18 -0
  117. package/dist/contracts/documentFormat.js +195 -0
  118. package/dist/contracts/editor.d.ts +189 -0
  119. package/dist/contracts/editor.js +2 -0
  120. package/dist/contracts/index.d.ts +3 -0
  121. package/dist/contracts/index.js +3 -0
  122. package/dist/contracts/validate.js +59 -3
  123. package/dist/contracts/values.d.ts +3 -3
  124. package/dist/contracts/values.js +1 -0
  125. package/dist/image.d.ts +141 -0
  126. package/dist/image.js +127 -0
  127. package/dist/index.html +4 -4
  128. package/dist/player/app.js +17 -5
  129. package/dist/player/editor.js +1919 -0
  130. package/dist/player/editorEngine.js +477 -0
  131. package/dist/runtime/builtins/core/bundle.d.ts +70 -0
  132. package/dist/runtime/builtins/core/bundle.js +81 -0
  133. package/dist/runtime/builtins/core/index.d.ts +3 -2
  134. package/dist/runtime/builtins/core/index.js +6 -2
  135. package/dist/runtime/builtins/core/routing.d.ts +27 -0
  136. package/dist/runtime/builtins/core/routing.js +28 -0
  137. package/dist/runtime/builtins/headless.d.ts +19 -0
  138. package/dist/runtime/builtins/headless.js +25 -0
  139. package/dist/runtime/builtins/image/contactSheet.d.ts +226 -0
  140. package/dist/runtime/builtins/image/contactSheet.js +199 -0
  141. package/dist/runtime/builtins/image/index.d.ts +9 -0
  142. package/dist/runtime/builtins/image/index.js +9 -0
  143. package/dist/runtime/edit/document.d.ts +94 -0
  144. package/dist/runtime/edit/document.js +194 -0
  145. package/dist/runtime/edit/graphEditor.d.ts +223 -0
  146. package/dist/runtime/edit/graphEditor.js +893 -0
  147. package/dist/runtime/edit/index.d.ts +12 -0
  148. package/dist/runtime/edit/index.js +6 -0
  149. package/dist/runtime/edit/layout.d.ts +50 -0
  150. package/dist/runtime/edit/layout.js +126 -0
  151. package/dist/runtime/edit/operations.d.ts +65 -0
  152. package/dist/runtime/edit/operations.js +57 -0
  153. package/dist/runtime/edit/parameters.d.ts +75 -0
  154. package/dist/runtime/edit/parameters.js +284 -0
  155. package/dist/runtime/edit/read.d.ts +35 -0
  156. package/dist/runtime/edit/read.js +65 -0
  157. package/dist/runtime/editor/index.d.ts +104 -0
  158. package/dist/runtime/editor/index.js +439 -0
  159. package/dist/runtime/expressions/bundlePaths.d.ts +37 -0
  160. package/dist/runtime/expressions/bundlePaths.js +55 -0
  161. package/dist/runtime/expressions/index.d.ts +2 -0
  162. package/dist/runtime/expressions/index.js +1 -0
  163. package/dist/runtime/index.d.ts +2 -0
  164. package/dist/runtime/index.js +2 -0
  165. package/dist/runtime/params/animator.d.ts +5 -0
  166. package/dist/runtime/params/animator.js +16 -0
  167. package/dist/runtime/runtime.js +238 -12
  168. package/dist/runtime/seed.d.ts +29 -0
  169. package/dist/runtime/seed.js +52 -0
  170. package/dist/runtime/types.d.ts +12 -0
  171. package/dist/stage.js +43 -9
  172. package/dist/studio/panel.d.ts +2 -0
  173. package/doc/CLI_REFERENCE.md +171 -0
  174. package/doc/EDITOR_EXPORT.md +235 -0
  175. package/doc/HEADLESS_GPU.md +27 -0
  176. package/doc/MCP.md +69 -0
  177. package/doc/NODE_REFERENCE.md +208 -0
  178. package/doc/PROJECT_AUTHORING.md +258 -1
  179. package/package.json +29 -8
  180. package/dist/assets/CodeEditor-BEk-kIBd.js +0 -623
  181. package/dist/assets/CodePanel-CeSdjXkg.js +0 -2
  182. package/dist/assets/ExportDialog-CjTbbTZJ.js +0 -358
  183. package/dist/assets/ExportDialog-DOq0flMV.css +0 -1
  184. package/dist/assets/OpenGraphDialog-DCwH9itM.js +0 -1
  185. package/dist/assets/ProjectSettings-Dg7M5xt9.js +0 -2
  186. package/dist/assets/SettingsDialog-e7GgsjB9.js +0 -1
  187. package/dist/assets/definitions-DZpOjWKR.js +0 -1
  188. package/dist/assets/geo-D2VPjAdt.js +0 -1
  189. package/dist/assets/index-CMiBdEuT.js +0 -212
  190. package/dist/assets/index-DMIuml9a.css +0 -1
  191. package/dist/assets/index-client-BI2H82FJ.js +0 -1
  192. package/dist/assets/legacy-ZA7textG.js +0 -2
  193. package/dist/assets/math-B6hpxPJO.js +0 -1
  194. package/dist/assets/pop-CYUIjT6x.js +0 -1
  195. package/dist/assets/projectSettingsApi-C1WvIwfP.js +0 -1
@@ -1,4 +1,5 @@
1
1
  import type { CapabilityMap, CascadeAbortSignal, NodeCapabilityName, ProgressReporter } from "./capabilities.js";
2
+ import type { BundleFieldDefinition, BundleFieldDefinitions } from "./bundle.js";
2
3
  import type { CascadeType, CoreType, JsonValue, NamespacedType, SerializableValueForType, ValueForType } from "./values.js";
3
4
  export type RuntimeEnvironment = "portable" | "browser" | "server";
4
5
  export type CapabilityForEnvironment<E extends RuntimeEnvironment> = E extends "portable" ? "assets" | "media" | "gpu" : E extends "browser" ? "assets" | "media" | "gpu" : "files" | "assets" | "media" | "python" | "shell" | "gpu";
@@ -70,6 +71,27 @@ type SelectMetadata<T extends CascadeType> = {
70
71
  readonly control: Extract<ControlFor<T>, "select">;
71
72
  readonly options?: readonly SelectOption<T>[];
72
73
  };
74
+ /**
75
+ * Bundle ports name an optional `schema`, and declare fields from both ends:
76
+ * a producer declares what it carries (`fields: { dpi: "float" }`), a consumer
77
+ * the fields it reads (`fields: ["dpi"]`). A consumer that declares its fields
78
+ * sees only those and, in Studio, re-cooks only when one of them changed. See
79
+ * `bundle.ts`.
80
+ */
81
+ type BundleInputMetadata<T extends CascadeType> = T extends "bundle" ? {
82
+ readonly schema?: string;
83
+ readonly fields?: readonly string[];
84
+ } : {
85
+ readonly schema?: never;
86
+ readonly fields?: never;
87
+ };
88
+ type BundleOutputMetadata<T extends CascadeType> = T extends "bundle" ? {
89
+ readonly schema?: string;
90
+ readonly fields?: BundleFieldDefinitions;
91
+ } : {
92
+ readonly schema?: never;
93
+ readonly fields?: never;
94
+ };
73
95
  export interface TriggerInputDefinition {
74
96
  readonly kind: "trigger";
75
97
  readonly description?: string;
@@ -80,7 +102,7 @@ export type DataInputDefinition<T extends CascadeType> = {
80
102
  readonly default?: SerializableValueForType<T>;
81
103
  readonly description?: string;
82
104
  readonly variadic?: boolean;
83
- } & NumericMetadata<T> & AcceptMetadata<T> & SelectMetadata<T>;
105
+ } & NumericMetadata<T> & AcceptMetadata<T> & SelectMetadata<T> & BundleInputMetadata<T>;
84
106
  export type InputDefinitionFor<E extends RuntimeEnvironment> = TriggerInputDefinition | {
85
107
  [T in DataTypeForEnvironment<E>]: DataInputDefinition<T>;
86
108
  }[DataTypeForEnvironment<E>];
@@ -88,11 +110,11 @@ export interface TriggerOutputDefinition {
88
110
  readonly kind: "trigger";
89
111
  readonly description?: string;
90
112
  }
91
- export interface DataOutputDefinition<T extends CascadeType> {
113
+ export type DataOutputDefinition<T extends CascadeType> = {
92
114
  readonly kind: "data";
93
115
  readonly type: T;
94
116
  readonly description?: string;
95
- }
117
+ } & BundleOutputMetadata<T>;
96
118
  export type OutputDefinitionFor<E extends RuntimeEnvironment> = TriggerOutputDefinition | {
97
119
  [T in DataTypeForEnvironment<E>]: DataOutputDefinition<T>;
98
120
  }[DataTypeForEnvironment<E>];
@@ -168,6 +190,14 @@ export interface NodeDefinitionForEnvironment<E extends RuntimeEnvironment> {
168
190
  */
169
191
  readonly container?: "subnet" | "feedback";
170
192
  readonly capabilities?: readonly CapabilityForEnvironment<E>[];
193
+ /**
194
+ * `live` marks a node that reads data from outside the graph — an archive,
195
+ * a CLI, a cache, body data, the filesystem or a network. `cascade export`
196
+ * never ships one: the author freezes it into a snapshot of chosen values or
197
+ * the export fails. Server nodes and nodes declaring `files`, `python` or
198
+ * `shell` are treated as live whether or not they say so.
199
+ */
200
+ readonly source?: "live";
171
201
  readonly label?: string;
172
202
  readonly description?: string;
173
203
  readonly icon?: string;
@@ -191,11 +221,32 @@ export interface TriggerEvent {
191
221
  }>;
192
222
  }
193
223
  type Entries<D, K extends "inputs" | "outputs" | "props"> = D extends Record<K, infer R> ? R : Record<never, never>;
194
- type InputValue<I> = I extends TriggerInputDefinition ? TriggerEvent | undefined : I extends DataInputDefinition<infer T> ? I extends {
224
+ /** The value a declared bundle field holds. */
225
+ type BundleFieldValue<F> = F extends CascadeType ? ValueForType<F> : F extends {
226
+ readonly type: infer T extends CascadeType;
227
+ } ? ValueForType<T> : unknown;
228
+ /** A bundle output's value, typed from its declared fields. Every field is
229
+ * optional: a producer may leave one unset, and a consumer then reads none. */
230
+ type BundleOutputValue<O> = O extends {
231
+ readonly fields: infer F extends Readonly<Record<string, BundleFieldDefinition>>;
232
+ } ? {
233
+ readonly [K in keyof F]?: BundleFieldValue<F[K]>;
234
+ } : Readonly<Record<string, unknown>>;
235
+ /** A bundle input's value: only the declared fields, when it declares any. */
236
+ type BundleInputValue<I> = I extends {
237
+ readonly fields: readonly (infer K extends string)[];
238
+ } ? {
239
+ readonly [P in K]?: unknown;
240
+ } : Readonly<Record<string, unknown>>;
241
+ type InputValue<I> = I extends TriggerInputDefinition ? TriggerEvent | undefined : I extends DataInputDefinition<"bundle"> ? I extends {
242
+ readonly default: unknown;
243
+ } ? BundleInputValue<I> : BundleInputValue<I> | undefined : I extends DataInputDefinition<infer T> ? I extends {
195
244
  readonly variadic: true;
196
245
  } ? readonly ValueForType<T>[] : "default" extends keyof I ? ValueForType<T> : ValueForType<T> | undefined : never;
197
246
  type OutputValue<O> = O extends TriggerOutputDefinition ? {
198
247
  trigger(payload?: JsonValue): void;
248
+ } : O extends DataOutputDefinition<"bundle"> ? {
249
+ set(value: BundleOutputValue<O>): void;
199
250
  } : O extends DataOutputDefinition<infer T> ? {
200
251
  set(value: ValueForType<T>): void;
201
252
  } : never;
@@ -228,6 +279,18 @@ export interface NodeExecutionContext<D extends NodeDefinition> {
228
279
  readonly capabilities: DeclaredCapabilities<D>;
229
280
  readonly signal: CascadeAbortSignal;
230
281
  readonly progress: ProgressReporter;
282
+ /**
283
+ * This node's seed, derived from the graph's `seed` and the node id
284
+ * (`nodeSeed` in `@cascade/runtime`). Every host computes it the same way,
285
+ * so a seeded node draws the same thing headless and in Studio. Pass it on
286
+ * to anything random, including a Python stage's args.
287
+ */
288
+ readonly seed: number;
289
+ /**
290
+ * A stream of floats in [0, 1) seeded with `seed`, starting afresh at every
291
+ * cook. Use it instead of `Math.random`, which no host can reproduce.
292
+ */
293
+ readonly random: () => number;
231
294
  }
232
295
  export type NodeExecute<D extends NodeDefinition = NodeDefinition> = (context: NodeExecutionContext<D>) => void | Promise<void>;
233
296
  export {};
@@ -1,3 +1,4 @@
1
+ import type { EditorDeclaration } from "./editor.js";
1
2
  import type { SerializableValue } from "./values.js";
2
3
  export interface CascadeDocumentNode {
3
4
  readonly id: string;
@@ -54,6 +55,34 @@ export interface CascadeDocument {
54
55
  readonly nodes: readonly CascadeDocumentNode[];
55
56
  readonly annotations?: readonly CascadeDocumentAnnotation[];
56
57
  readonly connections?: readonly CascadeDocumentConnection[];
58
+ /** The shareable editor this graph declares; ignored by the runtime. See `editor.ts`. */
59
+ readonly editor?: EditorDeclaration;
60
+ /**
61
+ * The graph seed, an unsigned 32-bit integer; 0 when absent. Each node's
62
+ * `context.seed` is derived from it and the node id, so changing it
63
+ * reshuffles every seeded node at once.
64
+ */
65
+ readonly seed?: number;
66
+ /** The timeline the graph is played and rendered over. See `TimelineSettings`. */
67
+ readonly timeline?: TimelineSettings;
68
+ }
69
+ /**
70
+ * The frame rate, range and looping a graph is made for, saved with it.
71
+ *
72
+ * Without it every graph opened at 30 fps and frames 1-250, and a piece made
73
+ * for 24 fps over 594 frames (cloud-wall's H1 flipbook) had to be set up by
74
+ * hand on every open. Studio's timeline reads and writes it, the runtime takes
75
+ * its `fps` as the graph's own rate, and `cascade run --frames timeline`
76
+ * renders `start`-`end`. Every field is optional; absent ones keep the
77
+ * defaults (30 fps, 1-250, looping).
78
+ */
79
+ export interface TimelineSettings {
80
+ readonly fps?: number;
81
+ /** First frame, inclusive. */
82
+ readonly start?: number;
83
+ /** Last frame, inclusive. */
84
+ readonly end?: number;
85
+ readonly loop?: boolean;
57
86
  }
58
87
  export interface CascadePreset {
59
88
  readonly version: 1;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Compact-array JSON formatting for .cascade files — ported unchanged
3
+ * from the original routes/projects.ts (real design work: keeps small
4
+ * arrays like [x, y] coordinates and [from, to] connections on one line
5
+ * instead of exploding them across many, so a saved graph stays readable
6
+ * and diffable in git — which matters now that every save is a commit.
7
+ *
8
+ * The one copy: Studio's save and download (src/utils/fileSystem.ts), the
9
+ * server's graph route and the CLI's graph edits all write through it, so a
10
+ * file saved by any of them diffs cleanly against the others.
11
+ */
12
+ /**
13
+ * Format JSON string with compact arrays (keeps small arrays on single lines)
14
+ * This function finds multi-line arrays with 2-4 elements and compacts them
15
+ * Handles both numeric arrays and arrays containing small arrays (like connections)
16
+ */
17
+ export declare function formatCompactJSON(jsonString: string, indent?: number): string;
18
+ //# sourceMappingURL=documentFormat.d.ts.map
@@ -0,0 +1,195 @@
1
+ /**
2
+ * Compact-array JSON formatting for .cascade files — ported unchanged
3
+ * from the original routes/projects.ts (real design work: keeps small
4
+ * arrays like [x, y] coordinates and [from, to] connections on one line
5
+ * instead of exploding them across many, so a saved graph stays readable
6
+ * and diffable in git — which matters now that every save is a commit.
7
+ *
8
+ * The one copy: Studio's save and download (src/utils/fileSystem.ts), the
9
+ * server's graph route and the CLI's graph edits all write through it, so a
10
+ * file saved by any of them diffs cleanly against the others.
11
+ */
12
+ /**
13
+ * Format JSON string with compact arrays (keeps small arrays on single lines)
14
+ * This function finds multi-line arrays with 2-4 elements and compacts them
15
+ * Handles both numeric arrays and arrays containing small arrays (like connections)
16
+ */
17
+ export function formatCompactJSON(jsonString, indent = 2) {
18
+ // Process multiple passes to handle nested arrays
19
+ let result = jsonString;
20
+ let previousResult = '';
21
+ // Keep processing until no more changes (handles nested arrays)
22
+ while (result !== previousResult) {
23
+ previousResult = result;
24
+ result = formatCompactJSONPass(result, indent);
25
+ }
26
+ return result;
27
+ }
28
+ /**
29
+ * Single pass of compact formatting
30
+ */
31
+ function formatCompactJSONPass(jsonString, indent = 2) {
32
+ const lines = jsonString.split('\n');
33
+ const result = [];
34
+ let i = 0;
35
+ while (i < lines.length) {
36
+ const line = lines[i];
37
+ const trimmed = line.trim();
38
+ // Check if this line starts an array (pattern: "key": [ or just [)
39
+ if (trimmed.endsWith('[') && (trimmed.includes(':') || trimmed === '[')) {
40
+ // Collect lines until we find the closing bracket
41
+ let arrayLines = [line];
42
+ let bracketDepth = 1;
43
+ let j = i + 1;
44
+ while (j < lines.length && bracketDepth > 0) {
45
+ const currentLine = lines[j];
46
+ arrayLines.push(currentLine);
47
+ // Count bracket depth
48
+ for (const char of currentLine) {
49
+ if (char === '[')
50
+ bracketDepth++;
51
+ if (char === ']')
52
+ bracketDepth--;
53
+ }
54
+ j++;
55
+ }
56
+ // Extract array content (lines between opening and closing brackets)
57
+ // Handle nested arrays by extracting complete array elements
58
+ const arrayContent = [];
59
+ let k = 1;
60
+ while (k < arrayLines.length - 1) {
61
+ const currentLine = arrayLines[k].trim();
62
+ // Check if this line starts a nested array
63
+ if (currentLine.endsWith('[') || (currentLine.startsWith('[') && !currentLine.endsWith(']'))) {
64
+ // Extract the complete nested array
65
+ let nestedArrayLines = [arrayLines[k]];
66
+ let nestedDepth = 1;
67
+ let m = k + 1;
68
+ while (m < arrayLines.length - 1 && nestedDepth > 0) {
69
+ nestedArrayLines.push(arrayLines[m]);
70
+ for (const char of arrayLines[m]) {
71
+ if (char === '[')
72
+ nestedDepth++;
73
+ if (char === ']')
74
+ nestedDepth--;
75
+ }
76
+ m++;
77
+ }
78
+ // Join nested array lines into a single compact representation
79
+ const nestedContent = [];
80
+ for (let n = 1; n < nestedArrayLines.length - 1; n++) {
81
+ const nestedLine = nestedArrayLines[n].trim().replace(/,$/, '').trim();
82
+ if (nestedLine) {
83
+ nestedContent.push(nestedLine);
84
+ }
85
+ }
86
+ // Create compact nested array string
87
+ const nestedArray = '[' + nestedContent.map(c => c.trim()).join(', ') + ']';
88
+ arrayContent.push(nestedArray);
89
+ k = m;
90
+ }
91
+ else {
92
+ // Simple element
93
+ const content = currentLine.replace(/,$/, '').trim();
94
+ if (content) {
95
+ arrayContent.push(content);
96
+ }
97
+ k++;
98
+ }
99
+ }
100
+ // Check if it's a small numeric array (2-4 elements)
101
+ const isSmallNumericArray = arrayContent.length >= 2 &&
102
+ arrayContent.length <= 4 &&
103
+ arrayContent.every(item => {
104
+ const trimmed = item.trim();
105
+ return /^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(trimmed);
106
+ });
107
+ // Check if it's an array containing small arrays (like connections: [[a, b], [c, d]])
108
+ // Look for patterns where each element is a small array (2-4 elements)
109
+ // This handles both already-compacted arrays and multi-line nested arrays
110
+ let isArrayOfSmallArrays = false;
111
+ if (arrayContent.length >= 2 && arrayContent.length <= 20) { // Reasonable limit for connections
112
+ // Check if elements are arrays (either compact or multi-line)
113
+ const allAreArrays = arrayContent.every(item => {
114
+ const trimmed = item.trim();
115
+ // Already compact array like [a, b] or ["a", 0]
116
+ if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
117
+ const inner = trimmed.slice(1, -1).trim();
118
+ const parts = inner.split(',').map(p => p.trim()).filter(p => p);
119
+ return parts.length >= 2 && parts.length <= 4;
120
+ }
121
+ // Multi-line array - check if this line starts an array
122
+ if (trimmed.endsWith('[')) {
123
+ return true; // This will be handled in a later pass
124
+ }
125
+ return false;
126
+ });
127
+ if (allAreArrays) {
128
+ // Check if inner arrays are small (2-4 elements each)
129
+ // For multi-line arrays, we'll need to extract their content
130
+ let allSmall = true;
131
+ for (const item of arrayContent) {
132
+ const trimmed = item.trim();
133
+ if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
134
+ // Already compact - check size
135
+ const inner = trimmed.slice(1, -1).trim();
136
+ const parts = inner.split(',').map(p => p.trim()).filter(p => p);
137
+ if (parts.length < 2 || parts.length > 4) {
138
+ allSmall = false;
139
+ break;
140
+ }
141
+ }
142
+ else if (trimmed.endsWith('[')) {
143
+ // Multi-line array - will be compacted in next pass, assume it's small for now
144
+ // We'll handle this in the multi-pass approach
145
+ }
146
+ else {
147
+ allSmall = false;
148
+ break;
149
+ }
150
+ }
151
+ isArrayOfSmallArrays = allSmall;
152
+ }
153
+ }
154
+ if (isSmallNumericArray || isArrayOfSmallArrays) {
155
+ // Compact format: put entire array on one line
156
+ const indentLevel = (line.match(/^(\s*)/)?.[1] || '').length;
157
+ // Extract the key part (everything before the opening bracket)
158
+ const keyMatch = trimmed.match(/^(.+?)\s*\[\s*$/);
159
+ const keyPart = keyMatch ? keyMatch[1] : '';
160
+ // Check if the closing bracket line has a comma (last line in arrayLines)
161
+ const closingLine = arrayLines[arrayLines.length - 1];
162
+ const hasComma = closingLine.trim().endsWith(',');
163
+ // Format array content
164
+ let formattedContent;
165
+ if (isArrayOfSmallArrays) {
166
+ // For arrays of arrays, each element should be compact
167
+ // If an element is a multi-line array (ends with [), we can't compact it yet
168
+ // Otherwise, use the already-compact form
169
+ formattedContent = arrayContent.map(c => {
170
+ const trimmed = c.trim();
171
+ // If it's already compact, use it as-is
172
+ if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
173
+ return trimmed;
174
+ }
175
+ // If it's a multi-line array start, we'll need another pass
176
+ // For now, return as-is (will be handled in next pass)
177
+ return trimmed;
178
+ }).join(', ');
179
+ }
180
+ else {
181
+ // Simple numeric array
182
+ formattedContent = arrayContent.map(c => c.trim()).join(', ');
183
+ }
184
+ const compactArray = keyPart + ' [' + formattedContent + ']' + (hasComma ? ',' : '');
185
+ result.push(' '.repeat(indentLevel) + compactArray);
186
+ i = j; // Skip the processed lines
187
+ continue;
188
+ }
189
+ }
190
+ result.push(line);
191
+ i++;
192
+ }
193
+ return result.join('\n');
194
+ }
195
+ //# sourceMappingURL=documentFormat.js.map
@@ -0,0 +1,189 @@
1
+ import type { SelectOption } from "./definition.js";
2
+ import type { JsonValue } from "./values.js";
3
+ /**
4
+ * The shareable editor a graph declares: which parameters someone else may
5
+ * change, which outputs they may export, the presets they may start from, and
6
+ * the assets that are allowed to leave the project with it.
7
+ *
8
+ * It sits beside `nodes` in the document, like Houdini's parameter interface on
9
+ * a digital asset sits beside its network. The runtime ignores it: a published
10
+ * parameter is an ordinary prop with a label, so a headless render, Studio and
11
+ * the exported editor cook the same graph. Only `cascade export`, the editor
12
+ * shell and scene files read it.
13
+ *
14
+ * Everything here is an allowlist. A parameter, output or asset that is not
15
+ * named does not reach the exported site, and a scene file carries values for
16
+ * named parameters only. That is the boundary a share relies on: an export is
17
+ * the selected subgraph plus the selected assets, never the project.
18
+ */
19
+ export interface EditorDeclaration {
20
+ /** Stable identity of the editor, written into every scene. `cloud-type`. */
21
+ readonly id: string;
22
+ readonly title?: string;
23
+ readonly description?: string;
24
+ /** Group names in display order. Groups not listed follow, in first-use order. */
25
+ readonly groups?: readonly string[];
26
+ readonly parameters?: readonly PublishedParameter[];
27
+ readonly outputs?: readonly PublishedOutput[];
28
+ readonly presets?: readonly EditorPreset[];
29
+ /**
30
+ * Project-relative files the author selects to ship. Literal asset values of
31
+ * published parameters are included too; nothing else is. A path inside a
32
+ * `licensed/` directory, a hidden file, or a gitignored file is refused.
33
+ */
34
+ readonly assets?: readonly string[];
35
+ /**
36
+ * Data-source nodes replaced by a snapshot of chosen values. A live source
37
+ * (server, files, Python, shell or a `source: "live"` definition) still wired
38
+ * into the exported subgraph fails the export.
39
+ */
40
+ readonly freeze?: readonly FrozenSource[];
41
+ /** Optional project panel module that extends or replaces the generated UI. */
42
+ readonly panel?: EditorPanelDeclaration;
43
+ /** The read-only stage view. On unless the author turns it off. */
44
+ readonly inspect?: boolean;
45
+ /**
46
+ * Fonts the exported editor ships and loads, in the page and in the engine
47
+ * worker, so a panel or a canvas that names the family draws with it rather
48
+ * than the system fallback. Open-licensed only: each one states its licence
49
+ * (`OFL-1.1`), and a file under `licensed/` is refused like any other asset.
50
+ */
51
+ readonly fonts?: readonly EditorFont[];
52
+ /**
53
+ * Parameter ids a phone keeps in reach at the bottom sheet's lowest snap
54
+ * point (the text, a Reroll). Defaults to the first text and seed parameters.
55
+ */
56
+ readonly peek?: readonly string[];
57
+ /**
58
+ * Values cooked while a slider is being dragged on a phone, for a quicker
59
+ * preview: a lower density, say. They never enter a scene or an export, and
60
+ * the real values cook again on release.
61
+ */
62
+ readonly draft?: Readonly<Record<string, JsonValue>>;
63
+ }
64
+ export interface EditorFont {
65
+ /** The CSS family name the project's code uses (`DM Mono`). */
66
+ readonly family: string;
67
+ /** Project-relative font file: `.woff2`, `.woff`, `.ttf` or `.otf`. */
68
+ readonly file: string;
69
+ /** SIL Open Font License. Anything else is refused at export. */
70
+ readonly license: "OFL-1.1";
71
+ readonly weight?: string | number;
72
+ readonly style?: "normal" | "italic";
73
+ }
74
+ export type PublishedControl = "number" | "slider" | "int" | "bool" | "select" | "text" | "textarea" | "color" | "file" | "seed" | "vec2";
75
+ export interface PublishedParameter {
76
+ /** Scene key. Stable across renames of the node or the prop it targets. */
77
+ readonly id: string;
78
+ /** The node and prop whose value this parameter sets. */
79
+ readonly node: string;
80
+ readonly prop: string;
81
+ readonly label?: string;
82
+ readonly group?: string;
83
+ readonly order?: number;
84
+ readonly help?: string;
85
+ readonly unit?: string;
86
+ /** Overrides the control the prop's type implies. */
87
+ readonly control?: PublishedControl;
88
+ readonly min?: number;
89
+ readonly max?: number;
90
+ readonly step?: number;
91
+ readonly options?: readonly SelectOption<"string">[] | readonly SelectOption<"float">[];
92
+ /** File parameters: accepted extensions or media types (`.otf`, `image/*`). */
93
+ readonly accept?: readonly string[];
94
+ /**
95
+ * File parameters: whether a dropped file may travel inside a scene.
96
+ * `never` keeps it to a name and a hash (licensed fonts); `auto` embeds files
97
+ * up to 2 MB. Dropped files never leave the viewer's browser otherwise.
98
+ */
99
+ readonly embed?: "never" | "auto";
100
+ /** Shown only when other parameters have these values; a list must all hold. */
101
+ readonly visibleWhen?: VisibleWhen | readonly VisibleWhen[];
102
+ }
103
+ export type VisibleWhen = Readonly<{
104
+ param: string;
105
+ equals?: JsonValue;
106
+ in?: readonly JsonValue[];
107
+ not?: readonly JsonValue[];
108
+ }>;
109
+ export type PublishedOutputFormat = "png" | "svg" | "json" | "text";
110
+ export interface PublishedOutput {
111
+ readonly id: string;
112
+ readonly node: string;
113
+ readonly port: string;
114
+ readonly label?: string;
115
+ readonly format: PublishedOutputFormat;
116
+ /** Download name; `{id}` and `{scene}` are replaced. */
117
+ readonly filename?: string;
118
+ /** Published parameter ids shown beside this output's button (dpi, ground). */
119
+ readonly parameters?: readonly string[];
120
+ /** The output shown in the viewer. One output should set it. */
121
+ readonly view?: boolean;
122
+ }
123
+ export interface EditorPreset {
124
+ readonly id: string;
125
+ readonly label: string;
126
+ /** Published parameter id to value. Missing parameters take their defaults. */
127
+ readonly values: Readonly<Record<string, JsonValue>>;
128
+ /** Parameters the preset leaves as they are (colour, pen) instead of resetting them. */
129
+ readonly keep?: readonly string[];
130
+ }
131
+ export interface FrozenSource {
132
+ /** The live node the snapshot replaces. Everything upstream of it is dropped. */
133
+ readonly node: string;
134
+ readonly output: string;
135
+ /** Project-relative snapshot written by `cascade freeze`. */
136
+ readonly snapshot: string;
137
+ }
138
+ export interface EditorPanelDeclaration {
139
+ /** Project-relative module exporting `mount(target, api)`. */
140
+ readonly module: string;
141
+ /** `extend` (default) mounts it above the generated parameters. */
142
+ readonly placement?: "extend" | "replace";
143
+ }
144
+ /** What `cascade freeze` writes: exactly the chosen values, nothing else. */
145
+ export interface FrozenSnapshot {
146
+ readonly format: "cascade.frozen";
147
+ readonly version: 1;
148
+ readonly node: string;
149
+ readonly output: string;
150
+ readonly fields: readonly string[];
151
+ /** Fields the author marked as personal, flagged in every export plan. */
152
+ readonly personal?: readonly string[];
153
+ readonly value: JsonValue;
154
+ /** Project-relative files the value refers to, copied beside the snapshot. */
155
+ readonly files?: readonly string[];
156
+ readonly frozenAt: string;
157
+ }
158
+ /**
159
+ * A scene: what someone changed in an editor, as a file that opens onto the
160
+ * same graph in Studio, the CLI or the exported editor.
161
+ *
162
+ * It holds published parameter values and the files the person dropped, and
163
+ * nothing from the project. Version mismatches degrade: unknown parameters are
164
+ * ignored with a warning, missing ones take the graph's defaults.
165
+ */
166
+ export interface CascadeScene {
167
+ readonly format: "cascade.scene";
168
+ readonly version: 1;
169
+ readonly graph: Readonly<{
170
+ id: string;
171
+ version: string;
172
+ }>;
173
+ readonly name?: string;
174
+ readonly values: Readonly<Record<string, JsonValue>>;
175
+ /** Files for `file` parameters, by parameter id. */
176
+ readonly files?: Readonly<Record<string, SceneFile>>;
177
+ readonly savedAt?: string;
178
+ }
179
+ export interface SceneFile {
180
+ readonly name: string;
181
+ readonly mediaType?: string;
182
+ readonly size: number;
183
+ /** Hex SHA-256 of the bytes, to match a file the receiver already has. */
184
+ readonly sha256: string;
185
+ /** Base64 bytes, present only when the parameter allows embedding. */
186
+ readonly data?: string;
187
+ }
188
+ export declare const SCENE_EMBED_LIMIT: number;
189
+ //# sourceMappingURL=editor.d.ts.map
@@ -0,0 +1,2 @@
1
+ export const SCENE_EMBED_LIMIT = 2 * 1024 * 1024;
2
+ //# sourceMappingURL=editor.js.map
@@ -1,9 +1,12 @@
1
1
  export * from "./animation.js";
2
+ export * from "./bundle.js";
2
3
  export * from "./camera.js";
3
4
  export * from "./capabilities.js";
4
5
  export * from "./color.js";
5
6
  export * from "./definition.js";
6
7
  export * from "./document.js";
8
+ export * from "./documentFormat.js";
9
+ export * from "./editor.js";
7
10
  export * from "./geometry.js";
8
11
  export * from "./particles.js";
9
12
  export * from "./scene.js";
@@ -1,9 +1,12 @@
1
1
  export * from "./animation.js";
2
+ export * from "./bundle.js";
2
3
  export * from "./camera.js";
3
4
  export * from "./capabilities.js";
4
5
  export * from "./color.js";
5
6
  export * from "./definition.js";
6
7
  export * from "./document.js";
8
+ export * from "./documentFormat.js";
9
+ export * from "./editor.js";
7
10
  export * from "./geometry.js";
8
11
  export * from "./particles.js";
9
12
  export * from "./scene.js";