@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.
- package/AGENTS.md +25 -5
- package/ARCHITECTURE.md +5 -4
- package/CHANGELOG.md +382 -0
- package/README.md +1 -2
- package/dist/assets/AgentPanel-1JugFjE4.css +1 -0
- package/dist/assets/AgentPanel-BDL5MddA.js +5 -0
- package/dist/assets/{CodeEditor-DSZBpzdy.js → CodeEditor-C-xYG-Wn.js} +120 -120
- package/dist/assets/CodePanel-CtXd50m6.js +2 -0
- package/dist/assets/CookInfoPanel-B3NMhKJF.css +1 -0
- package/dist/assets/CookInfoPanel-DG4_TRsX.js +2 -0
- package/dist/assets/CustomNodeDialog-CHfZUs-r.js +1 -0
- package/dist/assets/DefinitionNode-CaRTXQ_b.js +1 -0
- package/dist/assets/DefinitionPanel-C3CxZY9r.js +1 -0
- package/dist/assets/DefinitionPanel-VNLnAiQD.css +1 -0
- package/dist/assets/OpenGraphDialog-BLdr6k_q.js +1 -0
- package/dist/assets/ProjectSettings-ZnvmIAir.js +2 -0
- package/dist/assets/{SettingsDialog-p25h3tj0.js → SettingsDialog-CBX3Wa87.js} +1 -1
- package/dist/assets/TimelinePanel-CDeR0arY.css +1 -0
- package/dist/assets/TimelinePanel-CWgnFH1e.js +1 -0
- package/dist/assets/{VersionHistoryDialog-DzFLUotB.js → VersionHistoryDialog-BOSoW1R-.js} +1 -1
- package/dist/assets/assert-BO2_erPD.js +1 -0
- package/dist/assets/assert-hvykGCnP.js +1 -0
- package/dist/assets/builder-BmBKcDix.js +1 -0
- package/dist/assets/camera-DFF7YA3F.js +1 -0
- package/dist/assets/checks-DAvyO9Gf.js +1 -0
- package/dist/assets/contactSheet-N1NcaWxw.js +2 -0
- package/dist/assets/{core-BICrEt0y.js → core-DB-MkGjj.js} +3 -4
- package/dist/assets/coreTypes-DtnDATZ7.js +1 -0
- package/dist/assets/{cssMode-D7TXw57I.js → cssMode-DPVckSOc.js} +1 -1
- package/dist/assets/definitions-B227e7f_.js +1 -0
- package/dist/assets/definitions-D0WOUJd7.js +1 -0
- package/dist/assets/{editor.api-DvkCO3ko.js → editor.api-Dkutg_Z1.js} +1 -1
- package/dist/assets/expressions-X-Z-GrgW.js +5 -0
- package/dist/assets/file-DAL6IfjV.js +1 -0
- package/dist/assets/filters-D3k1LRMa.js +1 -0
- package/dist/assets/{freemarker2-BA2lxsF1.js → freemarker2-CLiLKk3B.js} +1 -1
- package/dist/assets/generators-BhDxRAFC.js +1 -0
- package/dist/assets/geo-BsMImJIJ.js +1 -0
- package/dist/assets/geo-C4YngDob.js +2 -0
- package/dist/assets/{handlebars-BcDiyPd8.js → handlebars-CcD3aMeL.js} +1 -1
- package/dist/assets/{html-C7O4TyhX.js → html-DvZWGfqb.js} +1 -1
- package/dist/assets/{htmlMode-WaDGF3Mj.js → htmlMode-DUD3VaoN.js} +1 -1
- package/dist/assets/image-0SfH-snh.js +1 -0
- package/dist/assets/image-Ck-RdGU4.js +2 -0
- package/dist/assets/index-BWnrmIB9.js +137 -0
- package/dist/assets/index-DIaxEONI.css +1 -0
- package/dist/assets/io-BGmt2g0D.js +1 -0
- package/dist/assets/{javascript-CpIEK7tz.js → javascript-Cap2ahgh.js} +1 -1
- package/dist/assets/{jsonMode-B2FltW0f.js → jsonMode-B0uLjp9C.js} +1 -1
- package/dist/assets/{liquid-CN6FFHZE.js → liquid-CnxwhfLn.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-QhV9XtLp.js → lspLanguageFeatures-Dn9hlKX6.js} +1 -1
- package/dist/assets/math-GeULS-sk.js +1 -0
- package/dist/assets/{mdx-DE89pafV.js → mdx-BV3jbrVa.js} +1 -1
- package/dist/assets/pop-KMF_qloi.js +1 -0
- package/dist/assets/preload-helper-Czpn1I53.js +1 -0
- package/dist/assets/{python-ByTllTB9.js → python-CGyFk4XK.js} +1 -1
- package/dist/assets/{razor-USYlRRCE.js → razor-CQfzX3-N.js} +1 -1
- package/dist/assets/remap-5SjXQU-q.js +1 -0
- package/dist/assets/renderMarkdown-ork0Oir7.js +67 -0
- package/dist/assets/studioImages-CAyH-0Pl.js +1 -0
- package/dist/assets/text-ZpX7qNkx.js +2 -0
- package/dist/assets/time-P_OiBhcf.js +1 -0
- package/dist/assets/{tsMode-BXpN8iUz.js → tsMode-BOeXzO9H.js} +1 -1
- package/dist/assets/{typescript-DInBjGQQ.js → typescript-J1SnE_Tu.js} +1 -1
- package/dist/assets/{workers-C7Ye5B7D.js → workers-CYwwTiVF.js} +1 -1
- package/dist/assets/{xml-U0Uocqyo.js → xml-DnPRNzK9.js} +1 -1
- package/dist/assets/{yaml-CBw_PVYf.js → yaml-BmmYBNa9.js} +1 -1
- package/dist/cli/DefinitionNode-P7AA4TAU.js +15 -0
- package/dist/cli/Graph-OB6EWSGL.js +2975 -0
- package/dist/cli/assert-GROGQNCQ.js +25 -0
- package/dist/cli/checks-3WB44XBL.js +189 -0
- package/dist/cli/chunk-2JEU3MGB.js +1125 -0
- package/dist/cli/chunk-2KXB47FP.js +115 -0
- package/dist/cli/chunk-3RXL5GHB.js +816 -0
- package/dist/cli/chunk-53LGFPWX.js +138 -0
- package/dist/cli/chunk-5ORUQ6ES.js +267 -0
- package/dist/cli/chunk-73S4JZXK.js +336 -0
- package/dist/cli/chunk-7QE2ZNSN.js +121 -0
- package/dist/cli/chunk-BP7UKF36.js +376 -0
- package/dist/cli/chunk-BPODRH52.js +201 -0
- package/dist/cli/chunk-BZ63XQ3I.js +1301 -0
- package/dist/cli/chunk-CKS2FQWR.js +89 -0
- package/dist/cli/chunk-CO22XHNG.js +593 -0
- package/dist/cli/chunk-CTPLRSWF.js +2197 -0
- package/dist/cli/chunk-DEQSEFFH.js +153 -0
- package/dist/cli/chunk-EU4ZFZ7Y.js +122 -0
- package/dist/cli/chunk-EZRWJ4G2.js +104 -0
- package/dist/cli/chunk-FWMSGKEH.js +71 -0
- package/dist/cli/chunk-G23A2BZZ.js +705 -0
- package/dist/cli/chunk-GRIN2DDP.js +1465 -0
- package/dist/cli/chunk-HFHWYL55.js +139 -0
- package/dist/cli/chunk-HSNOBIVT.js +263 -0
- package/dist/cli/chunk-ICH7N5PN.js +26 -0
- package/dist/cli/chunk-J7VK7MNF.js +418 -0
- package/dist/cli/chunk-JVOCK5W4.js +83 -0
- package/dist/cli/chunk-KBGUO27Q.js +15 -0
- package/dist/cli/chunk-KH4MUBKF.js +1551 -0
- package/dist/cli/chunk-L6B6FUQP.js +330 -0
- package/dist/cli/chunk-LTXWBXOM.js +438 -0
- package/dist/cli/chunk-MI5JLQYA.js +220 -0
- package/dist/cli/chunk-MP653A5O.js +3766 -0
- package/dist/cli/chunk-NJFMDXHR.js +320 -0
- package/dist/cli/chunk-OM6BEME6.js +267 -0
- package/dist/cli/chunk-OWWBYLHC.js +136 -0
- package/dist/cli/chunk-QQPA2ZHH.js +273 -0
- package/dist/cli/chunk-RUU3YWXU.js +99 -0
- package/dist/cli/chunk-RXDIMXN5.js +98 -0
- package/dist/cli/chunk-ST6LROUG.js +267 -0
- package/dist/cli/chunk-TJW67QSI.js +225 -0
- package/dist/cli/chunk-WD62JIP6.js +118 -0
- package/dist/cli/chunk-WGKPJZDY.js +364 -0
- package/dist/cli/chunk-X4WKAOQP.js +634 -0
- package/dist/cli/chunk-X566FWBV.js +156 -0
- package/dist/cli/chunk-YH637PDL.js +317 -0
- package/dist/cli/chunk-ZL4JTG5Y.js +37 -0
- package/dist/cli/chunk-ZSCUZE6I.js +112 -0
- package/dist/cli/cliCommands-JJN5Z3ZC.js +3470 -0
- package/dist/cli/commands-PHYFYA3F.js +1374 -0
- package/dist/cli/contactSheet-2PQVRUFW.js +11 -0
- package/dist/cli/definitions-BPOPW52L.js +32 -0
- package/dist/cli/doctorCommand-ORWQRNYP.js +106 -0
- package/dist/cli/edit-S5KEQ5RA.js +28 -0
- package/dist/cli/editorCommands-NFR32JOY.js +41 -0
- package/dist/cli/encode-ICPEPMH5.js +17 -0
- package/dist/cli/file-3HTQHPYQ.js +41 -0
- package/dist/cli/filters-6ODFWYK4.js +379 -0
- package/dist/cli/frames-LSAUBZ7P.js +16 -0
- package/dist/cli/generators-YU7GB4MD.js +210 -0
- package/dist/cli/geo-6ZPGKZRU.js +43 -0
- package/dist/cli/graphCommands-EOUOBOIJ.js +184 -0
- package/dist/cli/graphFile-YTGJB5F5.js +292 -0
- package/dist/cli/headlessCanvas-ENRHC7GS.js +16 -0
- package/dist/cli/helpCommand-PULH6ZYB.js +157 -0
- package/dist/cli/image-TXELZZK5.js +55 -0
- package/dist/cli/index.js +100 -30756
- package/dist/cli/math-RSYRQ3C6.js +16 -0
- package/dist/cli/mcp-JVZFQOEX.js +164 -0
- package/dist/cli/parity-X6DEH2DV.js +334 -0
- package/dist/cli/pop-B7SIIYKN.js +39 -0
- package/dist/cli/project-VYGIA7JX.js +12 -0
- package/dist/cli/projectDefinition-F3D7UIHJ.js +27 -0
- package/dist/cli/projectRuntime-2Q4JKEH3.js +55 -0
- package/dist/cli/registerStandardNodes-BXJCB6E4.js +744 -0
- package/dist/cli/render-PT4MWI6U.js +438 -0
- package/dist/cli/runCommand-HNPQVZMS.js +198 -0
- package/dist/cli/runner-5XPXVW7J.js +43 -0
- package/dist/cli/runtime/image.ts +302 -0
- package/dist/cli/runtime/io.ts +78 -0
- package/dist/cli/runtime/stage.ts +4 -1
- package/dist/cli/share-MHF6TNRK.js +166 -0
- package/dist/cli/stageCache-TY2BFZJR.js +15 -0
- package/dist/cli/stageRunner-KY2EJP7X.js +10 -0
- package/dist/cli/text-MB3EKR4H.js +126 -0
- package/dist/cli/verbs-PI2JH5FI.js +19 -0
- package/dist/cli/webBuild-WPPMGGW7.js +44 -0
- package/dist/contracts/capabilities.d.ts +18 -1
- package/dist/contracts/color.d.ts +8 -0
- package/dist/contracts/color.js +23 -0
- package/dist/contracts/definition.d.ts +10 -0
- package/dist/contracts/documentFormat.d.ts +18 -0
- package/dist/contracts/documentFormat.js +195 -0
- package/dist/contracts/editor.d.ts +17 -0
- package/dist/contracts/index.d.ts +1 -0
- package/dist/contracts/index.js +1 -0
- package/dist/contracts/schema.d.ts +1 -1
- package/dist/contracts/schema.js +1 -0
- package/dist/contracts/validate.js +11 -1
- package/dist/contracts/values.d.ts +24 -0
- package/dist/image.d.ts +156 -0
- package/dist/image.js +161 -0
- package/dist/index.html +8 -2
- package/dist/io.d.ts +29 -0
- package/dist/io.js +40 -0
- package/dist/player/app.js +3 -2
- package/dist/player/editor.js +35 -9
- package/dist/player/editorEngine.js +3 -2
- package/dist/runtime/builtins/assert/checks.d.ts +18 -0
- package/dist/runtime/builtins/assert/checks.js +207 -0
- package/dist/runtime/builtins/assert/definitions.d.ts +130 -0
- package/dist/runtime/builtins/assert/definitions.js +54 -0
- package/dist/runtime/builtins/assert/index.d.ts +152 -0
- package/dist/runtime/builtins/assert/index.js +36 -0
- package/dist/runtime/builtins/image/contactSheet.d.ts +64 -0
- package/dist/runtime/builtins/image/contactSheet.js +150 -0
- package/dist/runtime/builtins/image/definitions.d.ts +950 -0
- package/dist/runtime/builtins/image/definitions.js +343 -0
- package/dist/runtime/builtins/image/file.d.ts +8 -0
- package/dist/runtime/builtins/image/file.js +37 -0
- package/dist/runtime/builtins/image/filters.d.ts +8 -0
- package/dist/runtime/builtins/image/filters.js +394 -0
- package/dist/runtime/builtins/image/generators.d.ts +7 -0
- package/dist/runtime/builtins/image/generators.js +144 -0
- package/dist/runtime/builtins/image/index.d.ts +952 -0
- package/dist/runtime/builtins/image/index.js +44 -0
- package/dist/runtime/builtins/image/io.d.ts +100 -0
- package/dist/runtime/builtins/image/io.js +142 -0
- package/dist/runtime/builtins/image/planar.d.ts +55 -0
- package/dist/runtime/builtins/image/planar.js +274 -0
- package/dist/runtime/builtins/image/simplex.d.ts +22 -0
- package/dist/runtime/builtins/image/simplex.js +92 -0
- package/dist/runtime/builtins/image/text.d.ts +4 -0
- package/dist/runtime/builtins/image/text.js +141 -0
- package/dist/runtime/builtins/index.d.ts +3 -0
- package/dist/runtime/builtins/index.js +7 -0
- package/dist/runtime/gpu.d.ts +25 -0
- package/dist/runtime/gpu.js +40 -0
- package/dist/runtime/runtime.d.ts +2 -0
- package/dist/runtime/runtime.js +268 -44
- package/dist/runtime/types.d.ts +30 -0
- package/dist/stage.js +4 -1
- package/doc/CLI_REFERENCE.md +91 -2
- package/doc/EDITOR_EXPORT.md +37 -2
- package/doc/MCP.md +18 -1
- package/doc/NODE_REFERENCE.md +424 -10
- package/doc/PROJECT_AUTHORING.md +222 -7
- package/package.json +19 -4
- package/dist/assets/CodePanel-sY6sZa7B.js +0 -2
- package/dist/assets/CustomNodeDialog-BRKnqZhp.js +0 -1
- package/dist/assets/ExportDialog-C7dVGua4.js +0 -358
- package/dist/assets/ExportDialog-DOq0flMV.css +0 -1
- package/dist/assets/OpenGraphDialog-ZsgL-iwr.js +0 -1
- package/dist/assets/ProjectSettings-Cw17nNe3.js +0 -2
- package/dist/assets/definitions-DUww2Rt-.js +0 -1
- package/dist/assets/geo-C2RHOVHC.js +0 -1
- package/dist/assets/image-DR4oeyJB.js +0 -2062
- package/dist/assets/index-7vae6YFC.css +0 -1
- package/dist/assets/index-DyvDC6pS.js +0 -219
- package/dist/assets/math-DaDEgWKt.js +0 -1
- package/dist/assets/pop-pLH7L0PW.js +0 -1
package/doc/PROJECT_AUTHORING.md
CHANGED
|
@@ -61,6 +61,40 @@ difference. Use a deliberate local package override
|
|
|
61
61
|
for framework development rather than committing a machine-specific
|
|
62
62
|
`file:../../Dev/cascade` dependency to a shared project.
|
|
63
63
|
|
|
64
|
+
### Pin the core
|
|
65
|
+
|
|
66
|
+
A sketch pins one published Cascade, exactly, rather than linking the live
|
|
67
|
+
checkout, so a change on Cascade main cannot move its pixels until it opts in:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
"devDependencies": {
|
|
71
|
+
"cascade": "npm:@field/cascade@0.11.0",
|
|
72
|
+
"@field/cascade-kit": "file:../../Dev/cascade/packages/kit"
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Keep the dependency name `cascade`: imports stay `cascade/io`,
|
|
77
|
+
`cascade/stage` and so on, which is what Studio's compiler resolves. Only the
|
|
78
|
+
core is pinned; the kit is not on npm and stays a `file:` dependency. Commit
|
|
79
|
+
the lockfile, since it holds the core's own dependencies (a newer
|
|
80
|
+
`@napi-rs/canvas` shifts antialiasing by a few levels). To move from a link:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
npm install --save-dev --save-exact cascade@npm:@field/cascade@0.11.0
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
If `node_modules/cascade` is still a link afterwards, or npm fails with
|
|
87
|
+
`Cannot destructure property 'package' of 'node.target'`, the kit link is the
|
|
88
|
+
cause: its target sits inside the checkout, whose own package is
|
|
89
|
+
`@field/cascade`, so npm reuses the checkout. Move `node_modules` and
|
|
90
|
+
`package-lock.json` aside, install with the kit removed from `package.json`,
|
|
91
|
+
then add it back with `npm install --save-dev ../../Dev/cascade/packages/kit`.
|
|
92
|
+
|
|
93
|
+
To bump: change the version, `npm install`, `npx cascade check <graph>`, and
|
|
94
|
+
render a frame to compare. A sketch that needs something only on main (for
|
|
95
|
+
example `cascade share` before it ships) keeps the `file:` link and says why in
|
|
96
|
+
its README until the next release.
|
|
97
|
+
|
|
64
98
|
`index.cascade` is the default graph name. A project may contain several `.cascade` files; pass one explicitly when there is no unambiguous default:
|
|
65
99
|
|
|
66
100
|
```bash
|
|
@@ -83,6 +117,13 @@ my-artwork/
|
|
|
83
117
|
|
|
84
118
|
Keep generated output in a project-specific directory such as `renders/`. Keep reusable algorithms in `nodes/` or a normal TypeScript package rather than in Studio components.
|
|
85
119
|
|
|
120
|
+
Before writing OKLCH conversions, a seeded generator, noise, paper, a pen plot,
|
|
121
|
+
an ffmpeg call, a Cairn or Observatory loader or a disk cache, use the sketch
|
|
122
|
+
kit, `@field/cascade-kit` (`packages/kit`, a `file:` dependency). It also
|
|
123
|
+
generates the stubs for using another project's nodes without a symlink
|
|
124
|
+
(`npx cascade-kit nodes <provider>`). Read [KIT.md](KIT.md). The kit is
|
|
125
|
+
outside the core: Cascade never imports it.
|
|
126
|
+
|
|
86
127
|
## Add a project panel
|
|
87
128
|
|
|
88
129
|
A project can provide an optional dockable Studio panel without adding UI code to Cascade. Create `panels/asset-browser/index.ts`:
|
|
@@ -191,6 +232,19 @@ image-api:
|
|
|
191
232
|
|
|
192
233
|
The proxy accepts HTTPS only, refuses undeclared hosts, strips caller-supplied authorization headers, and never returns the credential value to the page. Studio defers its initial cook when a required credential is missing and links to File → Project Settings.
|
|
193
234
|
|
|
235
|
+
## Design the graph, not one big node
|
|
236
|
+
|
|
237
|
+
A piece is several nodes, each doing one job: load the data, lay it out, colour it, draw it, export it. The usage survey of November 2026 found the opposite in most projects (1 to 5 nodes of 300+ lines each over `lib/`), which leaves the graph as a parameter panel around opaque code. The graph is the record Marcus inspects, so each node boundary should be a place worth looking at, with the parameters that matter on it.
|
|
238
|
+
|
|
239
|
+
Clean graph design is clean code design:
|
|
240
|
+
|
|
241
|
+
- **One responsibility per node**, named for what it does (`layout_rings`, not `main`).
|
|
242
|
+
- **Data flows through typed ports**, never through module-level state or files one node writes and another reads behind the graph's back.
|
|
243
|
+
- **What varies is a parameter**; seeds, counts and colours are on the node, not constants in the code.
|
|
244
|
+
- **Shared helpers go in `lib/` or the kit** (`KIT.md`); the node is the unit you compose and reuse.
|
|
245
|
+
|
|
246
|
+
Split a node when it does two of load, generate, style, render and export, or when its `execute` grows past about 150 lines. `cascade check` warns on both (`shape/long-execute`, `shape/mixed-jobs`); the warnings are advice and never fail the check. Drawing with noise and colour is one job's worth of calls, so it only flags a module doing four of the five, or loading and exporting in the same node.
|
|
247
|
+
|
|
194
248
|
## Add a custom node
|
|
195
249
|
|
|
196
250
|
Before writing one, check whether you need one. A parameter can hold an expression, so anything time-based is usually a parameter rather than a node. See [Animate a parameter](#animate-a-parameter). A node earns its place when it produces geometry or pixels, or when several parameters share a computation. The built-in library is listed in `NODE_REFERENCE.md`, generated from the definitions themselves; read that before searching for what a node does.
|
|
@@ -345,7 +399,7 @@ export async function execute(node: any) {
|
|
|
345
399
|
|
|
346
400
|
`param()` is a method on the node the engine hands to `execute`, not an import. It is re-declared on every cook, so it never resets a value, an expression, or a keyframe someone set: reading `.value` gives the *resolved* value for the current frame, whichever of the three bindings is in force. The loader imports the module as real JavaScript, so top-level code does run at import time. Keep dynamic modules free of top-level effects and put interface declaration and cooking inside `execute`.
|
|
347
401
|
|
|
348
|
-
Prefer `new OffscreenCanvas(width, height)` to `document.createElement('canvas')` when both hosts can run the node. A portable declaration still requires output parity checks; installing Skia does not override a browser-only declaration. Use Python for libraries or tools that require a server. Measure transport, serialization, and cold-start costs; persistent workers can avoid repeated process/model startup.
|
|
402
|
+
Prefer `new OffscreenCanvas(width, height)` to `document.createElement('canvas')` when both hosts can run the node; a definition-v1 node uses `cascade/image` (see "Draw an image in any host"). A portable declaration still requires output parity checks; installing Skia does not override a browser-only declaration. Use Python for libraries or tools that require a server. Measure transport, serialization, and cold-start costs; persistent workers can avoid repeated process/model startup.
|
|
349
403
|
|
|
350
404
|
Choose the narrowest execution locus:
|
|
351
405
|
|
|
@@ -367,6 +421,96 @@ export const definition = {
|
|
|
367
421
|
|
|
368
422
|
The runtime refuses unsupported host/capability combinations before executing the graph.
|
|
369
423
|
|
|
424
|
+
### Draw an image in any host
|
|
425
|
+
|
|
426
|
+
A node that draws, reads or writes an image uses `cascade/image`, and then one
|
|
427
|
+
body cooks in Studio, under `cascade run`/`render`/MCP, and in an exported
|
|
428
|
+
editor's worker. Declare `runsOn: 'portable'` and `capabilities: ['assets']`,
|
|
429
|
+
and import nothing host-specific: no `node:*`, no `@napi-rs/canvas`, no
|
|
430
|
+
`document`.
|
|
431
|
+
|
|
432
|
+
```ts
|
|
433
|
+
import type { NodeDefinition, NodeExecutionContext } from 'cascade/contracts';
|
|
434
|
+
import { readBytes, readImage, registerFont, surface, writeImage } from 'cascade/image';
|
|
435
|
+
|
|
436
|
+
export const definition = {
|
|
437
|
+
apiVersion: 1,
|
|
438
|
+
label: 'Poster',
|
|
439
|
+
runsOn: 'portable',
|
|
440
|
+
capabilities: ['assets'],
|
|
441
|
+
inputs: { photo: { kind: 'data', type: 'image' } },
|
|
442
|
+
outputs: { image: { kind: 'data', type: 'image' } },
|
|
443
|
+
props: { title: { type: 'string', default: 'Hello' }, font: { type: 'string', default: 'assets/fonts/Display.otf' } },
|
|
444
|
+
} as const satisfies NodeDefinition;
|
|
445
|
+
|
|
446
|
+
export async function execute(context: NodeExecutionContext<typeof definition>) {
|
|
447
|
+
const photo = await readImage(context, context.inputs.photo); // an image input, asset or project path
|
|
448
|
+
await registerFont('Display', await readBytes(context, context.props.font));
|
|
449
|
+
const { canvas, context: g } = surface(photo.width, photo.height); // OffscreenCanvas, CPU-backed 2D
|
|
450
|
+
g.drawImage(photo, 0, 0);
|
|
451
|
+
g.font = '96px Display';
|
|
452
|
+
g.fillText(context.props.title, 40, 140);
|
|
453
|
+
context.outputs.image.set(await writeImage(context, canvas, `${context.nodeId}.png`));
|
|
454
|
+
}
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
| | Browser (Studio, exported editor) | Headless (CLI, MCP) |
|
|
458
|
+
| --- | --- | --- |
|
|
459
|
+
| `createCanvas`, `surface` | the realm's `OffscreenCanvas` | Skia's, from `@napi-rs/canvas` |
|
|
460
|
+
| `decodeImage`, `readImage` | `createImageBitmap` | the pixels from memory while the run holds them, else Skia's decoder |
|
|
461
|
+
| `writeImage` | an in-memory generated asset | `.cascade-cache/<name>.<hash>.png`, pixels held in memory and the file written behind |
|
|
462
|
+
| `registerFont` | `FontFace` added to the page's or worker's font set | Skia's `GlobalFonts` |
|
|
463
|
+
| `readBytes` | shipped files only (`editor.assets`, literal asset props, frozen files) | any project file |
|
|
464
|
+
|
|
465
|
+
- The host chooses where a written image lands; never name a path or read an
|
|
466
|
+
output file back by a path you built. `cachePath` and `saveImage` from
|
|
467
|
+
`cascade/io` remain for dynamic nodes.
|
|
468
|
+
- `surface(w, h)` asks for a `willReadFrequently` context, which keeps Chrome
|
|
469
|
+
on the same software Skia rasteriser the headless host uses. Expect the same
|
|
470
|
+
image, not the same bytes: on commons `plotter-social` the paper, foil and
|
|
471
|
+
wordmark match exactly and scanline marks differ at stroke edges (mean
|
|
472
|
+
channel delta under 0.5 of 255 with the same fonts).
|
|
473
|
+
- A font only matches across hosts when both register the same bytes. A file
|
|
474
|
+
that is not there (a licensed face the export never ships) should fall back
|
|
475
|
+
to a named system face, not fail; read it with `readBytes` in a `try`.
|
|
476
|
+
- What has no browser form is refused, not imitated: no canvas in the realm,
|
|
477
|
+
or `assets` not declared, throws a sentence saying which. A node that needs
|
|
478
|
+
the filesystem, a network fetch or ffmpeg stays `runsOn: 'server'`; to put
|
|
479
|
+
its output in an editor, freeze it (`cascade freeze <graph> <node> --fields
|
|
480
|
+
path,size,channels,depth,space` ships the image file with the snapshot).
|
|
481
|
+
|
|
482
|
+
#### How an image travels between nodes
|
|
483
|
+
|
|
484
|
+
An `image` port carries an `ImageRef` (a path plus size, channels, depth and
|
|
485
|
+
space), never the pixels, so a value stays cheap to snapshot, hash, trace and
|
|
486
|
+
send to Python. What sits behind the path is the host's business, and the
|
|
487
|
+
headless host keeps it in memory:
|
|
488
|
+
|
|
489
|
+
- `writeImage` (and `saveImage` in `cascade/io`) hands the canvas to the host
|
|
490
|
+
as `ImagePixels` (8-bit RGBA, sRGB, unpremultiplied, top row first: what
|
|
491
|
+
`getImageData` returns and what a PNG decodes to) through the optional
|
|
492
|
+
`assets.keepImage`. Under `cascade run`/`render` the host holds those pixels,
|
|
493
|
+
names the file by their hash, and writes a lossless PNG at zlib level 1
|
|
494
|
+
behind the run, off the main thread.
|
|
495
|
+
- `readImage` (and `loadBitmap`/`loadImage`) asks `assets.imagePixels` first
|
|
496
|
+
and gets a canvas holding the pixels: no file read and no decode. The next
|
|
497
|
+
node sees the same numbers a PNG round trip would give it.
|
|
498
|
+
- Anything that reads the path as a file gets a whole file: a Python stage
|
|
499
|
+
call, `assets.read`, a run's end, `freeze`, `lock` and `ladder` all wait for
|
|
500
|
+
the write behind, and so does every `runsOn: 'server'` node before it
|
|
501
|
+
starts, since it may read an input with `node:fs`. A run's saved outputs
|
|
502
|
+
(`--out`, `run --frames`, `render`) are encoded from the pixels at full
|
|
503
|
+
compression, never copied from the level-1 intermediate.
|
|
504
|
+
- Hosts without `keepImage` (an exported editor, the web player, and Studio
|
|
505
|
+
for project nodes) encode and store as before, so a node written against
|
|
506
|
+
`readImage`/`writeImage` works unchanged in each. Studio gives `keepImage`
|
|
507
|
+
to the built-in image library only: its images stay in the page under
|
|
508
|
+
`.cascade-studio/…` paths, which `readImage`, `assets.read` and the Viewer
|
|
509
|
+
all resolve, but which name no file a server stage could open.
|
|
510
|
+
|
|
511
|
+
On field-logo (12 canvas nodes at 1024²) this took a frame from 1,791 ms to
|
|
512
|
+
about 860 ms; most of what remains is the nodes' own pixel loops.
|
|
513
|
+
|
|
370
514
|
### GPU nodes today
|
|
371
515
|
|
|
372
516
|
A definition-v1 node may declare `capabilities: ['gpu']`. Studio and the optional
|
|
@@ -375,6 +519,26 @@ a cache scoped to each node instance for pipelines, samplers, and other
|
|
|
375
519
|
resources that outlive one cook. The host clears cached resources on host
|
|
376
520
|
disposal or device loss and requests a fresh device on a later cook.
|
|
377
521
|
|
|
522
|
+
The device is asked for with every limit the adapter allows, not WebGPU's
|
|
523
|
+
defaults: on an M3 Max that is 4 GiB per storage binding (default 128 MiB),
|
|
524
|
+
1,024 invocations per workgroup (256), 32 KiB of workgroup storage (16 KiB) and
|
|
525
|
+
10 storage buffers per stage (8). Read what you got from
|
|
526
|
+
`context.capabilities.gpu.limits` and size buffers and workgroups from it. A
|
|
527
|
+
node that cannot run below some limit declares it, and a smaller GPU then fails
|
|
528
|
+
before the cook with a sentence naming the limit:
|
|
529
|
+
|
|
530
|
+
```ts
|
|
531
|
+
export const definition = {
|
|
532
|
+
apiVersion: 1,
|
|
533
|
+
runsOn: 'portable',
|
|
534
|
+
capabilities: ['gpu'],
|
|
535
|
+
gpuLimits: { maxStorageBufferBindingSize: 512 * 2 ** 20 },
|
|
536
|
+
// ...
|
|
537
|
+
} as const;
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
`max*` limits are floors; `min*Alignment` limits are ceilings.
|
|
541
|
+
|
|
378
542
|
Use `runsOn: 'portable'` for shared WebGPU code without browser APIs. Render into
|
|
379
543
|
a texture and use `readTexture` from `cascade/gpu` for explicit RGBA8 pixels,
|
|
380
544
|
then encode through the image/IO host. See [headless GPU rendering](HEADLESS_GPU.md)
|
|
@@ -606,12 +770,63 @@ in `cascade run --json` under `stages`, and in the run trace.
|
|
|
606
770
|
keeps running its old code in a live Studio. Its bytecode cache is keyed by
|
|
607
771
|
the code hash, because Python accepts a `.pyc` whose source kept its size
|
|
608
772
|
within the same second.
|
|
609
|
-
- `
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
773
|
+
- `workers` (headless runs only) is how many warm workers `cascade run` keeps
|
|
774
|
+
for the project, and so how many independent nodes it cooks at once: sibling
|
|
775
|
+
stage calls in one frame (the morph's four renders) run side by side. Default
|
|
776
|
+
2–4, one per four cores and per 8 GB of memory; `CASCADE_STAGE_WORKERS`
|
|
777
|
+
overrides it, and `cascade render` workers keep one each. A second worker
|
|
778
|
+
starts only when a call finds the first busy. Nodes still start in the
|
|
779
|
+
graph's order, so the run trace lists them the same way every run; a stage
|
|
780
|
+
that writes a fixed path shared with another node is the one thing this can
|
|
781
|
+
break, and `"workers": 1` turns it off.
|
|
782
|
+
- `cache` controls Cascade's own result cache. A stored result is served only
|
|
783
|
+
while every file it names still has the bytes it had, so a stage that writes
|
|
784
|
+
a fixed path and was re-run with other inputs misses rather than serving the
|
|
785
|
+
overwritten file. See "The stage cache default" below.
|
|
786
|
+
|
|
787
|
+
#### The stage cache default
|
|
788
|
+
|
|
789
|
+
Since 6 Nov 2026 the cache is **on by default for the calls a node's cook
|
|
790
|
+
makes**, and off for everything else. A node is a pure function of its inputs,
|
|
791
|
+
so a stage it calls through `runStage` from `cascade/stage` is treated as pure:
|
|
792
|
+
same stage code, same arguments, same input file bytes, same answer. A second
|
|
793
|
+
identical cook is served from `.cascade/cache/stages/` without starting Python
|
|
794
|
+
at all; on `cloud-plots/relief.cascade` that takes a re-cook from about 4.2 s
|
|
795
|
+
to 0.45 s. A call from a panel (`api.runStage`) or a hand-rolled
|
|
796
|
+
`fetch('/api/exec')` is an action — `plot-start`, `plot-status` — and is not
|
|
797
|
+
cached unless you say so.
|
|
798
|
+
|
|
799
|
+
What is not pure, and must be opted out:
|
|
800
|
+
|
|
801
|
+
- a stage whose answer changes under an identical call: it reads the clock,
|
|
802
|
+
draws fresh randomness, queries a device or a job's progress, or calls a
|
|
803
|
+
network service whose answer you want fresh each time;
|
|
804
|
+
- a stage that reads a file its arguments do not name (a config file, a folder
|
|
805
|
+
it scans, a model downloaded on the side). Only files named in the arguments
|
|
806
|
+
are hashed into the key, so an edit to an unnamed file is invisible;
|
|
807
|
+
- a stage whose purpose is a side effect (copying to a named place, posting
|
|
808
|
+
somewhere). A result whose named files still have their bytes is served, so
|
|
809
|
+
a copy that already happened is not repeated; when the effect must happen
|
|
810
|
+
every time, opt the stage out.
|
|
811
|
+
|
|
812
|
+
How to opt out:
|
|
813
|
+
|
|
814
|
+
```json
|
|
815
|
+
"cache": { "exclude": ["plot-status", "camera-grab"], "outputs": ["out", "svg_out"] }
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
| Declaration | What is cached |
|
|
819
|
+
|---|---|
|
|
820
|
+
| absent | calls from node cooks, except `exclude` (none) |
|
|
821
|
+
| `{ "exclude": [...], "outputs": [...] }` | calls from node cooks, except the named stages |
|
|
822
|
+
| `{ "scope": "all", ... }` or `true` | every call, panel actions included, except `exclude` |
|
|
823
|
+
| `false` or `{ "enabled": false }` | nothing |
|
|
824
|
+
|
|
825
|
+
`CASCADE_STAGE_CACHE=off` in the environment still turns it off for one
|
|
826
|
+
process (`cascade parity` sets it). Every call's trace says what happened and
|
|
827
|
+
why: `hit`, `miss (no entry)`, `off (excluded)`, `off (not a cook call)`,
|
|
828
|
+
`off (not enabled)`. A project that keeps its own Python-side cache can keep
|
|
829
|
+
it; Cascade's sits in front, and on a hit the project's code is not called.
|
|
615
830
|
- A request carries `"cascade": {"key", "code", "cache"}` beside `args` (the
|
|
616
831
|
worker), or `CASCADE_STAGE_ENVELOPE` in the environment (one-shot). A
|
|
617
832
|
project that keeps its own cache should stand aside when `cache` is `"off"`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@field/cascade",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Visual programming for generative art",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "FIELD.IO <marcus@field.io>",
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
],
|
|
44
44
|
"workspaces": [
|
|
45
45
|
"packages/contracts",
|
|
46
|
-
"packages/runtime"
|
|
46
|
+
"packages/runtime",
|
|
47
|
+
"packages/kit"
|
|
47
48
|
],
|
|
48
49
|
"bin": {
|
|
49
50
|
"cascade": "./dist/cli/index.js"
|
|
@@ -105,6 +106,10 @@
|
|
|
105
106
|
"types": "./dist/io.d.ts",
|
|
106
107
|
"default": "./dist/io.js"
|
|
107
108
|
},
|
|
109
|
+
"./image": {
|
|
110
|
+
"types": "./dist/image.d.ts",
|
|
111
|
+
"default": "./dist/image.js"
|
|
112
|
+
},
|
|
108
113
|
"./gpu": {
|
|
109
114
|
"types": "./dist/gpu.d.ts",
|
|
110
115
|
"default": "./dist/gpu.js"
|
|
@@ -129,15 +134,24 @@
|
|
|
129
134
|
"dev": "vite",
|
|
130
135
|
"dev:client": "vite",
|
|
131
136
|
"build": "node scripts/build.mjs",
|
|
132
|
-
"build:workspaces": "npm run build --workspace @cascade/contracts && npm run build --workspace @cascade/runtime",
|
|
137
|
+
"build:workspaces": "npm run build --workspace @cascade/contracts && npm run build --workspace @cascade/runtime && npm run build --workspace @field/cascade-kit",
|
|
138
|
+
"build:kit": "npm run build --workspace @field/cascade-kit",
|
|
139
|
+
"test:kit": "npm run test --workspace @field/cascade-kit",
|
|
133
140
|
"build:packages": "npm run build:workspaces && node scripts/copy-package-builds.mjs",
|
|
134
141
|
"check:packages": "npm run check --workspace @cascade/contracts && npm run build --workspace @cascade/contracts && npm run check --workspace @cascade/runtime",
|
|
135
|
-
"test:packages": "npm run test --workspace @cascade/contracts && npm run test --workspace @cascade/runtime",
|
|
142
|
+
"test:packages": "npm run test --workspace @cascade/contracts && npm run test --workspace @cascade/runtime && npm run test --workspace @field/cascade-kit",
|
|
136
143
|
"build:cli": "node scripts/build.mjs --cli",
|
|
137
144
|
"build:server": "npm --prefix server run build",
|
|
138
145
|
"prepack": "npm run build",
|
|
139
146
|
"preview": "vite preview",
|
|
140
147
|
"check": "svelte-check --tsconfig ./tsconfig.json",
|
|
148
|
+
"verify": "node scripts/verify.mjs",
|
|
149
|
+
"verify:fast": "node scripts/verify.mjs --fast",
|
|
150
|
+
"verify:push": "node scripts/verify.mjs --push",
|
|
151
|
+
"prepare": "node scripts/install-hooks.mjs",
|
|
152
|
+
"check:architecture": "vitest run tests/architecture-",
|
|
153
|
+
"check:bundle": "node scripts/bundle-budget.mjs",
|
|
154
|
+
"check:node-reference": "tsx scripts/build-node-reference.mjs --check",
|
|
141
155
|
"test": "vitest",
|
|
142
156
|
"test:run": "vitest run",
|
|
143
157
|
"test:coverage": "vitest run --coverage",
|
|
@@ -171,6 +185,7 @@
|
|
|
171
185
|
"svelte": "^5.0.0",
|
|
172
186
|
"svelte-check": "^4.7.6",
|
|
173
187
|
"tsx": "^4.23.12",
|
|
188
|
+
"typescript7": "npm:typescript@^7.0.2",
|
|
174
189
|
"vite": "^8.2.2",
|
|
175
190
|
"vitest": "^4.1.11"
|
|
176
191
|
},
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/CodeEditor-DSZBpzdy.js","assets/legacy-CTEeXeqF.js","assets/nodeTypeUtils-BDJsc2Ks.js","assets/index-DyvDC6pS.js","assets/index-client-DqYmKstU.js","assets/index-7vae6YFC.css","assets/editor.api-DvkCO3ko.js","assets/editor-1FQrmyyI.css","assets/CodeEditor-DR7u0q7p.css"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{Dt as e,G as t,M as n,Ot as r,Q as i,U as a,V as o,W as s,Z as c,ct as l,dt as u,et as d,ht as f,i as p,it as m,jt as h,l as g,nt as _,ot as v,pt as y,r as b,rt as x,st as S,vt as C,yt as w,z as T}from"./legacy-CTEeXeqF.js";import{P as E,et as D}from"./index-DyvDC6pS.js";var O=t(`<div class="loading svelte-1pkj8m">Loading editor...</div>`),k=t(`<div class="error svelte-1pkj8m">Loading...</div>`),A=t(`<div class="error svelte-1pkj8m"> </div>`),j=t(`<div class="panel-wrapper svelte-1pkj8m"><!></div>`);function M(t,M){r(M,!1);let N=()=>w(D,`$sharedContextStore`,P),[P,F]=C(),I=u(null);b(async()=>{let e=await E(()=>import(`./CodeEditor-DSZBpzdy.js`).then(e=>e.t),__vite__mapDeps([0,1,2,3,4,5,6,7,8]));y(I,e.default)});let L=p(M,`panelParams`,8),R=p(M,`panelApi`,8),z=p(M,`graph`,12,void 0),B=p(M,`onRecordHistory`,12,void 0),V=u(null),H=L()?.nodeId;function U(){R()?.close&&R().close()}_(()=>N(),()=>{N()&&(z(N().graph),B(N().onRecordHistory))}),_(()=>c(z()),()=>{z()&&H?y(V,z().getNode(H)||null):y(V,null)}),_(()=>(c(R()),i(V)),()=>{R()?.setTitle&&i(V)&&R().setTitle(`Code: ${i(V).id}`)}),x(),g();var W=j(),G=v(W),K=e=>{var t=s(),r=S(t);{let e=f(()=>(c(z()),d(()=>z().packageManager||null)));n(r,()=>i(I),(t,n)=>{n(t,{get node(){return i(V)},get graph(){return z()},get packageManager(){return i(e)},onClose:U,showCloseButton:!1,get onRecordHistory(){return B()}})})}a(e,t)},q=e=>{var t=O();a(e,t)},J=e=>{var t=k();a(e,t)},Y=e=>{var t=A(),n=l(t);m(()=>o(n,`Node not found: ${H??``}`)),a(e,t)};T(G,e=>{i(V)&&z()&&i(I)?e(K):i(I)?z()?e(Y,-1):e(J,2):e(q,1)}),h(W),a(t,W),e(),F()}export{M as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{At as e,Dt as t,G as n,I as r,L as i,O as ee,Ot as a,Q as o,U as s,V as c,W as l,X as u,Z as d,_ as te,at as f,b as p,ct as m,d as h,dt as g,et as _,f as ne,i as v,it as y,jt as b,l as x,lt as S,nt as C,ot as w,p as re,pt as T,rt as E,s as ie,st as D,t as O,u as ae,v as k,z as A}from"./legacy-CTEeXeqF.js";import{H as j,U as M}from"./index-DyvDC6pS.js";var N=n(`<span class="auto-badge svelte-1c1mvak">auto</span>`),P=n(`<span class="radio-path svelte-1c1mvak"> </span>`),F=n(`<input type="text" class="custom-base-input svelte-1c1mvak" placeholder="e.g., cascade.mylib.MyBaseNode" autocomplete="off"/>`),I=n(`<label><input type="radio" name="baseClass" class="svelte-1c1mvak"/> <div class="radio-content svelte-1c1mvak"><div class="radio-header svelte-1c1mvak"><span class="radio-label svelte-1c1mvak"> </span> <!></div> <!></div></label>`),oe=n(`<div class="dialog-overlay svelte-1c1mvak"><div class="dialog svelte-1c1mvak" role="dialog" aria-modal="true" aria-labelledby="custom-node-title"><div class="dialog-header svelte-1c1mvak"><h2 id="custom-node-title" class="svelte-1c1mvak">Create Custom Node</h2> <button class="close-button svelte-1c1mvak" aria-label="Close"><!></button></div> <form class="svelte-1c1mvak"><div class="form-group svelte-1c1mvak"><label for="node-name" class="svelte-1c1mvak">Node Name</label> <input id="node-name" type="text" placeholder="e.g., ParticleField" autocomplete="off" class="svelte-1c1mvak"/> <span class="hint svelte-1c1mvak">The display name for your node</span></div> <div class="form-group svelte-1c1mvak"><label for="module-path" class="svelte-1c1mvak">Module Path</label> <input id="module-path" type="text" placeholder="e.g., project.particle-field" autocomplete="off" class="svelte-1c1mvak"/> <span class="hint svelte-1c1mvak">Unique identifier for the node module <!></span></div> <div class="form-group svelte-1c1mvak"><span class="field-label svelte-1c1mvak">Base Class</span> <div class="base-class-options svelte-1c1mvak"></div></div> <div class="dialog-footer svelte-1c1mvak"><button type="button" class="cancel-button svelte-1c1mvak">Cancel</button> <button type="submit" class="create-button svelte-1c1mvak"><!> Create Node</button></div></form></div></div>`);function L(n,L){a(L,!1);let R=g(),se=[],z=v(L,`open`,12,!1),B=O(),V=g(``),H=g(``),U=g(`cascade.Node`),W=g(``),G=g(!0),K=[{id:`cascade.Node`,label:`Node`,description:`Base class for all nodes - use for general purpose computation`,template:`node`},{id:`cascade.image.ImageNodeBase`,label:`ImageNodeBase`,description:`Image processing base class with canvas/image utilities`,template:`image`},{id:`custom`,label:`Other`,description:`Specify a custom base class path`,template:`node`}];function ce(){T(G,!1)}function le(){let e=`local.${o(V).toLowerCase().replace(/[^a-z0-9]/g,``)}`;(o(H)===e||o(H)===``)&&T(G,!0)}function q(){if(!o(V).trim()||o(U)===`custom`&&!o(W).trim())return;let e=K.find(e=>e.id===o(U));B(`create`,{name:o(V).trim(),modulePath:o(H)||`local.${o(V).toLowerCase().replace(/[^a-z0-9]/g,``)}`,baseClass:o(R),template:e?.template||`node`}),Y()}function J(){Y(),B(`close`)}function Y(){T(V,``),T(H,``),T(U,`cascade.Node`),T(W,``),T(G,!0),z(!1)}function X(e){e.key===`Escape`?J():e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),q())}let Z=g();C(()=>(o(U),o(W)),()=>{T(R,o(U)===`custom`?o(W):o(U))}),C(()=>(o(G),o(V)),()=>{if(o(G)&&o(V)){let e=o(V).toLowerCase().replace(/[^a-z0-9]/g,``);T(H,`local.${e}`)}}),C(()=>(d(z()),o(Z)),()=>{z()&&o(Z)&&setTimeout(()=>o(Z)?.focus(),50)}),E(),x();var Q=l();u(`keydown`,f,X);var $=D(Q),ue=t=>{var n=oe(),a=w(n),l=w(a),d=S(w(l),2),f=w(d);M(f,{size:18}),b(d),b(l);var g=S(l,2),v=w(g),x=S(w(v),2);p(x),re(x,e=>T(Z,e),()=>o(Z)),e(2),b(v);var C=S(v,2),E=S(w(C),2);p(E);var D=S(E,2),O=S(w(D)),R=e=>{var t=N();s(e,t)};A(O,e=>{o(G)&&e(R)}),b(D),b(C);var z=S(C,2),B=S(w(z),2);r(B,5,()=>K,i,(e,t)=>{var n=I();let r;var i=w(n);p(i);var a,l=S(i,2),d=w(l),f=w(d),h=m(f,!0),g=S(f,2),v=e=>{var n=P(),r=m(n,!0);y(()=>c(r,(o(t),_(()=>o(t).id)))),s(e,n)};A(g,e=>{o(t),_(()=>o(t).id!==`custom`)&&e(v)}),b(d);var x=S(d,2),C=e=>{var t=F();p(t),k(t,()=>o(W),e=>T(W,e)),u(`click`,t,ne(function(e){ie.call(this,L,e)})),s(e,t)};A(x,e=>{o(t),o(U),_(()=>o(t).id===`custom`&&o(U)===`custom`)&&e(C)}),b(l),b(n),y(()=>{r=ee(n,1,`radio-option svelte-1c1mvak`,null,r,{selected:o(U)===o(t).id}),a!==(a=(o(t),_(()=>o(t).id)))&&(i.value=(i.__value=a)??``),c(h,(o(t),_(()=>o(t).label)))}),te(se,[],i,()=>(o(t),_(()=>o(t).id),o(U)),e=>T(U,e)),s(e,n)}),b(B),b(z);var Y=S(z,2),X=w(Y),Q=S(X,2),$=w(Q);j($,{name:`Zap`,size:14}),e(),b(Q),b(Y),b(g),b(a),b(n),y(e=>Q.disabled=e,[()=>(o(V),o(U),o(W),_(()=>!o(V).trim()||o(U)===`custom`&&!o(W).trim()))]),u(`click`,d,J),k(x,()=>o(V),e=>T(V,e)),u(`input`,x,le),k(E,()=>o(H),e=>T(H,e)),u(`input`,E,ce),u(`click`,X,J),u(`submit`,g,ae(q)),u(`click`,n,h(J)),s(t,n)};A($,e=>{z()&&e(ue)}),s(n,Q),t()}export{L as default};
|