@field/cascade 0.10.0 → 0.12.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 (229) hide show
  1. package/AGENTS.md +25 -5
  2. package/ARCHITECTURE.md +5 -4
  3. package/CHANGELOG.md +382 -0
  4. package/README.md +1 -2
  5. package/dist/assets/AgentPanel-1JugFjE4.css +1 -0
  6. package/dist/assets/AgentPanel-BDL5MddA.js +5 -0
  7. package/dist/assets/{CodeEditor-DSZBpzdy.js → CodeEditor-C-xYG-Wn.js} +120 -120
  8. package/dist/assets/CodePanel-CtXd50m6.js +2 -0
  9. package/dist/assets/CookInfoPanel-B3NMhKJF.css +1 -0
  10. package/dist/assets/CookInfoPanel-DG4_TRsX.js +2 -0
  11. package/dist/assets/CustomNodeDialog-CHfZUs-r.js +1 -0
  12. package/dist/assets/DefinitionNode-CaRTXQ_b.js +1 -0
  13. package/dist/assets/DefinitionPanel-C3CxZY9r.js +1 -0
  14. package/dist/assets/DefinitionPanel-VNLnAiQD.css +1 -0
  15. package/dist/assets/OpenGraphDialog-BLdr6k_q.js +1 -0
  16. package/dist/assets/ProjectSettings-ZnvmIAir.js +2 -0
  17. package/dist/assets/{SettingsDialog-p25h3tj0.js → SettingsDialog-CBX3Wa87.js} +1 -1
  18. package/dist/assets/TimelinePanel-CDeR0arY.css +1 -0
  19. package/dist/assets/TimelinePanel-CWgnFH1e.js +1 -0
  20. package/dist/assets/{VersionHistoryDialog-DzFLUotB.js → VersionHistoryDialog-BOSoW1R-.js} +1 -1
  21. package/dist/assets/assert-BO2_erPD.js +1 -0
  22. package/dist/assets/assert-hvykGCnP.js +1 -0
  23. package/dist/assets/builder-BmBKcDix.js +1 -0
  24. package/dist/assets/camera-DFF7YA3F.js +1 -0
  25. package/dist/assets/checks-DAvyO9Gf.js +1 -0
  26. package/dist/assets/contactSheet-N1NcaWxw.js +2 -0
  27. package/dist/assets/{core-BICrEt0y.js → core-DB-MkGjj.js} +3 -4
  28. package/dist/assets/coreTypes-DtnDATZ7.js +1 -0
  29. package/dist/assets/{cssMode-D7TXw57I.js → cssMode-DPVckSOc.js} +1 -1
  30. package/dist/assets/definitions-B227e7f_.js +1 -0
  31. package/dist/assets/definitions-D0WOUJd7.js +1 -0
  32. package/dist/assets/{editor.api-DvkCO3ko.js → editor.api-Dkutg_Z1.js} +1 -1
  33. package/dist/assets/expressions-X-Z-GrgW.js +5 -0
  34. package/dist/assets/file-DAL6IfjV.js +1 -0
  35. package/dist/assets/filters-D3k1LRMa.js +1 -0
  36. package/dist/assets/{freemarker2-BA2lxsF1.js → freemarker2-CLiLKk3B.js} +1 -1
  37. package/dist/assets/generators-BhDxRAFC.js +1 -0
  38. package/dist/assets/geo-BsMImJIJ.js +1 -0
  39. package/dist/assets/geo-C4YngDob.js +2 -0
  40. package/dist/assets/{handlebars-BcDiyPd8.js → handlebars-CcD3aMeL.js} +1 -1
  41. package/dist/assets/{html-C7O4TyhX.js → html-DvZWGfqb.js} +1 -1
  42. package/dist/assets/{htmlMode-WaDGF3Mj.js → htmlMode-DUD3VaoN.js} +1 -1
  43. package/dist/assets/image-0SfH-snh.js +1 -0
  44. package/dist/assets/image-Ck-RdGU4.js +2 -0
  45. package/dist/assets/index-BWnrmIB9.js +137 -0
  46. package/dist/assets/index-DIaxEONI.css +1 -0
  47. package/dist/assets/io-BGmt2g0D.js +1 -0
  48. package/dist/assets/{javascript-CpIEK7tz.js → javascript-Cap2ahgh.js} +1 -1
  49. package/dist/assets/{jsonMode-B2FltW0f.js → jsonMode-B0uLjp9C.js} +1 -1
  50. package/dist/assets/{liquid-CN6FFHZE.js → liquid-CnxwhfLn.js} +1 -1
  51. package/dist/assets/{lspLanguageFeatures-QhV9XtLp.js → lspLanguageFeatures-Dn9hlKX6.js} +1 -1
  52. package/dist/assets/math-GeULS-sk.js +1 -0
  53. package/dist/assets/{mdx-DE89pafV.js → mdx-BV3jbrVa.js} +1 -1
  54. package/dist/assets/pop-KMF_qloi.js +1 -0
  55. package/dist/assets/preload-helper-Czpn1I53.js +1 -0
  56. package/dist/assets/{python-ByTllTB9.js → python-CGyFk4XK.js} +1 -1
  57. package/dist/assets/{razor-USYlRRCE.js → razor-CQfzX3-N.js} +1 -1
  58. package/dist/assets/remap-5SjXQU-q.js +1 -0
  59. package/dist/assets/renderMarkdown-ork0Oir7.js +67 -0
  60. package/dist/assets/studioImages-CAyH-0Pl.js +1 -0
  61. package/dist/assets/text-ZpX7qNkx.js +2 -0
  62. package/dist/assets/time-P_OiBhcf.js +1 -0
  63. package/dist/assets/{tsMode-BXpN8iUz.js → tsMode-BOeXzO9H.js} +1 -1
  64. package/dist/assets/{typescript-DInBjGQQ.js → typescript-J1SnE_Tu.js} +1 -1
  65. package/dist/assets/{workers-C7Ye5B7D.js → workers-CYwwTiVF.js} +1 -1
  66. package/dist/assets/{xml-U0Uocqyo.js → xml-DnPRNzK9.js} +1 -1
  67. package/dist/assets/{yaml-CBw_PVYf.js → yaml-BmmYBNa9.js} +1 -1
  68. package/dist/cli/DefinitionNode-P7AA4TAU.js +15 -0
  69. package/dist/cli/Graph-OB6EWSGL.js +2975 -0
  70. package/dist/cli/assert-GROGQNCQ.js +25 -0
  71. package/dist/cli/checks-3WB44XBL.js +189 -0
  72. package/dist/cli/chunk-2JEU3MGB.js +1125 -0
  73. package/dist/cli/chunk-2KXB47FP.js +115 -0
  74. package/dist/cli/chunk-3RXL5GHB.js +816 -0
  75. package/dist/cli/chunk-53LGFPWX.js +138 -0
  76. package/dist/cli/chunk-5ORUQ6ES.js +267 -0
  77. package/dist/cli/chunk-73S4JZXK.js +336 -0
  78. package/dist/cli/chunk-7QE2ZNSN.js +121 -0
  79. package/dist/cli/chunk-BP7UKF36.js +376 -0
  80. package/dist/cli/chunk-BPODRH52.js +201 -0
  81. package/dist/cli/chunk-BZ63XQ3I.js +1301 -0
  82. package/dist/cli/chunk-CKS2FQWR.js +89 -0
  83. package/dist/cli/chunk-CO22XHNG.js +593 -0
  84. package/dist/cli/chunk-CTPLRSWF.js +2197 -0
  85. package/dist/cli/chunk-DEQSEFFH.js +153 -0
  86. package/dist/cli/chunk-EU4ZFZ7Y.js +122 -0
  87. package/dist/cli/chunk-EZRWJ4G2.js +104 -0
  88. package/dist/cli/chunk-FWMSGKEH.js +71 -0
  89. package/dist/cli/chunk-G23A2BZZ.js +705 -0
  90. package/dist/cli/chunk-GRIN2DDP.js +1465 -0
  91. package/dist/cli/chunk-HFHWYL55.js +139 -0
  92. package/dist/cli/chunk-HSNOBIVT.js +263 -0
  93. package/dist/cli/chunk-ICH7N5PN.js +26 -0
  94. package/dist/cli/chunk-J7VK7MNF.js +418 -0
  95. package/dist/cli/chunk-JVOCK5W4.js +83 -0
  96. package/dist/cli/chunk-KBGUO27Q.js +15 -0
  97. package/dist/cli/chunk-KH4MUBKF.js +1551 -0
  98. package/dist/cli/chunk-L6B6FUQP.js +330 -0
  99. package/dist/cli/chunk-LTXWBXOM.js +438 -0
  100. package/dist/cli/chunk-MI5JLQYA.js +220 -0
  101. package/dist/cli/chunk-MP653A5O.js +3766 -0
  102. package/dist/cli/chunk-NJFMDXHR.js +320 -0
  103. package/dist/cli/chunk-OM6BEME6.js +267 -0
  104. package/dist/cli/chunk-OWWBYLHC.js +136 -0
  105. package/dist/cli/chunk-QQPA2ZHH.js +273 -0
  106. package/dist/cli/chunk-RUU3YWXU.js +99 -0
  107. package/dist/cli/chunk-RXDIMXN5.js +98 -0
  108. package/dist/cli/chunk-ST6LROUG.js +267 -0
  109. package/dist/cli/chunk-TJW67QSI.js +225 -0
  110. package/dist/cli/chunk-WD62JIP6.js +118 -0
  111. package/dist/cli/chunk-WGKPJZDY.js +364 -0
  112. package/dist/cli/chunk-X4WKAOQP.js +634 -0
  113. package/dist/cli/chunk-X566FWBV.js +156 -0
  114. package/dist/cli/chunk-YH637PDL.js +317 -0
  115. package/dist/cli/chunk-ZL4JTG5Y.js +37 -0
  116. package/dist/cli/chunk-ZSCUZE6I.js +112 -0
  117. package/dist/cli/cliCommands-JJN5Z3ZC.js +3470 -0
  118. package/dist/cli/commands-PHYFYA3F.js +1374 -0
  119. package/dist/cli/contactSheet-2PQVRUFW.js +11 -0
  120. package/dist/cli/definitions-BPOPW52L.js +32 -0
  121. package/dist/cli/doctorCommand-ORWQRNYP.js +106 -0
  122. package/dist/cli/edit-S5KEQ5RA.js +28 -0
  123. package/dist/cli/editorCommands-NFR32JOY.js +41 -0
  124. package/dist/cli/encode-ICPEPMH5.js +17 -0
  125. package/dist/cli/file-3HTQHPYQ.js +41 -0
  126. package/dist/cli/filters-6ODFWYK4.js +379 -0
  127. package/dist/cli/frames-LSAUBZ7P.js +16 -0
  128. package/dist/cli/generators-YU7GB4MD.js +210 -0
  129. package/dist/cli/geo-6ZPGKZRU.js +43 -0
  130. package/dist/cli/graphCommands-EOUOBOIJ.js +184 -0
  131. package/dist/cli/graphFile-YTGJB5F5.js +292 -0
  132. package/dist/cli/headlessCanvas-ENRHC7GS.js +16 -0
  133. package/dist/cli/helpCommand-PULH6ZYB.js +157 -0
  134. package/dist/cli/image-TXELZZK5.js +55 -0
  135. package/dist/cli/index.js +100 -30756
  136. package/dist/cli/math-RSYRQ3C6.js +16 -0
  137. package/dist/cli/mcp-JVZFQOEX.js +164 -0
  138. package/dist/cli/parity-X6DEH2DV.js +334 -0
  139. package/dist/cli/pop-B7SIIYKN.js +39 -0
  140. package/dist/cli/project-VYGIA7JX.js +12 -0
  141. package/dist/cli/projectDefinition-F3D7UIHJ.js +27 -0
  142. package/dist/cli/projectRuntime-2Q4JKEH3.js +55 -0
  143. package/dist/cli/registerStandardNodes-BXJCB6E4.js +744 -0
  144. package/dist/cli/render-PT4MWI6U.js +438 -0
  145. package/dist/cli/runCommand-HNPQVZMS.js +198 -0
  146. package/dist/cli/runner-5XPXVW7J.js +43 -0
  147. package/dist/cli/runtime/image.ts +302 -0
  148. package/dist/cli/runtime/io.ts +78 -0
  149. package/dist/cli/runtime/stage.ts +4 -1
  150. package/dist/cli/share-MHF6TNRK.js +166 -0
  151. package/dist/cli/stageCache-TY2BFZJR.js +15 -0
  152. package/dist/cli/stageRunner-KY2EJP7X.js +10 -0
  153. package/dist/cli/text-MB3EKR4H.js +126 -0
  154. package/dist/cli/verbs-PI2JH5FI.js +19 -0
  155. package/dist/cli/webBuild-WPPMGGW7.js +44 -0
  156. package/dist/contracts/capabilities.d.ts +18 -1
  157. package/dist/contracts/color.d.ts +8 -0
  158. package/dist/contracts/color.js +23 -0
  159. package/dist/contracts/definition.d.ts +10 -0
  160. package/dist/contracts/documentFormat.d.ts +18 -0
  161. package/dist/contracts/documentFormat.js +195 -0
  162. package/dist/contracts/editor.d.ts +17 -0
  163. package/dist/contracts/index.d.ts +1 -0
  164. package/dist/contracts/index.js +1 -0
  165. package/dist/contracts/schema.d.ts +1 -1
  166. package/dist/contracts/schema.js +1 -0
  167. package/dist/contracts/validate.js +11 -1
  168. package/dist/contracts/values.d.ts +24 -0
  169. package/dist/image.d.ts +156 -0
  170. package/dist/image.js +161 -0
  171. package/dist/index.html +8 -2
  172. package/dist/io.d.ts +29 -0
  173. package/dist/io.js +40 -0
  174. package/dist/player/app.js +3 -2
  175. package/dist/player/editor.js +35 -9
  176. package/dist/player/editorEngine.js +3 -2
  177. package/dist/runtime/builtins/assert/checks.d.ts +18 -0
  178. package/dist/runtime/builtins/assert/checks.js +207 -0
  179. package/dist/runtime/builtins/assert/definitions.d.ts +130 -0
  180. package/dist/runtime/builtins/assert/definitions.js +54 -0
  181. package/dist/runtime/builtins/assert/index.d.ts +152 -0
  182. package/dist/runtime/builtins/assert/index.js +36 -0
  183. package/dist/runtime/builtins/image/contactSheet.d.ts +64 -0
  184. package/dist/runtime/builtins/image/contactSheet.js +150 -0
  185. package/dist/runtime/builtins/image/definitions.d.ts +950 -0
  186. package/dist/runtime/builtins/image/definitions.js +343 -0
  187. package/dist/runtime/builtins/image/file.d.ts +8 -0
  188. package/dist/runtime/builtins/image/file.js +37 -0
  189. package/dist/runtime/builtins/image/filters.d.ts +8 -0
  190. package/dist/runtime/builtins/image/filters.js +394 -0
  191. package/dist/runtime/builtins/image/generators.d.ts +7 -0
  192. package/dist/runtime/builtins/image/generators.js +144 -0
  193. package/dist/runtime/builtins/image/index.d.ts +952 -0
  194. package/dist/runtime/builtins/image/index.js +44 -0
  195. package/dist/runtime/builtins/image/io.d.ts +100 -0
  196. package/dist/runtime/builtins/image/io.js +142 -0
  197. package/dist/runtime/builtins/image/planar.d.ts +55 -0
  198. package/dist/runtime/builtins/image/planar.js +274 -0
  199. package/dist/runtime/builtins/image/simplex.d.ts +22 -0
  200. package/dist/runtime/builtins/image/simplex.js +92 -0
  201. package/dist/runtime/builtins/image/text.d.ts +4 -0
  202. package/dist/runtime/builtins/image/text.js +141 -0
  203. package/dist/runtime/builtins/index.d.ts +3 -0
  204. package/dist/runtime/builtins/index.js +7 -0
  205. package/dist/runtime/gpu.d.ts +25 -0
  206. package/dist/runtime/gpu.js +40 -0
  207. package/dist/runtime/runtime.d.ts +2 -0
  208. package/dist/runtime/runtime.js +268 -44
  209. package/dist/runtime/types.d.ts +30 -0
  210. package/dist/stage.js +4 -1
  211. package/doc/CLI_REFERENCE.md +91 -2
  212. package/doc/EDITOR_EXPORT.md +37 -2
  213. package/doc/MCP.md +18 -1
  214. package/doc/NODE_REFERENCE.md +424 -10
  215. package/doc/PROJECT_AUTHORING.md +222 -7
  216. package/package.json +19 -4
  217. package/dist/assets/CodePanel-sY6sZa7B.js +0 -2
  218. package/dist/assets/CustomNodeDialog-BRKnqZhp.js +0 -1
  219. package/dist/assets/ExportDialog-C7dVGua4.js +0 -358
  220. package/dist/assets/ExportDialog-DOq0flMV.css +0 -1
  221. package/dist/assets/OpenGraphDialog-ZsgL-iwr.js +0 -1
  222. package/dist/assets/ProjectSettings-Cw17nNe3.js +0 -2
  223. package/dist/assets/definitions-DUww2Rt-.js +0 -1
  224. package/dist/assets/geo-C2RHOVHC.js +0 -1
  225. package/dist/assets/image-DR4oeyJB.js +0 -2062
  226. package/dist/assets/index-7vae6YFC.css +0 -1
  227. package/dist/assets/index-DyvDC6pS.js +0 -219
  228. package/dist/assets/math-DaDEgWKt.js +0 -1
  229. package/dist/assets/pop-pLH7L0PW.js +0 -1
@@ -0,0 +1,126 @@
1
+ import {
2
+ colorToCss,
3
+ normalizeColor,
4
+ readPixelsFromCanvas,
5
+ surface,
6
+ writePixels
7
+ } from "./chunk-WGKPJZDY.js";
8
+
9
+ // packages/runtime/src/builtins/image/text.ts
10
+ var FONT_FILE = /\.(otf|ttf|woff2?)$/i;
11
+ var HOST_KEY = "__cascadeImageHost";
12
+ var registered = /* @__PURE__ */ new Set();
13
+ function fingerprint(bytes) {
14
+ let hash = 2166136261;
15
+ for (let index = 0; index < bytes.length; index += 1) {
16
+ hash ^= bytes[index];
17
+ hash = Math.imul(hash, 16777619);
18
+ }
19
+ return `${bytes.length}-${(hash >>> 0).toString(16)}`;
20
+ }
21
+ async function fontFamily(context, font) {
22
+ const path = font.trim();
23
+ if (!FONT_FILE.test(path)) return font;
24
+ let bytes;
25
+ try {
26
+ const assets = context.capabilities.assets;
27
+ if (!assets) throw new Error("no assets");
28
+ bytes = await assets.read({ path }, { signal: context.signal });
29
+ } catch {
30
+ return "sans-serif";
31
+ }
32
+ const family = `cascade-font-${fingerprint(bytes)}`;
33
+ const globals = globalThis;
34
+ const host = globals[HOST_KEY];
35
+ const fonts = host ? null : globals.fonts ?? globals.document?.fonts;
36
+ const key = `${host ? `headless:${host.renderer}` : "browser"}:${family}`;
37
+ if (registered.has(key)) return family;
38
+ if (host && typeof host.registerFont === "function") {
39
+ await host.registerFont(family, bytes, {});
40
+ } else if (typeof globals.FontFace === "function" && fonts) {
41
+ const face = new globals.FontFace(family, bytes.slice().buffer);
42
+ fonts.add(await face.load());
43
+ } else {
44
+ return "sans-serif";
45
+ }
46
+ registered.add(key);
47
+ return family;
48
+ }
49
+ async function executeText(context) {
50
+ const { props } = context;
51
+ const [width, height] = [props.resolution[0], props.resolution[1]];
52
+ const color = normalizeColor(props.color);
53
+ const background = normalizeColor(props.backgroundColor);
54
+ const [offsetX, offsetY] = props.offset;
55
+ const { fontSize, alignH, alignV, rotation, letterSpacing } = props;
56
+ const family = await fontFamily(context, props.font);
57
+ const { canvas, context: ctx } = surface(width, height);
58
+ if (background.a > 0) {
59
+ ctx.fillStyle = colorToCss(background);
60
+ ctx.fillRect(0, 0, width, height);
61
+ } else {
62
+ ctx.clearRect(0, 0, width, height);
63
+ }
64
+ ctx.save();
65
+ ctx.globalAlpha = props.opacity;
66
+ ctx.font = `${props.fontStyle} ${props.fontWeight} ${fontSize}px ${family}`;
67
+ ctx.fillStyle = colorToCss(color);
68
+ const lines = props.text.split("\n");
69
+ const lineHeightPx = fontSize * props.lineHeight;
70
+ const totalTextHeight = lines.length * lineHeightPx;
71
+ let anchorX;
72
+ let anchorY;
73
+ switch (alignH) {
74
+ case "left":
75
+ ctx.textAlign = "left";
76
+ anchorX = 0;
77
+ break;
78
+ case "right":
79
+ ctx.textAlign = "right";
80
+ anchorX = width;
81
+ break;
82
+ default:
83
+ ctx.textAlign = "center";
84
+ anchorX = width / 2;
85
+ }
86
+ switch (alignV) {
87
+ case "top":
88
+ anchorY = fontSize;
89
+ break;
90
+ case "bottom":
91
+ anchorY = height - totalTextHeight + fontSize;
92
+ break;
93
+ default:
94
+ anchorY = (height - totalTextHeight) / 2 + fontSize;
95
+ }
96
+ anchorX += offsetX;
97
+ anchorY += offsetY;
98
+ if (rotation !== 0) {
99
+ const pivotY = anchorY - fontSize / 2 + totalTextHeight / 2;
100
+ ctx.translate(anchorX, pivotY);
101
+ ctx.rotate(rotation * Math.PI / 180);
102
+ ctx.translate(-anchorX, -pivotY);
103
+ }
104
+ if (letterSpacing !== 0) {
105
+ ctx.textAlign = "left";
106
+ lines.forEach((line, index) => {
107
+ const y = anchorY + index * lineHeightPx;
108
+ let lineWidth = 0;
109
+ for (const char of line) lineWidth += ctx.measureText(char).width + letterSpacing;
110
+ lineWidth -= letterSpacing;
111
+ let x = alignH === "left" ? anchorX : alignH === "right" ? anchorX - lineWidth : anchorX - lineWidth / 2;
112
+ for (const char of line) {
113
+ ctx.fillText(char, x, y);
114
+ x += ctx.measureText(char).width + letterSpacing;
115
+ }
116
+ });
117
+ } else {
118
+ lines.forEach((line, index) => ctx.fillText(line, anchorX, anchorY + index * lineHeightPx));
119
+ }
120
+ ctx.restore();
121
+ context.outputs.image.set(await writePixels(context, readPixelsFromCanvas(canvas)));
122
+ }
123
+ export {
124
+ executeText
125
+ };
126
+ //# sourceMappingURL=text-MB3EKR4H.js.map
@@ -0,0 +1,19 @@
1
+ import {
2
+ VERBS,
3
+ graphCommandsHelp,
4
+ graphOptions,
5
+ isGraphCommand,
6
+ mainHelp,
7
+ mcpTools,
8
+ verbFor
9
+ } from "./chunk-G23A2BZZ.js";
10
+ export {
11
+ VERBS,
12
+ graphCommandsHelp,
13
+ graphOptions,
14
+ isGraphCommand,
15
+ mainHelp,
16
+ mcpTools,
17
+ verbFor
18
+ };
19
+ //# sourceMappingURL=verbs-PI2JH5FI.js.map
@@ -0,0 +1,44 @@
1
+ import {
2
+ buildPlayer,
3
+ canonicalFuturePath,
4
+ exists,
5
+ inside,
6
+ installRoot,
7
+ playerFile,
8
+ staticRuntimePlugin
9
+ } from "./chunk-OM6BEME6.js";
10
+ import "./chunk-MP653A5O.js";
11
+ import "./chunk-MI5JLQYA.js";
12
+ import "./chunk-GRIN2DDP.js";
13
+ import "./chunk-X4WKAOQP.js";
14
+ import "./chunk-DEQSEFFH.js";
15
+ import "./chunk-RXDIMXN5.js";
16
+ import "./chunk-QQPA2ZHH.js";
17
+ import "./chunk-KH4MUBKF.js";
18
+ import "./chunk-HSNOBIVT.js";
19
+ import "./chunk-L6B6FUQP.js";
20
+ import "./chunk-HFHWYL55.js";
21
+ import "./chunk-KBGUO27Q.js";
22
+ import "./chunk-ICH7N5PN.js";
23
+ import "./chunk-CO22XHNG.js";
24
+ import "./chunk-LTXWBXOM.js";
25
+ import "./chunk-BZ63XQ3I.js";
26
+ import "./chunk-YH637PDL.js";
27
+ import "./chunk-X566FWBV.js";
28
+ import "./chunk-WD62JIP6.js";
29
+ import "./chunk-5ORUQ6ES.js";
30
+ import "./chunk-2JEU3MGB.js";
31
+ import "./chunk-NJFMDXHR.js";
32
+ import "./chunk-J7VK7MNF.js";
33
+ import "./chunk-FWMSGKEH.js";
34
+ import "./chunk-JVOCK5W4.js";
35
+ export {
36
+ buildPlayer,
37
+ canonicalFuturePath,
38
+ exists,
39
+ inside,
40
+ installRoot,
41
+ playerFile,
42
+ staticRuntimePlugin
43
+ };
44
+ //# sourceMappingURL=webBuild-WPPMGGW7.js.map
@@ -1,4 +1,4 @@
1
- import type { AssetRef, ImageRef, JsonValue } from "./values.js";
1
+ import type { AssetRef, ImagePixels, ImageRef, JsonValue } from "./values.js";
2
2
  export interface CascadeAbortSignal {
3
3
  readonly aborted: boolean;
4
4
  readonly reason?: unknown;
@@ -46,6 +46,23 @@ export interface AssetCapability {
46
46
  signal: CascadeAbortSignal;
47
47
  }): Promise<AssetRef>;
48
48
  resolveUrl?(ref: AssetRef | ImageRef): Promise<ResourceLease<string>>;
49
+ /**
50
+ * Store an intermediate image from its pixels. Optional; a host without it
51
+ * gets encoded bytes through `write`. The host chooses how: the headless
52
+ * host holds the pixels in memory and writes a fast lossless PNG behind
53
+ * (zlib level 1), or encodes that PNG at once when the run does not keep
54
+ * pixels. The returned path is content-addressed like `write`'s and is a
55
+ * whole file before anything reads it from disk. Finals are not encoded
56
+ * here: a run's saved outputs are encoded at full compression when copied.
57
+ */
58
+ keepImage?(pixels: ImagePixels, metadata: {
59
+ suggestedName?: string;
60
+ }, options: {
61
+ signal: CascadeAbortSignal;
62
+ }): Promise<AssetRef>;
63
+ /** The pixels behind a stored image while the host still holds them in
64
+ * memory, so a reader skips the read and the decode. */
65
+ imagePixels?(ref: AssetRef | ImageRef): ImagePixels | undefined;
49
66
  }
50
67
  export interface MediaCapability {
51
68
  decodeImage(ref: ImageRef | AssetRef, options: {
@@ -57,6 +57,14 @@ export declare const Color: Readonly<{
57
57
  alpha(color: Color): number;
58
58
  /** The same colour at full alpha. */
59
59
  opaque(color: Color): Color;
60
+ /**
61
+ * A colour saved in an older shape, as the one colour: `{ r, g, b, a? }`
62
+ * (the class-based image nodes stored that until 2026-11-07) or three
63
+ * components, with alpha 1. Components above 1 are read as 0–255, the way
64
+ * those nodes read them. Anything else comes back unchanged, so a reader can
65
+ * apply this to every stored `color` value and validate the result.
66
+ */
67
+ upgrade(value: unknown): unknown;
60
68
  /**
61
69
  * Four unit components from anything indexable, clamping and defaulting a
62
70
  * missing alpha to 1. The reader for a `Cd` attribute's flat array, and the
@@ -70,6 +70,29 @@ export const Color = Object.freeze({
70
70
  opaque(color) {
71
71
  return [clamp(color[0]), clamp(color[1]), clamp(color[2]), 1];
72
72
  },
73
+ /**
74
+ * A colour saved in an older shape, as the one colour: `{ r, g, b, a? }`
75
+ * (the class-based image nodes stored that until 2026-11-07) or three
76
+ * components, with alpha 1. Components above 1 are read as 0–255, the way
77
+ * those nodes read them. Anything else comes back unchanged, so a reader can
78
+ * apply this to every stored `color` value and validate the result.
79
+ */
80
+ upgrade(value) {
81
+ const legacy = value !== null && typeof value === "object" && !Array.isArray(value) && "r" in value && "g" in value && "b" in value
82
+ ? value
83
+ : Array.isArray(value) && value.length === 3
84
+ ? { r: value[0], g: value[1], b: value[2] }
85
+ : null;
86
+ if (!legacy)
87
+ return value;
88
+ const parts = [legacy.r, legacy.g, legacy.b, legacy.a ?? 1];
89
+ if (!parts.every((part) => typeof part === "number" && Number.isFinite(part)))
90
+ return value;
91
+ const numbers = parts;
92
+ const unit = numbers.slice(0, 3).every((part) => part <= 1);
93
+ const read = (part) => (unit ? part : part / 255);
94
+ return [read(numbers[0]), read(numbers[1]), read(numbers[2]), legacy.a === undefined ? 1 : read(numbers[3])];
95
+ },
73
96
  /**
74
97
  * Four unit components from anything indexable, clamping and defaulting a
75
98
  * missing alpha to 1. The reader for a `Cd` attribute's flat array, and the
@@ -190,6 +190,16 @@ export interface NodeDefinitionForEnvironment<E extends RuntimeEnvironment> {
190
190
  */
191
191
  readonly container?: "subnet" | "feedback";
192
192
  readonly capabilities?: readonly CapabilityForEnvironment<E>[];
193
+ /**
194
+ * GPU limits this node cannot run without, by WebGPU name, for a node that
195
+ * declares `gpu`: `{ maxStorageBufferBindingSize: 512 * 2 ** 20 }`. The host
196
+ * already asks for everything the adapter allows; this makes a GPU that
197
+ * allows less fail before the cook, naming the limit, instead of with a
198
+ * validation error from inside it. `max*` limits are minimums to reach,
199
+ * `min*Alignment` ones maximums. Read `context.capabilities.gpu.limits` for
200
+ * what the device actually gives.
201
+ */
202
+ readonly gpuLimits?: Readonly<Record<string, number>>;
193
203
  /**
194
204
  * `live` marks a node that reads data from outside the graph — an archive,
195
205
  * a CLI, a cache, body data, the filesystem or a network. `cascade export`
@@ -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
@@ -42,6 +42,13 @@ export interface EditorDeclaration {
42
42
  readonly panel?: EditorPanelDeclaration;
43
43
  /** The read-only stage view. On unless the author turns it off. */
44
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[];
45
52
  /**
46
53
  * Parameter ids a phone keeps in reach at the bottom sheet's lowest snap
47
54
  * point (the text, a Reroll). Defaults to the first text and seed parameters.
@@ -54,6 +61,16 @@ export interface EditorDeclaration {
54
61
  */
55
62
  readonly draft?: Readonly<Record<string, JsonValue>>;
56
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
+ }
57
74
  export type PublishedControl = "number" | "slider" | "int" | "bool" | "select" | "text" | "textarea" | "color" | "file" | "seed" | "vec2";
58
75
  export interface PublishedParameter {
59
76
  /** Scene key. Stable across renames of the node or the prop it targets. */
@@ -5,6 +5,7 @@ export * from "./capabilities.js";
5
5
  export * from "./color.js";
6
6
  export * from "./definition.js";
7
7
  export * from "./document.js";
8
+ export * from "./documentFormat.js";
8
9
  export * from "./editor.js";
9
10
  export * from "./geometry.js";
10
11
  export * from "./particles.js";
@@ -5,6 +5,7 @@ export * from "./capabilities.js";
5
5
  export * from "./color.js";
6
6
  export * from "./definition.js";
7
7
  export * from "./document.js";
8
+ export * from "./documentFormat.js";
8
9
  export * from "./editor.js";
9
10
  export * from "./geometry.js";
10
11
  export * from "./particles.js";
@@ -1,6 +1,6 @@
1
1
  export declare const nodeDefinitionSchema: {
2
- readonly allOf: readonly [Readonly<Record<string, unknown>>, Readonly<Record<string, unknown>>, Readonly<Record<string, unknown>>];
3
2
  readonly $schema: "https://json-schema.org/draft/2020-12/schema";
4
3
  readonly $id: "https://cascade.dev/schema/node-definition-v1.json";
4
+ readonly allOf: readonly [Readonly<Record<string, unknown>>, Readonly<Record<string, unknown>>, Readonly<Record<string, unknown>>];
5
5
  };
6
6
  //# sourceMappingURL=schema.d.ts.map
@@ -88,6 +88,7 @@ export const nodeDefinitionSchema = {
88
88
  items: { type: "string" },
89
89
  uniqueItems: true,
90
90
  },
91
+ gpuLimits: record({ type: "number", minimum: 0 }),
91
92
  label: description,
92
93
  description,
93
94
  icon: description,
@@ -19,7 +19,7 @@ export const CAPABILITIES_BY_ENVIRONMENT = {
19
19
  };
20
20
  const ALLOWED = CAPABILITIES_BY_ENVIRONMENT;
21
21
  const fields = (names) => new Set(names.split(" "));
22
- const TOP_FIELDS = fields("apiVersion runsOn container capabilities source label description icon inputs outputs props");
22
+ const TOP_FIELDS = fields("apiVersion runsOn container capabilities gpuLimits source label description icon inputs outputs props");
23
23
  const DATA_FIELDS = fields("kind type default description variadic min max step accept control options schema fields");
24
24
  const OUTPUT_FIELDS = fields("kind type description schema fields");
25
25
  const PROP_FIELDS = fields("type default label description min max step accept control options expression action");
@@ -111,6 +111,16 @@ export function validateNodeDefinition(value) {
111
111
  add("duplicate-capability", `${String(capability)} is duplicated`, path);
112
112
  seen.add(capability);
113
113
  }
114
+ if (value.gpuLimits !== undefined) {
115
+ if (!seen.has("gpu"))
116
+ add("gpu-limits-without-gpu", "gpuLimits needs the gpu capability", "gpuLimits");
117
+ if (!isRecord(value.gpuLimits))
118
+ add("invalid-gpu-limits", "gpuLimits must be an object of WebGPU limit names to numbers", "gpuLimits");
119
+ else
120
+ for (const [name, limit] of Object.entries(value.gpuLimits))
121
+ if (typeof limit !== "number" || !Number.isFinite(limit) || limit < 0)
122
+ add("invalid-gpu-limits", `gpuLimits.${name} must be a non-negative number`, `gpuLimits.${name}`);
123
+ }
114
124
  // Two namespaces, not one. An output is addressed in the other direction from
115
125
  // an input, so `geometry` in and `geometry` out is not ambiguous anywhere: the
116
126
  // document format names the two endpoints of a connection separately, the
@@ -51,6 +51,18 @@ export type Mat4 = readonly [
51
51
  number,
52
52
  number
53
53
  ];
54
+ /**
55
+ * The value on an `image` port: a path naming stored pixels, plus what they
56
+ * are. The port carries the reference, never the pixels, so a value stays
57
+ * small to snapshot, hash, trace and send to a Python stage.
58
+ *
59
+ * The path is always readable as a file by whoever needs a file. A host may
60
+ * still hold the pixels in memory and write the file behind (see
61
+ * {@link ImagePixels} and `AssetCapability.keepImage`): a reader in the same
62
+ * process gets the pixels without a decode, and the host makes the file whole
63
+ * before anything reads it from disk (a final copy, a Python stage, the end of
64
+ * a run).
65
+ */
54
66
  export interface ImageRef {
55
67
  readonly path: string;
56
68
  readonly size: Vec2i;
@@ -58,6 +70,18 @@ export interface ImageRef {
58
70
  readonly depth: "u8" | "u16" | "f16" | "f32";
59
71
  readonly space: "srgb" | "linear";
60
72
  }
73
+ /**
74
+ * An image's pixels in memory: 8-bit RGBA, sRGB, unpremultiplied, row-major
75
+ * with the top row first. This is the layout of `ImageData` and of a PNG's
76
+ * decoded rows, so handing pixels on in memory and handing them on through a
77
+ * PNG give the next node the same numbers.
78
+ */
79
+ export interface ImagePixels {
80
+ readonly width: number;
81
+ readonly height: number;
82
+ /** `width * height * 4` bytes. Owned by the host once kept: never mutate. */
83
+ readonly data: Uint8ClampedArray;
84
+ }
61
85
  declare const textureHandleBrand: unique symbol;
62
86
  export interface TextureHandle {
63
87
  readonly [textureHandleBrand]: true;