@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,92 @@
1
+ /**
2
+ * 2D simplex noise: `createNoise2D` and `buildPermutationTable` from
3
+ * simplex-noise 4.0.3 by Jonas Wagner (MIT), copied rather than depended on.
4
+ *
5
+ * The class `Noise` node loaded simplex-noise@latest from esm.sh at cook time,
6
+ * so it needed a network and could not run headless. The runtime depends on
7
+ * contracts alone, so the two functions it used live here, unchanged, and a
8
+ * seeded noise image is the same pixels it always was.
9
+ *
10
+ * Copyright (c) 2024 Jonas Wagner. Permission is hereby granted, free of
11
+ * charge, to any person obtaining a copy of this software and associated
12
+ * documentation files (the "Software"), to deal in the Software without
13
+ * restriction, including without limitation the rights to use, copy, modify,
14
+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
15
+ * and to permit persons to whom the Software is furnished to do so, subject to
16
+ * the following conditions: The above copyright notice and this permission
17
+ * notice shall be included in all copies or substantial portions of the
18
+ * Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
19
+ */
20
+ const SQRT3 = Math.sqrt(3.0);
21
+ const F2 = 0.5 * (SQRT3 - 1.0);
22
+ const G2 = (3.0 - SQRT3) / 6.0;
23
+ const fastFloor = (x) => Math.floor(x) | 0;
24
+ const grad2 = new Float64Array([1, 1, -1, 1, 1, -1, -1, -1, 1, 0, -1, 0, 1, 0, -1, 0, 0, 1, 0, -1, 0, 1, 0, -1]);
25
+ function buildPermutationTable(random) {
26
+ const tableSize = 512;
27
+ const p = new Uint8Array(tableSize);
28
+ for (let i = 0; i < tableSize / 2; i++)
29
+ p[i] = i;
30
+ for (let i = 0; i < tableSize / 2 - 1; i++) {
31
+ const r = i + ~~(random() * (256 - i));
32
+ const aux = p[i];
33
+ p[i] = p[r];
34
+ p[r] = aux;
35
+ }
36
+ for (let i = 256; i < tableSize; i++)
37
+ p[i] = p[i - 256];
38
+ return p;
39
+ }
40
+ export function createNoise2D(random) {
41
+ const perm = buildPermutationTable(random);
42
+ const permGrad2x = new Float64Array(perm).map((v) => grad2[(v % 12) * 2]);
43
+ const permGrad2y = new Float64Array(perm).map((v) => grad2[(v % 12) * 2 + 1]);
44
+ return function noise2D(x, y) {
45
+ let n0 = 0;
46
+ let n1 = 0;
47
+ let n2 = 0;
48
+ const s = (x + y) * F2;
49
+ const i = fastFloor(x + s);
50
+ const j = fastFloor(y + s);
51
+ const t = (i + j) * G2;
52
+ const X0 = i - t;
53
+ const Y0 = j - t;
54
+ const x0 = x - X0;
55
+ const y0 = y - Y0;
56
+ let i1, j1;
57
+ if (x0 > y0) {
58
+ i1 = 1;
59
+ j1 = 0;
60
+ }
61
+ else {
62
+ i1 = 0;
63
+ j1 = 1;
64
+ }
65
+ const x1 = x0 - i1 + G2;
66
+ const y1 = y0 - j1 + G2;
67
+ const x2 = x0 - 1.0 + 2.0 * G2;
68
+ const y2 = y0 - 1.0 + 2.0 * G2;
69
+ const ii = i & 255;
70
+ const jj = j & 255;
71
+ let t0 = 0.5 - x0 * x0 - y0 * y0;
72
+ if (t0 >= 0) {
73
+ const gi0 = ii + perm[jj];
74
+ t0 *= t0;
75
+ n0 = t0 * t0 * (permGrad2x[gi0] * x0 + permGrad2y[gi0] * y0);
76
+ }
77
+ let t1 = 0.5 - x1 * x1 - y1 * y1;
78
+ if (t1 >= 0) {
79
+ const gi1 = ii + i1 + perm[jj + j1];
80
+ t1 *= t1;
81
+ n1 = t1 * t1 * (permGrad2x[gi1] * x1 + permGrad2y[gi1] * y1);
82
+ }
83
+ let t2 = 0.5 - x2 * x2 - y2 * y2;
84
+ if (t2 >= 0) {
85
+ const gi2 = ii + 1 + perm[jj + 1];
86
+ t2 *= t2;
87
+ n2 = t2 * t2 * (permGrad2x[gi2] * x2 + permGrad2y[gi2] * y2);
88
+ }
89
+ return 70.0 * (n0 + n1 + n2);
90
+ };
91
+ }
92
+ //# sourceMappingURL=simplex.js.map
@@ -0,0 +1,4 @@
1
+ import type { NodeExecutionContext } from "@field/cascade/contracts";
2
+ import type { textDefinition } from "./definitions.js";
3
+ export declare function executeText(context: NodeExecutionContext<typeof textDefinition>): Promise<void>;
4
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1,141 @@
1
+ import { colorToCss, normalizeColor, readPixelsFromCanvas, surface, writePixels } from "./io.js";
2
+ /**
3
+ * `cascade.image.Text`: lines of text on a canvas, aligned to an anchor, with
4
+ * tracking, rotation and opacity.
5
+ *
6
+ * Fonts follow `cascade/image`'s rules. `font` is a CSS family list and draws
7
+ * with whatever faces the realm has (the page's or worker's in a browser,
8
+ * Skia's system fonts headless), so the same family only matches across hosts
9
+ * when both have the same face. A project font file (`.otf`, `.ttf`, `.woff`,
10
+ * `.woff2`) is read through `assets` and registered with the realm, which
11
+ * makes it match everywhere; a file that is not there falls back to
12
+ * `sans-serif` rather than failing, since a licensed face an export does not
13
+ * ship should still draw.
14
+ */
15
+ const FONT_FILE = /\.(otf|ttf|woff2?)$/i;
16
+ const HOST_KEY = "__cascadeImageHost";
17
+ // One registration per realm and font file contents; see `registerFont` in
18
+ // cascade/image, which this mirrors for a runtime that cannot import it.
19
+ const registered = new Set();
20
+ function fingerprint(bytes) {
21
+ let hash = 0x811c9dc5;
22
+ for (let index = 0; index < bytes.length; index += 1) {
23
+ hash ^= bytes[index];
24
+ hash = Math.imul(hash, 0x01000193);
25
+ }
26
+ return `${bytes.length}-${(hash >>> 0).toString(16)}`;
27
+ }
28
+ /** The family to draw with: `font` itself, or a registered face for a font file. */
29
+ async function fontFamily(context, font) {
30
+ const path = font.trim();
31
+ if (!FONT_FILE.test(path))
32
+ return font;
33
+ let bytes;
34
+ try {
35
+ const assets = context.capabilities.assets;
36
+ if (!assets)
37
+ throw new Error("no assets");
38
+ bytes = await assets.read({ path }, { signal: context.signal });
39
+ }
40
+ catch {
41
+ return "sans-serif";
42
+ }
43
+ const family = `cascade-font-${fingerprint(bytes)}`;
44
+ const globals = globalThis;
45
+ const host = globals[HOST_KEY];
46
+ const fonts = host ? null : globals.fonts ?? globals.document?.fonts;
47
+ const key = `${host ? `headless:${host.renderer}` : "browser"}:${family}`;
48
+ if (registered.has(key))
49
+ return family;
50
+ if (host && typeof host.registerFont === "function") {
51
+ await host.registerFont(family, bytes, {});
52
+ }
53
+ else if (typeof globals.FontFace === "function" && fonts) {
54
+ const face = new globals.FontFace(family, bytes.slice().buffer);
55
+ fonts.add(await face.load());
56
+ }
57
+ else {
58
+ return "sans-serif";
59
+ }
60
+ registered.add(key);
61
+ return family;
62
+ }
63
+ export async function executeText(context) {
64
+ const { props } = context;
65
+ const [width, height] = [props.resolution[0], props.resolution[1]];
66
+ const color = normalizeColor(props.color);
67
+ const background = normalizeColor(props.backgroundColor);
68
+ const [offsetX, offsetY] = props.offset;
69
+ const { fontSize, alignH, alignV, rotation, letterSpacing } = props;
70
+ const family = await fontFamily(context, props.font);
71
+ const { canvas, context: ctx } = surface(width, height);
72
+ if (background.a > 0) {
73
+ ctx.fillStyle = colorToCss(background);
74
+ ctx.fillRect(0, 0, width, height);
75
+ }
76
+ else {
77
+ ctx.clearRect(0, 0, width, height);
78
+ }
79
+ ctx.save();
80
+ ctx.globalAlpha = props.opacity;
81
+ ctx.font = `${props.fontStyle} ${props.fontWeight} ${fontSize}px ${family}`;
82
+ ctx.fillStyle = colorToCss(color);
83
+ const lines = props.text.split("\n");
84
+ const lineHeightPx = fontSize * props.lineHeight;
85
+ const totalTextHeight = lines.length * lineHeightPx;
86
+ let anchorX;
87
+ let anchorY;
88
+ switch (alignH) {
89
+ case "left":
90
+ ctx.textAlign = "left";
91
+ anchorX = 0;
92
+ break;
93
+ case "right":
94
+ ctx.textAlign = "right";
95
+ anchorX = width;
96
+ break;
97
+ default:
98
+ ctx.textAlign = "center";
99
+ anchorX = width / 2;
100
+ }
101
+ switch (alignV) {
102
+ case "top":
103
+ anchorY = fontSize;
104
+ break;
105
+ case "bottom":
106
+ anchorY = height - totalTextHeight + fontSize;
107
+ break;
108
+ default:
109
+ anchorY = (height - totalTextHeight) / 2 + fontSize;
110
+ }
111
+ anchorX += offsetX;
112
+ anchorY += offsetY;
113
+ if (rotation !== 0) {
114
+ const pivotY = anchorY - fontSize / 2 + totalTextHeight / 2;
115
+ ctx.translate(anchorX, pivotY);
116
+ ctx.rotate((rotation * Math.PI) / 180);
117
+ ctx.translate(-anchorX, -pivotY);
118
+ }
119
+ if (letterSpacing !== 0) {
120
+ // Tracking: one glyph at a time.
121
+ ctx.textAlign = "left";
122
+ lines.forEach((line, index) => {
123
+ const y = anchorY + index * lineHeightPx;
124
+ let lineWidth = 0;
125
+ for (const char of line)
126
+ lineWidth += ctx.measureText(char).width + letterSpacing;
127
+ lineWidth -= letterSpacing;
128
+ let x = alignH === "left" ? anchorX : alignH === "right" ? anchorX - lineWidth : anchorX - lineWidth / 2;
129
+ for (const char of line) {
130
+ ctx.fillText(char, x, y);
131
+ x += ctx.measureText(char).width + letterSpacing;
132
+ }
133
+ });
134
+ }
135
+ else {
136
+ lines.forEach((line, index) => ctx.fillText(line, anchorX, anchorY + index * lineHeightPx));
137
+ }
138
+ ctx.restore();
139
+ context.outputs.image.set(await writePixels(context, readPixelsFromCanvas(canvas)));
140
+ }
141
+ //# sourceMappingURL=text.js.map
@@ -6,6 +6,9 @@ import type { DefinitionNodeRegistration } from "../types.js";
6
6
  * set — which speaks the same `geometry` type as `geo`, so any of its outputs
7
7
  * fits any geometry node's input. `cascade.scene.*` is the assembly: geometry
8
8
  * plus a viewpoint plus lights, which is what the Viewer's 3D mode renders.
9
+ * `cascade.image.*` makes and filters images, and `cascade.assert.*` fails a
10
+ * run whose result is wrong. Those two load their bodies lazily: this list is
11
+ * in Studio's first-paint bundle.
9
12
  */
10
13
  export declare const builtinNodeRegistrations: readonly DefinitionNodeRegistration[];
11
14
  export declare function builtinNodeRegistration(moduleId: string): DefinitionNodeRegistration | undefined;
@@ -1,5 +1,7 @@
1
+ import { assertNodeRegistrations } from "./assert/index.js";
1
2
  import { coreNodeRegistrations } from "./core/index.js";
2
3
  import { geoNodeRegistrations } from "./geo/index.js";
4
+ import { imageNodeRegistrations } from "./image/index.js";
3
5
  import { mathNodeRegistrations } from "./math/index.js";
4
6
  import { popNodeRegistrations } from "./pop/index.js";
5
7
  import { sceneNodeRegistrations } from "./scene/index.js";
@@ -10,6 +12,9 @@ import { sceneNodeRegistrations } from "./scene/index.js";
10
12
  * set — which speaks the same `geometry` type as `geo`, so any of its outputs
11
13
  * fits any geometry node's input. `cascade.scene.*` is the assembly: geometry
12
14
  * plus a viewpoint plus lights, which is what the Viewer's 3D mode renders.
15
+ * `cascade.image.*` makes and filters images, and `cascade.assert.*` fails a
16
+ * run whose result is wrong. Those two load their bodies lazily: this list is
17
+ * in Studio's first-paint bundle.
13
18
  */
14
19
  export const builtinNodeRegistrations = Object.freeze([
15
20
  ...coreNodeRegistrations,
@@ -17,6 +22,8 @@ export const builtinNodeRegistrations = Object.freeze([
17
22
  ...mathNodeRegistrations,
18
23
  ...popNodeRegistrations,
19
24
  ...sceneNodeRegistrations,
25
+ ...imageNodeRegistrations,
26
+ ...assertNodeRegistrations,
20
27
  ]);
21
28
  const registrationsById = new Map(builtinNodeRegistrations.map((registration) => [
22
29
  registration.moduleId,
@@ -28,6 +28,31 @@ export interface GpuHost extends GpuCapability {
28
28
  }
29
29
  export declare function isGpuHost(value: unknown): value is GpuHost;
30
30
  export declare function createGpuHost(options: GpuHostOptions): GpuHost;
31
+ interface LimitedAdapter {
32
+ readonly limits: unknown;
33
+ requestDevice(descriptor?: {
34
+ requiredLimits?: Record<string, number>;
35
+ }): Promise<GpuCapability["device"]>;
36
+ }
37
+ /**
38
+ * The host's one device, asked for with everything the adapter allows.
39
+ *
40
+ * A bare `requestDevice()` gets WebGPU's defaults (128 MiB per storage binding,
41
+ * 256 invocations, 16 KiB workgroup storage, 8 storage buffers per stage)
42
+ * whatever the hardware is, and the device is shared, so a node cannot ask for
43
+ * more later. Brand + Design chunked a ribbon into four accumulator buffers on
44
+ * an M3 Max for that reason (3 Nov 2026). Should an adapter refuse its own
45
+ * ceiling, the defaults are better than no device; a node that needs more
46
+ * says so with `gpuLimits` and gets {@link gpuLimitShortfall}'s message.
47
+ */
48
+ export declare function requestDeviceWithAdapterLimits(adapter: LimitedAdapter): Promise<GpuCapability["device"]>;
49
+ /**
50
+ * What a node's declared `gpuLimits` asks for that this device does not give,
51
+ * as one sentence, or null when it all fits. `max*` limits must reach the
52
+ * value; `min*Alignment` limits must be at most it (smaller is better there).
53
+ */
54
+ export declare function gpuLimitShortfall(label: string, required: Readonly<Record<string, number>> | undefined, gpu: Pick<GpuCapability, "limits" | "adapterInfo">): string | null;
31
55
  /** Getter-backed supported-limits objects cannot be normalized with spread. */
32
56
  export declare function readGpuLimits(source: unknown): Record<string, number>;
57
+ export {};
33
58
  //# sourceMappingURL=gpu.d.ts.map
@@ -196,6 +196,46 @@ export function createGpuHost(options) {
196
196
  }
197
197
  return host;
198
198
  }
199
+ /**
200
+ * The host's one device, asked for with everything the adapter allows.
201
+ *
202
+ * A bare `requestDevice()` gets WebGPU's defaults (128 MiB per storage binding,
203
+ * 256 invocations, 16 KiB workgroup storage, 8 storage buffers per stage)
204
+ * whatever the hardware is, and the device is shared, so a node cannot ask for
205
+ * more later. Brand + Design chunked a ribbon into four accumulator buffers on
206
+ * an M3 Max for that reason (3 Nov 2026). Should an adapter refuse its own
207
+ * ceiling, the defaults are better than no device; a node that needs more
208
+ * says so with `gpuLimits` and gets {@link gpuLimitShortfall}'s message.
209
+ */
210
+ export async function requestDeviceWithAdapterLimits(adapter) {
211
+ const requiredLimits = readGpuLimits(adapter.limits);
212
+ try {
213
+ return await adapter.requestDevice({ requiredLimits });
214
+ }
215
+ catch {
216
+ return adapter.requestDevice();
217
+ }
218
+ }
219
+ /**
220
+ * What a node's declared `gpuLimits` asks for that this device does not give,
221
+ * as one sentence, or null when it all fits. `max*` limits must reach the
222
+ * value; `min*Alignment` limits must be at most it (smaller is better there).
223
+ */
224
+ export function gpuLimitShortfall(label, required, gpu) {
225
+ if (!required)
226
+ return null;
227
+ const short = [];
228
+ for (const [name, wanted] of Object.entries(required)) {
229
+ const have = gpu.limits[name];
230
+ const fits = have !== undefined && (name.startsWith("min") ? have <= wanted : have >= wanted);
231
+ if (!fits)
232
+ short.push(`${name} ${wanted} (this GPU: ${have ?? "not reported"})`);
233
+ }
234
+ if (!short.length)
235
+ return null;
236
+ const adapter = gpu.adapterInfo.description || gpu.adapterInfo.device || gpu.adapterInfo.vendor || "this adapter";
237
+ return `${label} needs GPU limits ${adapter} does not allow: ${short.join(", ")}.`;
238
+ }
199
239
  /** Getter-backed supported-limits objects cannot be normalized with spread. */
200
240
  export function readGpuLimits(source) {
201
241
  if (!source || typeof source !== "object")
@@ -42,4 +42,6 @@ import type { CascadeRuntime, CreateRuntimeOptions } from "./types.js";
42
42
  */
43
43
  export declare const PREFLIGHT_WARNING_CODES: ReadonlySet<string>;
44
44
  export declare function createRuntime(options: CreateRuntimeOptions): CascadeRuntime;
45
+ /** How many plain arrays/objects the runtime has copied in this process. */
46
+ export declare function runtimeValueCopies(): number;
45
47
  //# sourceMappingURL=runtime.d.ts.map