@field/cascade 0.11.0 → 0.13.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 (220) hide show
  1. package/AGENTS.md +8 -5
  2. package/ARCHITECTURE.md +5 -4
  3. package/CHANGELOG.md +245 -0
  4. package/README.md +1 -1
  5. package/dist/assets/AgentPanel-1JugFjE4.css +1 -0
  6. package/dist/assets/AgentPanel-BDL5MddA.js +5 -0
  7. package/dist/assets/{CodeEditor-4O7FQ__R.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-Bz8JxISH.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-D5Z0nJ5-.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-Yqi0Ni61.js → core-DB-MkGjj.js} +3 -4
  28. package/dist/assets/coreTypes-DtnDATZ7.js +1 -0
  29. package/dist/assets/{cssMode-CxUzc4vp.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-BNFb25CX.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-0ZDnWxeM.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-Cy18MoaD.js → handlebars-CcD3aMeL.js} +1 -1
  41. package/dist/assets/{html-B-2Dx7nq.js → html-DvZWGfqb.js} +1 -1
  42. package/dist/assets/{htmlMode-DUAc9B_d.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-DeQsDqP5.js → javascript-Cap2ahgh.js} +1 -1
  49. package/dist/assets/{jsonMode-BiFwJVSk.js → jsonMode-B0uLjp9C.js} +1 -1
  50. package/dist/assets/{liquid-BLoHH68a.js → liquid-CnxwhfLn.js} +1 -1
  51. package/dist/assets/{lspLanguageFeatures-CNFgm1Kv.js → lspLanguageFeatures-Dn9hlKX6.js} +1 -1
  52. package/dist/assets/math-GeULS-sk.js +1 -0
  53. package/dist/assets/{mdx-CFXQVNfs.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-Cf7S7p2E.js → python-CGyFk4XK.js} +1 -1
  57. package/dist/assets/{razor-CMHBcG-g.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-BEih0GDj.js → tsMode-BOeXzO9H.js} +1 -1
  64. package/dist/assets/{typescript-COEKYD_a.js → typescript-J1SnE_Tu.js} +1 -1
  65. package/dist/assets/{workers-BNhAhMNn.js → workers-CYwwTiVF.js} +1 -1
  66. package/dist/assets/{xml-CPiMpnPl.js → xml-DnPRNzK9.js} +1 -1
  67. package/dist/assets/{yaml-Bgp1ITLR.js → yaml-BmmYBNa9.js} +1 -1
  68. package/dist/cli/DefinitionNode-P7AA4TAU.js +15 -0
  69. package/dist/cli/{Graph-ZJJTRQTM.js → Graph-OB6EWSGL.js} +12 -12
  70. package/dist/cli/assert-GROGQNCQ.js +25 -0
  71. package/dist/cli/checks-3WB44XBL.js +189 -0
  72. package/dist/cli/{chunk-3JTJHF7V.js → chunk-2L34ERS2.js} +4 -4
  73. package/dist/cli/chunk-53LGFPWX.js +138 -0
  74. package/dist/cli/chunk-5ORUQ6ES.js +267 -0
  75. package/dist/cli/{chunk-YAT5Y25U.js → chunk-7QE2ZNSN.js} +3 -3
  76. package/dist/cli/{chunk-SGJAET2L.js → chunk-BPODRH52.js} +8 -4
  77. package/dist/cli/{chunk-XWDSKG7N.js → chunk-BZ63XQ3I.js} +2 -2
  78. package/dist/cli/{chunk-FCDXJ6EK.js → chunk-CTPLRSWF.js} +2 -13
  79. package/dist/cli/{chunk-WIH4TEIS.js → chunk-EZRWJ4G2.js} +1 -1
  80. package/dist/cli/{chunk-BIJO5OFS.js → chunk-FWMSGKEH.js} +1 -1
  81. package/dist/cli/{chunk-POMMNKZZ.js → chunk-G23A2BZZ.js} +38 -5
  82. package/dist/cli/{chunk-35D343DC.js → chunk-GRIN2DDP.js} +19 -1
  83. package/dist/cli/{chunk-WKURDVYP.js → chunk-JEW5MPGI.js} +28 -331
  84. package/dist/cli/chunk-JVOCK5W4.js +83 -0
  85. package/dist/cli/chunk-KBGUO27Q.js +15 -0
  86. package/dist/cli/{chunk-GFS6W3C5.js → chunk-L6B6FUQP.js} +54 -32
  87. package/dist/cli/chunk-LTXWBXOM.js +438 -0
  88. package/dist/cli/chunk-MI5JLQYA.js +220 -0
  89. package/dist/cli/{chunk-A4OAMOZH.js → chunk-NJFMDXHR.js} +13 -3
  90. package/dist/cli/{chunk-DUIUFVU2.js → chunk-OBZAP3GG.js} +49 -23
  91. package/dist/cli/chunk-QAGATJGE.js +336 -0
  92. package/dist/cli/{chunk-EUIAC3U3.js → chunk-QKL7CCRS.js} +966 -132
  93. package/dist/cli/{chunk-RLCAJBVR.js → chunk-TJW67QSI.js} +8 -7
  94. package/dist/cli/{chunk-RQZ4SX5R.js → chunk-W5PJ5RMP.js} +156 -84
  95. package/dist/cli/chunk-W7OUAT7J.js +122 -0
  96. package/dist/cli/chunk-WGKPJZDY.js +364 -0
  97. package/dist/cli/{chunk-D6BUOHUG.js → chunk-X4WKAOQP.js} +4 -4
  98. package/dist/cli/{chunk-VVGSLVSF.js → chunk-X566FWBV.js} +6 -1
  99. package/dist/cli/chunk-YH637PDL.js +317 -0
  100. package/dist/cli/chunk-ZSCUZE6I.js +112 -0
  101. package/dist/cli/{cliCommands-UQSFGEHF.js → cliCommands-XVFRD7CF.js} +23 -17
  102. package/dist/cli/{commands-Q23M26QM.js → commands-M2XLTPTZ.js} +129 -47
  103. package/dist/cli/contactSheet-2PQVRUFW.js +11 -0
  104. package/dist/cli/{definitions-HF2FTHYU.js → definitions-BPOPW52L.js} +7 -7
  105. package/dist/cli/{doctorCommand-B7BPQMN6.js → doctorCommand-RAEI7GVY.js} +36 -6
  106. package/dist/cli/{edit-JHCPTQFT.js → edit-S5KEQ5RA.js} +3 -3
  107. package/dist/cli/editorCommands-5BBG4S6V.js +41 -0
  108. package/dist/cli/{encode-HAUZTYPT.js → encode-ICPEPMH5.js} +2 -2
  109. package/dist/cli/file-3HTQHPYQ.js +41 -0
  110. package/dist/cli/filters-6ODFWYK4.js +379 -0
  111. package/dist/cli/generators-YU7GB4MD.js +210 -0
  112. package/dist/cli/{geo-4RNK3QVN.js → geo-6ZPGKZRU.js} +7 -7
  113. package/dist/cli/{graphCommands-6BMAKGQE.js → graphCommands-MULQ7VD2.js} +4 -4
  114. package/dist/cli/{graphFile-VPSQ6OF7.js → graphFile-CITF36ZM.js} +25 -19
  115. package/dist/cli/{headlessCanvas-5XLDZT7M.js → headlessCanvas-ENRHC7GS.js} +3 -2
  116. package/dist/cli/{helpCommand-3VRE3KVO.js → helpCommand-X2QDANM3.js} +9 -7
  117. package/dist/cli/image-TXELZZK5.js +55 -0
  118. package/dist/cli/index.js +14 -14
  119. package/dist/cli/{math-ZRMLKU2D.js → math-RSYRQ3C6.js} +5 -5
  120. package/dist/cli/{mcp-ZLEEMYGF.js → mcp-YRIGRLYQ.js} +4 -4
  121. package/dist/cli/{parity-KINARCP2.js → parity-3N3HTKWX.js} +42 -36
  122. package/dist/cli/{pop-USDFXB7H.js → pop-B7SIIYKN.js} +5 -5
  123. package/dist/cli/project-SJF5ZF3F.js +12 -0
  124. package/dist/cli/{projectDefinition-DMTZN2NE.js → projectDefinition-F3D7UIHJ.js} +8 -8
  125. package/dist/cli/{projectRuntime-Z5PJOH47.js → projectRuntime-NY4XMDFH.js} +19 -12
  126. package/dist/cli/registerStandardNodes-BXJCB6E4.js +744 -0
  127. package/dist/cli/{render-YURAPPUI.js → render-Y23W6MY6.js} +29 -22
  128. package/dist/cli/{runCommand-PI764LEG.js → runCommand-XOG7AVC5.js} +3 -3
  129. package/dist/cli/runner-DNJO5WO2.js +43 -0
  130. package/dist/cli/runtime/image.ts +27 -2
  131. package/dist/cli/runtime/io.ts +78 -0
  132. package/dist/cli/share-B7HTCOJX.js +166 -0
  133. package/dist/cli/stageCache-TY2BFZJR.js +15 -0
  134. package/dist/cli/{stageRunner-KUNIMQKJ.js → stageRunner-KY2EJP7X.js} +2 -2
  135. package/dist/cli/text-MB3EKR4H.js +126 -0
  136. package/dist/cli/{verbs-RCE3K4VQ.js → verbs-PI2JH5FI.js} +2 -2
  137. package/dist/cli/webBuild-2K4COCGY.js +44 -0
  138. package/dist/contracts/capabilities.d.ts +39 -1
  139. package/dist/contracts/color.d.ts +8 -0
  140. package/dist/contracts/color.js +23 -0
  141. package/dist/contracts/definition.d.ts +10 -0
  142. package/dist/contracts/schema.d.ts +1 -1
  143. package/dist/contracts/schema.js +1 -0
  144. package/dist/contracts/validate.js +11 -1
  145. package/dist/contracts/values.d.ts +24 -0
  146. package/dist/image.d.ts +15 -0
  147. package/dist/image.js +36 -2
  148. package/dist/index.html +8 -2
  149. package/dist/io.d.ts +29 -0
  150. package/dist/io.js +40 -0
  151. package/dist/player/app.js +11 -7
  152. package/dist/player/editor.js +3 -2
  153. package/dist/player/editorEngine.js +3 -2
  154. package/dist/player/embed.js +2 -0
  155. package/dist/player/types.d.ts +6 -0
  156. package/dist/runtime/builtins/assert/checks.d.ts +18 -0
  157. package/dist/runtime/builtins/assert/checks.js +207 -0
  158. package/dist/runtime/builtins/assert/definitions.d.ts +130 -0
  159. package/dist/runtime/builtins/assert/definitions.js +54 -0
  160. package/dist/runtime/builtins/assert/index.d.ts +152 -0
  161. package/dist/runtime/builtins/assert/index.js +36 -0
  162. package/dist/runtime/builtins/image/contactSheet.d.ts +3 -165
  163. package/dist/runtime/builtins/image/contactSheet.js +0 -49
  164. package/dist/runtime/builtins/image/definitions.d.ts +950 -0
  165. package/dist/runtime/builtins/image/definitions.js +343 -0
  166. package/dist/runtime/builtins/image/file.d.ts +8 -0
  167. package/dist/runtime/builtins/image/file.js +37 -0
  168. package/dist/runtime/builtins/image/filters.d.ts +8 -0
  169. package/dist/runtime/builtins/image/filters.js +394 -0
  170. package/dist/runtime/builtins/image/generators.d.ts +7 -0
  171. package/dist/runtime/builtins/image/generators.js +144 -0
  172. package/dist/runtime/builtins/image/index.d.ts +947 -4
  173. package/dist/runtime/builtins/image/index.js +41 -6
  174. package/dist/runtime/builtins/image/io.d.ts +100 -0
  175. package/dist/runtime/builtins/image/io.js +142 -0
  176. package/dist/runtime/builtins/image/planar.d.ts +55 -0
  177. package/dist/runtime/builtins/image/planar.js +274 -0
  178. package/dist/runtime/builtins/image/simplex.d.ts +22 -0
  179. package/dist/runtime/builtins/image/simplex.js +92 -0
  180. package/dist/runtime/builtins/image/text.d.ts +4 -0
  181. package/dist/runtime/builtins/image/text.js +141 -0
  182. package/dist/runtime/builtins/index.d.ts +3 -0
  183. package/dist/runtime/builtins/index.js +7 -0
  184. package/dist/runtime/definition/architecture.js +89 -0
  185. package/dist/runtime/gpu.d.ts +25 -0
  186. package/dist/runtime/gpu.js +40 -0
  187. package/dist/runtime/runtime.d.ts +2 -0
  188. package/dist/runtime/runtime.js +268 -44
  189. package/dist/runtime/types.d.ts +30 -0
  190. package/doc/CLI_REFERENCE.md +21 -3
  191. package/doc/EDITOR_EXPORT.md +26 -0
  192. package/doc/MCP.md +2 -1
  193. package/doc/NODE_REFERENCE.md +286 -14
  194. package/doc/PROJECT_AUTHORING.md +158 -4
  195. package/doc/WEB_PLAYER.md +9 -1
  196. package/package.json +4 -1
  197. package/dist/assets/CodePanel-BU-autmq.js +0 -2
  198. package/dist/assets/CustomNodeDialog-BRpDfOV5.js +0 -1
  199. package/dist/assets/OpenGraphDialog-BwbRlC0X.js +0 -1
  200. package/dist/assets/ProjectSettings-DLOXLxcA.js +0 -2
  201. package/dist/assets/definitions-GreEMXLV.js +0 -1
  202. package/dist/assets/geo-u0n_jOsD.js +0 -1
  203. package/dist/assets/image-cAa-Nu9O.js +0 -2062
  204. package/dist/assets/index-5ZtDAuy2.js +0 -220
  205. package/dist/assets/index-7vae6YFC.css +0 -1
  206. package/dist/assets/math-DioIQOPJ.js +0 -1
  207. package/dist/assets/pop-DC_TQG9t.js +0 -1
  208. package/dist/cli/chunk-36P5K3SD.js +0 -631
  209. package/dist/cli/chunk-4UDFYF5G.js +0 -132
  210. package/dist/cli/chunk-53NMBJAO.js +0 -35
  211. package/dist/cli/chunk-MIIEFUGG.js +0 -623
  212. package/dist/cli/chunk-QBBKRNGY.js +0 -90
  213. package/dist/cli/chunk-WPUDGEFY.js +0 -20
  214. package/dist/cli/editorCommands-UIF5YLUZ.js +0 -33
  215. package/dist/cli/project-K3QIPGBB.js +0 -12
  216. package/dist/cli/registerStandardNodes-S2VLMF6J.js +0 -3081
  217. package/dist/cli/runner-RA6UKEPD.js +0 -37
  218. package/dist/cli/webBuild-GT4PZT5D.js +0 -37
  219. package/dist/runtime/builtins/headless.d.ts +0 -19
  220. package/dist/runtime/builtins/headless.js +0 -25
@@ -1,9 +1,44 @@
1
- import { contactSheetRegistration } from "./contactSheet.js";
1
+ import { blurDefinition, checkersDefinition, colorDefinition, compositeDefinition, contactSheetDefinition, imageDefinition, noiseDefinition, normalMapDefinition, rampDefinition, resizeDefinition, textDefinition, transformDefinition, } from "./definitions.js";
2
2
  /**
3
- * The definition-v1 image nodes. One so far: the contact sheet a ladder of
4
- * variants is judged on. Studio's `cascade.image.*` library (src/nodes/image)
5
- * is the compatibility engine's and is not listed here.
3
+ * `cascade.image.*`: the image library, in every host.
4
+ *
5
+ * Eleven nodes were Studio classes over `ImageNodeBase` until 2026-11-07, when
6
+ * Marcus decided to port them (round 1 decision 4); the twelfth, the contact
7
+ * sheet, was the first definition-v1 node here. The declarations are literal
8
+ * and small, because this list sits in Studio's first-paint bundle with every
9
+ * other built-in; each body loads behind a dynamic import the first time a node
10
+ * of that kind cooks, so Studio pays for a node's pixel loop only when a graph
11
+ * uses it. (`cascade ladder` imports the contact sheet's layout and drawing
12
+ * from `contactSheet.ts` directly, for the same reason.)
6
13
  */
7
- export { composeContactSheet, contactSheetDefinition, contactSheetLayout, contactSheetRegistration, executeContactSheet, } from "./contactSheet.js";
8
- export const imageNodeRegistrations = Object.freeze([contactSheetRegistration]);
14
+ export * from "./definitions.js";
15
+ function lazy(name, definition, load) {
16
+ return { kind: "definition-v1", moduleId: `cascade.image.${name}`, definition, loadExecute: load };
17
+ }
18
+ export const contactSheetRegistration = lazy("ContactSheet", contactSheetDefinition, async () => (await import("./contactSheet.js")).executeContactSheet);
19
+ export const colorRegistration = lazy("Color", colorDefinition, async () => (await import("./generators.js")).executeColor);
20
+ export const checkersRegistration = lazy("Checkers", checkersDefinition, async () => (await import("./generators.js")).executeCheckers);
21
+ export const noiseRegistration = lazy("Noise", noiseDefinition, async () => (await import("./generators.js")).executeNoise);
22
+ export const rampRegistration = lazy("Ramp", rampDefinition, async () => (await import("./generators.js")).executeRamp);
23
+ export const textRegistration = lazy("Text", textDefinition, async () => (await import("./text.js")).executeText);
24
+ export const imageRegistration = lazy("Image", imageDefinition, async () => (await import("./file.js")).executeImage);
25
+ export const blurRegistration = lazy("Blur", blurDefinition, async () => (await import("./filters.js")).executeBlur);
26
+ export const normalMapRegistration = lazy("NormalMap", normalMapDefinition, async () => (await import("./filters.js")).executeNormalMap);
27
+ export const resizeRegistration = lazy("Resize", resizeDefinition, async () => (await import("./filters.js")).executeResize);
28
+ export const transformRegistration = lazy("Transform", transformDefinition, async () => (await import("./filters.js")).executeTransform);
29
+ export const compositeRegistration = lazy("Composite", compositeDefinition, async () => (await import("./filters.js")).executeComposite);
30
+ export const imageNodeRegistrations = Object.freeze([
31
+ colorRegistration,
32
+ checkersRegistration,
33
+ noiseRegistration,
34
+ rampRegistration,
35
+ textRegistration,
36
+ imageRegistration,
37
+ blurRegistration,
38
+ normalMapRegistration,
39
+ resizeRegistration,
40
+ transformRegistration,
41
+ compositeRegistration,
42
+ contactSheetRegistration,
43
+ ]);
9
44
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,100 @@
1
+ import type { AssetCapability, CascadeAbortSignal, ImagePixels, ImageRef } from "@field/cascade/contracts";
2
+ import { Planar, type RGBA } from "./planar.js";
3
+ /**
4
+ * How a `cascade.image.*` node reads and writes an image: the in-memory image
5
+ * contract ("How an image travels between nodes" in doc/PROJECT_AUTHORING.md),
6
+ * for built-ins that cannot import `cascade/image` (the runtime depends on
7
+ * contracts alone).
8
+ *
9
+ * In: the host's pixels when it still holds them (`assets.imagePixels`), else
10
+ * the stored bytes decoded with the realm's `createImageBitmap` and read back
11
+ * off an `OffscreenCanvas`. Out: the pixels to `assets.keepImage` when the
12
+ * host keeps images in memory (`cascade run`/`render`, Studio), else a PNG
13
+ * through `assets.write` (an exported editor, the web player).
14
+ */
15
+ export interface ImageNodeContext {
16
+ readonly nodeId: string;
17
+ readonly capabilities: {
18
+ readonly assets?: AssetCapability;
19
+ };
20
+ readonly signal: CascadeAbortSignal;
21
+ }
22
+ interface Bitmap {
23
+ readonly width: number;
24
+ readonly height: number;
25
+ close?(): void;
26
+ }
27
+ export interface Context2D {
28
+ fillStyle: unknown;
29
+ font: string;
30
+ textAlign: string;
31
+ globalAlpha: number;
32
+ fillRect(x: number, y: number, width: number, height: number): void;
33
+ clearRect(x: number, y: number, width: number, height: number): void;
34
+ save(): void;
35
+ restore(): void;
36
+ translate(x: number, y: number): void;
37
+ rotate(angle: number): void;
38
+ fillText(text: string, x: number, y: number): void;
39
+ measureText(text: string): {
40
+ width: number;
41
+ };
42
+ drawImage(image: Bitmap, x: number, y: number): void;
43
+ getImageData(x: number, y: number, width: number, height: number): {
44
+ data: Uint8ClampedArray;
45
+ };
46
+ putImageData(data: unknown, x: number, y: number): void;
47
+ }
48
+ interface Surface {
49
+ readonly width: number;
50
+ readonly height: number;
51
+ getContext(kind: "2d", options?: {
52
+ willReadFrequently?: boolean;
53
+ }): Context2D | null;
54
+ convertToBlob(options?: {
55
+ type?: string;
56
+ }): Promise<{
57
+ arrayBuffer(): Promise<ArrayBuffer>;
58
+ }>;
59
+ }
60
+ /**
61
+ * A CPU-backed 2D surface. `willReadFrequently` keeps a browser on the
62
+ * software rasteriser the headless host also uses, as `cascade/image` does.
63
+ */
64
+ export declare function surface(width: number, height: number): {
65
+ canvas: Surface;
66
+ context: Context2D;
67
+ };
68
+ /** An image input, an asset or a project path, as the reference to read. */
69
+ export declare function imageReference(value: unknown): {
70
+ path: string;
71
+ } | null;
72
+ /** Decode stored bytes to 8-bit RGBA through the realm's canvas. */
73
+ export declare function decodePixels(bytes: Uint8Array): Promise<ImagePixels>;
74
+ /** A whole canvas's pixels. */
75
+ export declare function readPixelsFromCanvas(canvas: Surface): ImagePixels;
76
+ export declare function readPixels(context: ImageNodeContext, ref: {
77
+ path: string;
78
+ }): Promise<ImagePixels>;
79
+ /** An image input as a `Planar`, or null when nothing is wired. */
80
+ export declare function readPlanar(context: ImageNodeContext, value: unknown): Promise<Planar | null>;
81
+ /** Store pixels as this node's image output and return the value to set. */
82
+ export declare function writePixels(context: ImageNodeContext, pixels: ImagePixels): Promise<ImageRef>;
83
+ /** Set a node's `image` output from a `Planar`. */
84
+ export declare function output(context: ImageNodeContext & {
85
+ readonly outputs: {
86
+ readonly image: {
87
+ set(value: ImageRef): void;
88
+ };
89
+ };
90
+ }, image: Planar): Promise<void>;
91
+ /**
92
+ * A colour in any of the shapes the class library accepted: `[r, g, b, a]`
93
+ * (Cascade's one colour), the older `{ r, g, b, a }`, 0–255 components, or a
94
+ * CSS `rgb()` / hex string. Saved graphs hold all of them.
95
+ */
96
+ export declare function normalizeColor(input: unknown): Required<RGBA>;
97
+ /** `rgb(r,g,b)`, or `rgba(r,g,b,a)` below full alpha, for `fillStyle`. */
98
+ export declare function colorToCss(color: RGBA): string;
99
+ export {};
100
+ //# sourceMappingURL=io.d.ts.map
@@ -0,0 +1,142 @@
1
+ import { Planar } from "./planar.js";
2
+ const NO_CANVAS = "cascade.image: this host has no canvas. In a browser this needs OffscreenCanvas; headless, Cascade installs " +
3
+ '@napi-rs/canvas before a run (install it with "npm install @napi-rs/canvas" if it is missing).';
4
+ /** The host's canvas, read here and nowhere else (see `cascade.geo.Render`). */
5
+ function canvasGlobals() {
6
+ return globalThis;
7
+ }
8
+ /**
9
+ * A CPU-backed 2D surface. `willReadFrequently` keeps a browser on the
10
+ * software rasteriser the headless host also uses, as `cascade/image` does.
11
+ */
12
+ export function surface(width, height) {
13
+ const Canvas = canvasGlobals().OffscreenCanvas;
14
+ if (!Canvas)
15
+ throw new Error(NO_CANVAS);
16
+ const canvas = new Canvas(width, height);
17
+ const context = canvas.getContext("2d", { willReadFrequently: true });
18
+ if (!context)
19
+ throw new Error("cascade.image: the canvas has no 2D context");
20
+ return { canvas, context };
21
+ }
22
+ function assetsOf(context) {
23
+ const assets = context.capabilities.assets;
24
+ if (!assets)
25
+ throw new Error(`${context.nodeId}: this host gives cascade.image nodes no assets capability`);
26
+ return assets;
27
+ }
28
+ /** An image input, an asset or a project path, as the reference to read. */
29
+ export function imageReference(value) {
30
+ if (typeof value === "string")
31
+ return value ? { path: value } : null;
32
+ const path = value?.path;
33
+ return typeof path === "string" && path ? { path } : null;
34
+ }
35
+ /** Decode stored bytes to 8-bit RGBA through the realm's canvas. */
36
+ export async function decodePixels(bytes) {
37
+ const globals = canvasGlobals();
38
+ if (!globals.createImageBitmap || !globals.Blob)
39
+ throw new Error(NO_CANVAS);
40
+ const bitmap = await globals.createImageBitmap(new globals.Blob([bytes]));
41
+ try {
42
+ const { width, height } = bitmap;
43
+ if (!width || !height)
44
+ throw new Error("cascade.image: could not decode the image data");
45
+ const { context } = surface(width, height);
46
+ context.drawImage(bitmap, 0, 0);
47
+ return { width, height, data: context.getImageData(0, 0, width, height).data };
48
+ }
49
+ finally {
50
+ bitmap.close?.();
51
+ }
52
+ }
53
+ /** A whole canvas's pixels. */
54
+ export function readPixelsFromCanvas(canvas) {
55
+ const context = canvas.getContext("2d", { willReadFrequently: true });
56
+ if (!context)
57
+ throw new Error("cascade.image: the canvas has no 2D context");
58
+ return { width: canvas.width, height: canvas.height, data: context.getImageData(0, 0, canvas.width, canvas.height).data };
59
+ }
60
+ export async function readPixels(context, ref) {
61
+ const assets = assetsOf(context);
62
+ const kept = assets.imagePixels?.(ref);
63
+ if (kept)
64
+ return kept;
65
+ return decodePixels(await assets.read(ref, { signal: context.signal }));
66
+ }
67
+ /** An image input as a `Planar`, or null when nothing is wired. */
68
+ export async function readPlanar(context, value) {
69
+ const ref = imageReference(value);
70
+ return ref ? Planar.fromPixels(await readPixels(context, ref)) : null;
71
+ }
72
+ async function encodePng(pixels) {
73
+ const globals = canvasGlobals();
74
+ if (!globals.ImageData)
75
+ throw new Error(NO_CANVAS);
76
+ const { canvas, context } = surface(pixels.width, pixels.height);
77
+ context.putImageData(new globals.ImageData(pixels.data, pixels.width, pixels.height), 0, 0);
78
+ const blob = await canvas.convertToBlob({ type: "image/png" });
79
+ return new Uint8Array(await blob.arrayBuffer());
80
+ }
81
+ /** Store pixels as this node's image output and return the value to set. */
82
+ export async function writePixels(context, pixels) {
83
+ const assets = assetsOf(context);
84
+ const name = `${context.nodeId}.png`;
85
+ const options = { signal: context.signal };
86
+ const stored = assets.keepImage
87
+ ? await assets.keepImage(pixels, { suggestedName: name }, options)
88
+ : await assets.write(await encodePng(pixels), { mediaType: "image/png", suggestedName: name }, options);
89
+ return { path: stored.path, size: [pixels.width, pixels.height], channels: "rgba", depth: "u8", space: "srgb" };
90
+ }
91
+ /** Set a node's `image` output from a `Planar`. */
92
+ export async function output(context, image) {
93
+ context.outputs.image.set(await writePixels(context, image.toPixels()));
94
+ }
95
+ /**
96
+ * A colour in any of the shapes the class library accepted: `[r, g, b, a]`
97
+ * (Cascade's one colour), the older `{ r, g, b, a }`, 0–255 components, or a
98
+ * CSS `rgb()` / hex string. Saved graphs hold all of them.
99
+ */
100
+ export function normalizeColor(input) {
101
+ if (input && typeof input === "object" && !Array.isArray(input) && "r" in input && "g" in input && "b" in input) {
102
+ const color = input;
103
+ const unit = color.r <= 1 && color.g <= 1 && color.b <= 1;
104
+ return {
105
+ r: unit ? color.r : color.r / 255,
106
+ g: unit ? color.g : color.g / 255,
107
+ b: unit ? color.b : color.b / 255,
108
+ a: color.a !== undefined ? (unit ? color.a : color.a / 255) : 1,
109
+ };
110
+ }
111
+ if (Array.isArray(input)) {
112
+ const unit = input.every((value) => value <= 1);
113
+ return {
114
+ r: unit ? input[0] : input[0] / 255,
115
+ g: unit ? input[1] : input[1] / 255,
116
+ b: unit ? input[2] : input[2] / 255,
117
+ a: input[3] !== undefined ? (unit ? input[3] : input[3] / 255) : 1,
118
+ };
119
+ }
120
+ if (typeof input === "string") {
121
+ const rgb = input.match(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/);
122
+ if (rgb)
123
+ return { r: parseInt(rgb[1], 10) / 255, g: parseInt(rgb[2], 10) / 255, b: parseInt(rgb[3], 10) / 255, a: 1 };
124
+ const hex = input.replace("#", "");
125
+ if (hex.length === 3 || hex.length === 6) {
126
+ const expanded = hex.length === 3 ? hex.split("").map((digit) => digit + digit).join("") : hex;
127
+ const parts = /^([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(expanded);
128
+ if (parts)
129
+ return { r: parseInt(parts[1], 16) / 255, g: parseInt(parts[2], 16) / 255, b: parseInt(parts[3], 16) / 255, a: 1 };
130
+ }
131
+ }
132
+ return { r: 0, g: 0, b: 0, a: 1 };
133
+ }
134
+ /** `rgb(r,g,b)`, or `rgba(r,g,b,a)` below full alpha, for `fillStyle`. */
135
+ export function colorToCss(color) {
136
+ const r = Math.round(color.r * 255);
137
+ const g = Math.round(color.g * 255);
138
+ const b = Math.round(color.b * 255);
139
+ const a = color.a !== undefined ? color.a : 1;
140
+ return a < 1 ? `rgba(${r},${g},${b},${a})` : `rgb(${r},${g},${b})`;
141
+ }
142
+ //# sourceMappingURL=io.js.map
@@ -0,0 +1,55 @@
1
+ import type { ImagePixels } from "@field/cascade/contracts";
2
+ /**
3
+ * The working image of the `cascade.image.*` nodes: one Float32Array per
4
+ * channel, 0..1, one, three or four channels.
5
+ *
6
+ * Ported from the class library's `ImageBuffer` with the canvas half left out.
7
+ * The arithmetic is kept exactly — the same Float32 stores, the same 1/255
8
+ * conversion in and the same round-and-clamp out — because the port is held to
9
+ * the class nodes' golden images pixel for pixel
10
+ * (`tests/fixtures/image-golden`). Between nodes an image travels as 8-bit
11
+ * RGBA (`ImagePixels`, see "How an image travels between nodes"), so a value
12
+ * becomes a `Planar` when a node reads it and 8-bit again when it writes.
13
+ */
14
+ export declare class Planar {
15
+ readonly width: number;
16
+ readonly height: number;
17
+ readonly channels: Float32Array[];
18
+ constructor(width: number, height: number, channels: Float32Array[]);
19
+ static grayscale(width: number, height: number): Planar;
20
+ static rgba(width: number, height: number): Planar;
21
+ /** From 8-bit RGBA, unpremultiplied. */
22
+ static fromPixels(pixels: ImagePixels): Planar;
23
+ static solid(width: number, height: number, color: RGBA): Planar;
24
+ get channelCount(): number;
25
+ get pixelCount(): number;
26
+ fill(channel: number, value: number): void;
27
+ clone(): Planar;
28
+ emptyClone(): Planar;
29
+ toRGBA(): Planar;
30
+ /** To 8-bit RGBA: a grey image fills red, green and blue, and no alpha is opaque. */
31
+ toPixels(): ImagePixels;
32
+ /** Bilinear, clamped at the edges (or wrapped). */
33
+ sample(x: number, y: number, channel?: number, wrap?: boolean): number;
34
+ }
35
+ export interface RGBA {
36
+ readonly r: number;
37
+ readonly g: number;
38
+ readonly b: number;
39
+ readonly a?: number;
40
+ }
41
+ /** A plain resample to a new size, every channel, opaque when there was no alpha. */
42
+ export declare function resample(source: Planar, width: number, height: number): Planar;
43
+ export type ResolutionMode = "input" | "input1" | "input2" | "largest" | "smallest" | "custom";
44
+ export type FitMode = "fill" | "fit" | "stretch" | "native";
45
+ /** Which input decides the output size. */
46
+ export declare function resolveOutputSize(mode: ResolutionMode, inputs: readonly (Planar | null)[], customSize?: readonly [number, number]): {
47
+ width: number;
48
+ height: number;
49
+ };
50
+ /**
51
+ * Fit an image to a size: `fill` crops, `fit` letterboxes, `stretch` distorts,
52
+ * `native` centres it at 1:1.
53
+ */
54
+ export declare function resizeToFit(source: Planar, targetWidth: number, targetHeight: number, fitMode?: FitMode): Planar;
55
+ //# sourceMappingURL=planar.d.ts.map
@@ -0,0 +1,274 @@
1
+ /**
2
+ * The working image of the `cascade.image.*` nodes: one Float32Array per
3
+ * channel, 0..1, one, three or four channels.
4
+ *
5
+ * Ported from the class library's `ImageBuffer` with the canvas half left out.
6
+ * The arithmetic is kept exactly — the same Float32 stores, the same 1/255
7
+ * conversion in and the same round-and-clamp out — because the port is held to
8
+ * the class nodes' golden images pixel for pixel
9
+ * (`tests/fixtures/image-golden`). Between nodes an image travels as 8-bit
10
+ * RGBA (`ImagePixels`, see "How an image travels between nodes"), so a value
11
+ * becomes a `Planar` when a node reads it and 8-bit again when it writes.
12
+ */
13
+ export class Planar {
14
+ width;
15
+ height;
16
+ channels;
17
+ constructor(width, height, channels) {
18
+ pixelCount(width, height);
19
+ this.width = width;
20
+ this.height = height;
21
+ this.channels = channels;
22
+ }
23
+ static grayscale(width, height) {
24
+ return new Planar(width, height, [new Float32Array(pixelCount(width, height))]);
25
+ }
26
+ static rgba(width, height) {
27
+ const size = pixelCount(width, height);
28
+ return new Planar(width, height, [
29
+ new Float32Array(size),
30
+ new Float32Array(size),
31
+ new Float32Array(size),
32
+ new Float32Array(size),
33
+ ]);
34
+ }
35
+ /** From 8-bit RGBA, unpremultiplied. */
36
+ static fromPixels(pixels) {
37
+ const { width, height, data } = pixels;
38
+ const size = width * height;
39
+ const r = new Float32Array(size);
40
+ const g = new Float32Array(size);
41
+ const b = new Float32Array(size);
42
+ const a = new Float32Array(size);
43
+ const inv255 = 1 / 255;
44
+ for (let i = 0; i < size; i++) {
45
+ const idx = i * 4;
46
+ r[i] = data[idx] * inv255;
47
+ g[i] = data[idx + 1] * inv255;
48
+ b[i] = data[idx + 2] * inv255;
49
+ a[i] = data[idx + 3] * inv255;
50
+ }
51
+ return new Planar(width, height, [r, g, b, a]);
52
+ }
53
+ static solid(width, height, color) {
54
+ const buffer = Planar.rgba(width, height);
55
+ buffer.fill(0, color.r);
56
+ buffer.fill(1, color.g);
57
+ buffer.fill(2, color.b);
58
+ buffer.fill(3, color.a ?? 1);
59
+ return buffer;
60
+ }
61
+ get channelCount() {
62
+ return this.channels.length;
63
+ }
64
+ get pixelCount() {
65
+ return this.width * this.height;
66
+ }
67
+ fill(channel, value) {
68
+ this.channels[channel].fill(value);
69
+ }
70
+ clone() {
71
+ return new Planar(this.width, this.height, this.channels.map((channel) => new Float32Array(channel)));
72
+ }
73
+ emptyClone() {
74
+ return new Planar(this.width, this.height, this.channels.map(() => new Float32Array(this.pixelCount)));
75
+ }
76
+ toRGBA() {
77
+ if (this.channels.length >= 4)
78
+ return this.clone();
79
+ const result = Planar.rgba(this.width, this.height);
80
+ const [r, g = r, b = r] = this.channels.length === 1 ? [this.channels[0]] : this.channels;
81
+ result.channels[0].set(r);
82
+ result.channels[1].set(g);
83
+ result.channels[2].set(b);
84
+ result.channels[3].fill(1);
85
+ return result;
86
+ }
87
+ /** To 8-bit RGBA: a grey image fills red, green and blue, and no alpha is opaque. */
88
+ toPixels() {
89
+ const size = this.pixelCount;
90
+ const data = new Uint8ClampedArray(size * 4);
91
+ const r = this.channels[0];
92
+ const g = this.channels.length > 1 ? this.channels[1] : r;
93
+ const b = this.channels.length > 2 ? this.channels[2] : r;
94
+ const a = this.channels.length > 3 ? this.channels[3] : null;
95
+ for (let i = 0; i < size; i++) {
96
+ const idx = i << 2;
97
+ let v = (r[i] * 255 + 0.5) | 0;
98
+ data[idx] = v < 0 ? 0 : v > 255 ? 255 : v;
99
+ v = (g[i] * 255 + 0.5) | 0;
100
+ data[idx + 1] = v < 0 ? 0 : v > 255 ? 255 : v;
101
+ v = (b[i] * 255 + 0.5) | 0;
102
+ data[idx + 2] = v < 0 ? 0 : v > 255 ? 255 : v;
103
+ if (a) {
104
+ v = (a[i] * 255 + 0.5) | 0;
105
+ data[idx + 3] = v < 0 ? 0 : v > 255 ? 255 : v;
106
+ }
107
+ else {
108
+ data[idx + 3] = 255;
109
+ }
110
+ }
111
+ return { width: this.width, height: this.height, data };
112
+ }
113
+ /** Bilinear, clamped at the edges (or wrapped). */
114
+ sample(x, y, channel = 0, wrap = false) {
115
+ const x0 = Math.floor(x);
116
+ const y0 = Math.floor(y);
117
+ const fx = x - x0;
118
+ const fy = y - y0;
119
+ const ch = this.channels[channel];
120
+ const w = this.width;
121
+ const h = this.height;
122
+ const px0 = edge(x0, w, wrap);
123
+ const px1 = edge(x0 + 1, w, wrap);
124
+ const py0 = edge(y0, h, wrap);
125
+ const py1 = edge(y0 + 1, h, wrap);
126
+ const v0 = ch[py0 * w + px0] * (1 - fx) + ch[py0 * w + px1] * fx;
127
+ const v1 = ch[py1 * w + px0] * (1 - fx) + ch[py1 * w + px1] * fx;
128
+ return v0 * (1 - fy) + v1 * fy;
129
+ }
130
+ }
131
+ function edge(coord, max, wrap) {
132
+ return wrap ? ((coord % max) + max) % max : Math.max(0, Math.min(max - 1, coord));
133
+ }
134
+ function pixelCount(width, height) {
135
+ const count = width * height;
136
+ if (!Number.isSafeInteger(width) ||
137
+ !Number.isSafeInteger(height) ||
138
+ width < 1 ||
139
+ height < 1 ||
140
+ !Number.isSafeInteger(count)) {
141
+ throw new RangeError(`Image dimensions must be positive safe integers; received ${width}×${height}`);
142
+ }
143
+ return count;
144
+ }
145
+ /** A plain resample to a new size, every channel, opaque when there was no alpha. */
146
+ export function resample(source, width, height) {
147
+ const result = Planar.rgba(width, height);
148
+ const scaleX = source.width / width;
149
+ const scaleY = source.height / height;
150
+ for (let c = 0; c < Math.min(source.channelCount, 4); c++) {
151
+ const dst = result.channels[c];
152
+ for (let y = 0; y < height; y++) {
153
+ for (let x = 0; x < width; x++) {
154
+ dst[y * width + x] = source.sample(x * scaleX, y * scaleY, c);
155
+ }
156
+ }
157
+ }
158
+ if (source.channelCount < 4)
159
+ result.fill(3, 1);
160
+ return result;
161
+ }
162
+ /** Which input decides the output size. */
163
+ export function resolveOutputSize(mode, inputs, customSize) {
164
+ const valid = inputs.filter((buffer) => buffer !== null);
165
+ const area = (buffer) => buffer.width * buffer.height;
166
+ switch (mode) {
167
+ case "input":
168
+ case "input1":
169
+ if (valid[0])
170
+ return { width: valid[0].width, height: valid[0].height };
171
+ break;
172
+ case "input2": {
173
+ const chosen = valid[1] ?? valid[0];
174
+ if (chosen)
175
+ return { width: chosen.width, height: chosen.height };
176
+ break;
177
+ }
178
+ case "largest":
179
+ case "smallest":
180
+ if (valid.length > 0) {
181
+ let best = valid[0];
182
+ let bestArea = mode === "largest" ? 0 : Infinity;
183
+ for (const buffer of valid) {
184
+ if (mode === "largest" ? area(buffer) > bestArea : area(buffer) < bestArea) {
185
+ bestArea = area(buffer);
186
+ best = buffer;
187
+ }
188
+ }
189
+ return { width: best.width, height: best.height };
190
+ }
191
+ break;
192
+ case "custom":
193
+ if (customSize)
194
+ return { width: customSize[0], height: customSize[1] };
195
+ break;
196
+ }
197
+ if (valid[0])
198
+ return { width: valid[0].width, height: valid[0].height };
199
+ return { width: 512, height: 512 };
200
+ }
201
+ /**
202
+ * Fit an image to a size: `fill` crops, `fit` letterboxes, `stretch` distorts,
203
+ * `native` centres it at 1:1.
204
+ */
205
+ export function resizeToFit(source, targetWidth, targetHeight, fitMode = "fill") {
206
+ if (source.width === targetWidth && source.height === targetHeight)
207
+ return source;
208
+ const result = Planar.rgba(targetWidth, targetHeight);
209
+ const srcAspect = source.width / source.height;
210
+ const dstAspect = targetWidth / targetHeight;
211
+ let srcX = 0, srcY = 0, srcW = source.width, srcH = source.height;
212
+ let dstX = 0, dstY = 0, dstW = targetWidth, dstH = targetHeight;
213
+ const black = () => {
214
+ result.fill(0, 0);
215
+ result.fill(1, 0);
216
+ result.fill(2, 0);
217
+ result.fill(3, 1);
218
+ };
219
+ switch (fitMode) {
220
+ case "fill":
221
+ if (srcAspect > dstAspect) {
222
+ srcW = Math.round(source.height * dstAspect);
223
+ srcX = Math.round((source.width - srcW) / 2);
224
+ }
225
+ else {
226
+ srcH = Math.round(source.width / dstAspect);
227
+ srcY = Math.round((source.height - srcH) / 2);
228
+ }
229
+ break;
230
+ case "fit":
231
+ if (srcAspect > dstAspect) {
232
+ dstH = Math.round(targetWidth / srcAspect);
233
+ dstY = Math.round((targetHeight - dstH) / 2);
234
+ }
235
+ else {
236
+ dstW = Math.round(targetHeight * srcAspect);
237
+ dstX = Math.round((targetWidth - dstW) / 2);
238
+ }
239
+ black();
240
+ break;
241
+ case "stretch":
242
+ break;
243
+ case "native":
244
+ dstW = Math.min(source.width, targetWidth);
245
+ dstH = Math.min(source.height, targetHeight);
246
+ srcW = dstW;
247
+ srcH = dstH;
248
+ dstX = Math.round((targetWidth - dstW) / 2);
249
+ dstY = Math.round((targetHeight - dstH) / 2);
250
+ srcX = Math.round((source.width - srcW) / 2);
251
+ srcY = Math.round((source.height - srcH) / 2);
252
+ black();
253
+ break;
254
+ }
255
+ const scaleX = srcW / dstW;
256
+ const scaleY = srcH / dstH;
257
+ for (let c = 0; c < Math.min(source.channelCount, 4); c++) {
258
+ const dst = result.channels[c];
259
+ for (let y = 0; y < dstH; y++) {
260
+ for (let x = 0; x < dstW; x++) {
261
+ dst[(dstY + y) * targetWidth + (dstX + x)] = source.sample(srcX + x * scaleX, srcY + y * scaleY, c);
262
+ }
263
+ }
264
+ }
265
+ if (source.channelCount < 4 && fitMode !== "fit" && fitMode !== "native") {
266
+ const alpha = result.channels[3];
267
+ for (let y = 0; y < dstH; y++) {
268
+ for (let x = 0; x < dstW; x++)
269
+ alpha[(dstY + y) * targetWidth + (dstX + x)] = 1;
270
+ }
271
+ }
272
+ return result;
273
+ }
274
+ //# sourceMappingURL=planar.js.map
@@ -0,0 +1,22 @@
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
+ export type NoiseFunction2D = (x: number, y: number) => number;
21
+ export declare function createNoise2D(random: () => number): NoiseFunction2D;
22
+ //# sourceMappingURL=simplex.d.ts.map