@field/cascade 0.11.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 +7 -4
- package/ARCHITECTURE.md +5 -4
- package/CHANGELOG.md +195 -0
- package/README.md +1 -1
- package/dist/assets/AgentPanel-1JugFjE4.css +1 -0
- package/dist/assets/AgentPanel-BDL5MddA.js +5 -0
- package/dist/assets/{CodeEditor-4O7FQ__R.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-Bz8JxISH.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-D5Z0nJ5-.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-Yqi0Ni61.js → core-DB-MkGjj.js} +3 -4
- package/dist/assets/coreTypes-DtnDATZ7.js +1 -0
- package/dist/assets/{cssMode-CxUzc4vp.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-BNFb25CX.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-0ZDnWxeM.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-Cy18MoaD.js → handlebars-CcD3aMeL.js} +1 -1
- package/dist/assets/{html-B-2Dx7nq.js → html-DvZWGfqb.js} +1 -1
- package/dist/assets/{htmlMode-DUAc9B_d.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-DeQsDqP5.js → javascript-Cap2ahgh.js} +1 -1
- package/dist/assets/{jsonMode-BiFwJVSk.js → jsonMode-B0uLjp9C.js} +1 -1
- package/dist/assets/{liquid-BLoHH68a.js → liquid-CnxwhfLn.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-CNFgm1Kv.js → lspLanguageFeatures-Dn9hlKX6.js} +1 -1
- package/dist/assets/math-GeULS-sk.js +1 -0
- package/dist/assets/{mdx-CFXQVNfs.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-Cf7S7p2E.js → python-CGyFk4XK.js} +1 -1
- package/dist/assets/{razor-CMHBcG-g.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-BEih0GDj.js → tsMode-BOeXzO9H.js} +1 -1
- package/dist/assets/{typescript-COEKYD_a.js → typescript-J1SnE_Tu.js} +1 -1
- package/dist/assets/{workers-BNhAhMNn.js → workers-CYwwTiVF.js} +1 -1
- package/dist/assets/{xml-CPiMpnPl.js → xml-DnPRNzK9.js} +1 -1
- package/dist/assets/{yaml-Bgp1ITLR.js → yaml-BmmYBNa9.js} +1 -1
- package/dist/cli/DefinitionNode-P7AA4TAU.js +15 -0
- package/dist/cli/{Graph-ZJJTRQTM.js → Graph-OB6EWSGL.js} +12 -12
- package/dist/cli/assert-GROGQNCQ.js +25 -0
- package/dist/cli/checks-3WB44XBL.js +189 -0
- package/dist/cli/{chunk-RQZ4SX5R.js → chunk-2JEU3MGB.js} +2 -2
- package/dist/cli/{chunk-WKURDVYP.js → chunk-3RXL5GHB.js} +28 -331
- 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-YAT5Y25U.js → chunk-7QE2ZNSN.js} +3 -3
- package/dist/cli/{chunk-SGJAET2L.js → chunk-BPODRH52.js} +8 -4
- package/dist/cli/{chunk-XWDSKG7N.js → chunk-BZ63XQ3I.js} +2 -2
- package/dist/cli/{chunk-FCDXJ6EK.js → chunk-CTPLRSWF.js} +2 -13
- package/dist/cli/chunk-EU4ZFZ7Y.js +122 -0
- package/dist/cli/{chunk-WIH4TEIS.js → chunk-EZRWJ4G2.js} +1 -1
- package/dist/cli/{chunk-BIJO5OFS.js → chunk-FWMSGKEH.js} +1 -1
- package/dist/cli/{chunk-POMMNKZZ.js → chunk-G23A2BZZ.js} +38 -5
- package/dist/cli/{chunk-35D343DC.js → chunk-GRIN2DDP.js} +19 -1
- package/dist/cli/chunk-JVOCK5W4.js +83 -0
- package/dist/cli/chunk-KBGUO27Q.js +15 -0
- package/dist/cli/{chunk-GFS6W3C5.js → chunk-L6B6FUQP.js} +54 -32
- package/dist/cli/chunk-LTXWBXOM.js +438 -0
- package/dist/cli/chunk-MI5JLQYA.js +220 -0
- package/dist/cli/{chunk-EUIAC3U3.js → chunk-MP653A5O.js} +884 -124
- package/dist/cli/{chunk-A4OAMOZH.js → chunk-NJFMDXHR.js} +13 -3
- package/dist/cli/{chunk-3JTJHF7V.js → chunk-OM6BEME6.js} +4 -4
- package/dist/cli/{chunk-DUIUFVU2.js → chunk-ST6LROUG.js} +49 -23
- package/dist/cli/{chunk-RLCAJBVR.js → chunk-TJW67QSI.js} +8 -7
- package/dist/cli/chunk-WGKPJZDY.js +364 -0
- package/dist/cli/{chunk-D6BUOHUG.js → chunk-X4WKAOQP.js} +4 -4
- package/dist/cli/{chunk-VVGSLVSF.js → chunk-X566FWBV.js} +6 -1
- package/dist/cli/chunk-YH637PDL.js +317 -0
- package/dist/cli/chunk-ZSCUZE6I.js +112 -0
- package/dist/cli/{cliCommands-UQSFGEHF.js → cliCommands-JJN5Z3ZC.js} +23 -17
- package/dist/cli/{commands-Q23M26QM.js → commands-PHYFYA3F.js} +129 -47
- package/dist/cli/contactSheet-2PQVRUFW.js +11 -0
- package/dist/cli/{definitions-HF2FTHYU.js → definitions-BPOPW52L.js} +7 -7
- package/dist/cli/{doctorCommand-B7BPQMN6.js → doctorCommand-ORWQRNYP.js} +36 -6
- package/dist/cli/{edit-JHCPTQFT.js → edit-S5KEQ5RA.js} +3 -3
- package/dist/cli/editorCommands-NFR32JOY.js +41 -0
- package/dist/cli/{encode-HAUZTYPT.js → encode-ICPEPMH5.js} +2 -2
- package/dist/cli/file-3HTQHPYQ.js +41 -0
- package/dist/cli/filters-6ODFWYK4.js +379 -0
- package/dist/cli/generators-YU7GB4MD.js +210 -0
- package/dist/cli/{geo-4RNK3QVN.js → geo-6ZPGKZRU.js} +7 -7
- package/dist/cli/{graphCommands-6BMAKGQE.js → graphCommands-EOUOBOIJ.js} +4 -4
- package/dist/cli/{graphFile-VPSQ6OF7.js → graphFile-YTGJB5F5.js} +25 -19
- package/dist/cli/{headlessCanvas-5XLDZT7M.js → headlessCanvas-ENRHC7GS.js} +3 -2
- package/dist/cli/{helpCommand-3VRE3KVO.js → helpCommand-PULH6ZYB.js} +9 -7
- package/dist/cli/image-TXELZZK5.js +55 -0
- package/dist/cli/index.js +14 -14
- package/dist/cli/{math-ZRMLKU2D.js → math-RSYRQ3C6.js} +5 -5
- package/dist/cli/{mcp-ZLEEMYGF.js → mcp-JVZFQOEX.js} +4 -4
- package/dist/cli/{parity-KINARCP2.js → parity-X6DEH2DV.js} +42 -36
- package/dist/cli/{pop-USDFXB7H.js → pop-B7SIIYKN.js} +5 -5
- package/dist/cli/project-VYGIA7JX.js +12 -0
- package/dist/cli/{projectDefinition-DMTZN2NE.js → projectDefinition-F3D7UIHJ.js} +8 -8
- package/dist/cli/{projectRuntime-Z5PJOH47.js → projectRuntime-2Q4JKEH3.js} +19 -12
- package/dist/cli/registerStandardNodes-BXJCB6E4.js +744 -0
- package/dist/cli/{render-YURAPPUI.js → render-PT4MWI6U.js} +24 -22
- package/dist/cli/{runCommand-PI764LEG.js → runCommand-HNPQVZMS.js} +3 -3
- package/dist/cli/runner-5XPXVW7J.js +43 -0
- package/dist/cli/runtime/image.ts +27 -2
- package/dist/cli/runtime/io.ts +78 -0
- package/dist/cli/share-MHF6TNRK.js +166 -0
- package/dist/cli/stageCache-TY2BFZJR.js +15 -0
- package/dist/cli/{stageRunner-KUNIMQKJ.js → stageRunner-KY2EJP7X.js} +2 -2
- package/dist/cli/text-MB3EKR4H.js +126 -0
- package/dist/cli/{verbs-RCE3K4VQ.js → verbs-PI2JH5FI.js} +2 -2
- 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/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 +15 -0
- package/dist/image.js +36 -2
- 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 +3 -2
- 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 +3 -165
- package/dist/runtime/builtins/image/contactSheet.js +0 -49
- 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 +947 -4
- package/dist/runtime/builtins/image/index.js +41 -6
- 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/doc/CLI_REFERENCE.md +21 -3
- package/doc/EDITOR_EXPORT.md +26 -0
- package/doc/MCP.md +2 -1
- package/doc/NODE_REFERENCE.md +286 -14
- package/doc/PROJECT_AUTHORING.md +98 -3
- package/package.json +4 -1
- package/dist/assets/CodePanel-BU-autmq.js +0 -2
- package/dist/assets/CustomNodeDialog-BRpDfOV5.js +0 -1
- package/dist/assets/OpenGraphDialog-BwbRlC0X.js +0 -1
- package/dist/assets/ProjectSettings-DLOXLxcA.js +0 -2
- package/dist/assets/definitions-GreEMXLV.js +0 -1
- package/dist/assets/geo-u0n_jOsD.js +0 -1
- package/dist/assets/image-cAa-Nu9O.js +0 -2062
- package/dist/assets/index-5ZtDAuy2.js +0 -220
- package/dist/assets/index-7vae6YFC.css +0 -1
- package/dist/assets/math-DioIQOPJ.js +0 -1
- package/dist/assets/pop-DC_TQG9t.js +0 -1
- package/dist/cli/chunk-36P5K3SD.js +0 -631
- package/dist/cli/chunk-4UDFYF5G.js +0 -132
- package/dist/cli/chunk-53NMBJAO.js +0 -35
- package/dist/cli/chunk-MIIEFUGG.js +0 -623
- package/dist/cli/chunk-QBBKRNGY.js +0 -90
- package/dist/cli/chunk-WPUDGEFY.js +0 -20
- package/dist/cli/editorCommands-UIF5YLUZ.js +0 -33
- package/dist/cli/project-K3QIPGBB.js +0 -12
- package/dist/cli/registerStandardNodes-S2VLMF6J.js +0 -3081
- package/dist/cli/runner-RA6UKEPD.js +0 -37
- package/dist/cli/webBuild-GT4PZT5D.js +0 -37
- package/dist/runtime/builtins/headless.d.ts +0 -19
- package/dist/runtime/builtins/headless.js +0 -25
|
@@ -1,631 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
coreNodeRegistrations,
|
|
3
|
-
isCamera
|
|
4
|
-
} from "./chunk-D6BUOHUG.js";
|
|
5
|
-
import {
|
|
6
|
-
mathNodeRegistrations
|
|
7
|
-
} from "./chunk-QQPA2ZHH.js";
|
|
8
|
-
import {
|
|
9
|
-
popNodeRegistrations
|
|
10
|
-
} from "./chunk-KH4MUBKF.js";
|
|
11
|
-
import {
|
|
12
|
-
LIGHT_DEFAULTS,
|
|
13
|
-
geoNodeRegistrations,
|
|
14
|
-
isLight,
|
|
15
|
-
isScene
|
|
16
|
-
} from "./chunk-35D343DC.js";
|
|
17
|
-
|
|
18
|
-
// packages/runtime/src/builtins/scene/definitions.ts
|
|
19
|
-
var SCENE_NAMESPACE = "cascade.scene";
|
|
20
|
-
function sceneModuleId(name) {
|
|
21
|
-
return `${SCENE_NAMESPACE}.${name}`;
|
|
22
|
-
}
|
|
23
|
-
var sceneDefinition = {
|
|
24
|
-
apiVersion: 1,
|
|
25
|
-
label: "Scene",
|
|
26
|
-
description: "Geometry, a camera and lights, assembled into a scene. Attach anything to the input.",
|
|
27
|
-
icon: "Box",
|
|
28
|
-
runsOn: "portable",
|
|
29
|
-
inputs: {
|
|
30
|
-
inputs: {
|
|
31
|
-
kind: "data",
|
|
32
|
-
type: "any",
|
|
33
|
-
variadic: true,
|
|
34
|
-
description: "Geometry, one camera, and lights, in any order. Scenes are flattened."
|
|
35
|
-
}
|
|
36
|
-
},
|
|
37
|
-
outputs: {
|
|
38
|
-
scene: { kind: "data", type: "scene" }
|
|
39
|
-
},
|
|
40
|
-
props: {}
|
|
41
|
-
};
|
|
42
|
-
function executeScene(context) {
|
|
43
|
-
const geometry = [];
|
|
44
|
-
const lights = [];
|
|
45
|
-
let camera = null;
|
|
46
|
-
let cameraFrom = -1;
|
|
47
|
-
context.inputs.inputs.forEach((value, index) => {
|
|
48
|
-
if (value === void 0 || value === null) return;
|
|
49
|
-
if (isScene(value)) {
|
|
50
|
-
geometry.push(...value.geometry);
|
|
51
|
-
lights.push(...value.lights);
|
|
52
|
-
if (value.camera !== null) {
|
|
53
|
-
if (camera !== null)
|
|
54
|
-
throw new Error(
|
|
55
|
-
`cascade.scene.Scene has two cameras, on inputs ${cameraFrom} and ${index}. A scene has one viewpoint; remove one or use a Switch to choose between them.`
|
|
56
|
-
);
|
|
57
|
-
camera = value.camera;
|
|
58
|
-
cameraFrom = index;
|
|
59
|
-
}
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
if (isCamera(value)) {
|
|
63
|
-
if (camera !== null)
|
|
64
|
-
throw new Error(
|
|
65
|
-
`cascade.scene.Scene has two cameras, on inputs ${cameraFrom} and ${index}. A scene has one viewpoint; remove one or use a Switch to choose between them.`
|
|
66
|
-
);
|
|
67
|
-
camera = value;
|
|
68
|
-
cameraFrom = index;
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
if (isLight(value)) {
|
|
72
|
-
lights.push(value);
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
if (typeof value === "object" && value.kind === "geometry") {
|
|
76
|
-
geometry.push(value);
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
throw new Error(
|
|
80
|
-
`cascade.scene.Scene input ${index} is not geometry, a camera, a light or a scene (received ${describe(value)}). A scene can only hold those.`
|
|
81
|
-
);
|
|
82
|
-
});
|
|
83
|
-
context.outputs.scene.set({ geometry, camera, lights });
|
|
84
|
-
}
|
|
85
|
-
function describe(value) {
|
|
86
|
-
if (Array.isArray(value)) return `an array of ${value.length}`;
|
|
87
|
-
if (typeof value === "object" && value !== null) {
|
|
88
|
-
const kind = value.kind;
|
|
89
|
-
return typeof kind === "string" ? `an object of kind "${kind}"` : "an object";
|
|
90
|
-
}
|
|
91
|
-
return `a ${typeof value}`;
|
|
92
|
-
}
|
|
93
|
-
var lightDefinition = {
|
|
94
|
-
apiVersion: 1,
|
|
95
|
-
label: "Light",
|
|
96
|
-
description: "A light, following Houdini's /obj/hlight. Nothing shades with lights yet \u2014 the viewport draws wireframe and points.",
|
|
97
|
-
icon: "Lightbulb",
|
|
98
|
-
runsOn: "portable",
|
|
99
|
-
inputs: {
|
|
100
|
-
translate: {
|
|
101
|
-
kind: "data",
|
|
102
|
-
type: "vec3",
|
|
103
|
-
default: [0, 0, 5],
|
|
104
|
-
description: "World position. Ignored for a distant or ambient light."
|
|
105
|
-
},
|
|
106
|
-
direction: {
|
|
107
|
-
kind: "data",
|
|
108
|
-
type: "vec3",
|
|
109
|
-
default: [0, 0, -1],
|
|
110
|
-
description: "Direction the light points. Used by distant and spot."
|
|
111
|
-
},
|
|
112
|
-
color: {
|
|
113
|
-
kind: "data",
|
|
114
|
-
type: "color",
|
|
115
|
-
default: [1, 1, 1, 1],
|
|
116
|
-
description: "Houdini light_color."
|
|
117
|
-
},
|
|
118
|
-
intensity: {
|
|
119
|
-
kind: "data",
|
|
120
|
-
type: "float",
|
|
121
|
-
default: 1,
|
|
122
|
-
min: 0,
|
|
123
|
-
description: "Houdini light_intensity."
|
|
124
|
-
}
|
|
125
|
-
},
|
|
126
|
-
outputs: {
|
|
127
|
-
light: { kind: "data", type: "light" }
|
|
128
|
-
},
|
|
129
|
-
props: {
|
|
130
|
-
type: {
|
|
131
|
-
type: "string",
|
|
132
|
-
default: "point",
|
|
133
|
-
label: "Light Type",
|
|
134
|
-
control: "select",
|
|
135
|
-
options: [
|
|
136
|
-
{ value: "point", label: "Point" },
|
|
137
|
-
{ value: "distant", label: "Distant - directional" },
|
|
138
|
-
{ value: "ambient", label: "Ambient" },
|
|
139
|
-
{ value: "spot", label: "Spot" }
|
|
140
|
-
],
|
|
141
|
-
description: "Houdini light_type. Distant is what other renderers call directional."
|
|
142
|
-
},
|
|
143
|
-
coneangle: {
|
|
144
|
-
type: "float",
|
|
145
|
-
default: 45,
|
|
146
|
-
min: 0,
|
|
147
|
-
max: 180,
|
|
148
|
-
label: "Cone Angle",
|
|
149
|
-
description: "Degrees. Spot only."
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
function executeLight(context) {
|
|
154
|
-
const type = context.props.type;
|
|
155
|
-
context.outputs.light.set({
|
|
156
|
-
type: type === "distant" || type === "ambient" || type === "spot" ? type : LIGHT_DEFAULTS.type,
|
|
157
|
-
translate: context.inputs.translate ?? LIGHT_DEFAULTS.translate,
|
|
158
|
-
direction: context.inputs.direction ?? LIGHT_DEFAULTS.direction,
|
|
159
|
-
color: context.inputs.color ?? LIGHT_DEFAULTS.color,
|
|
160
|
-
intensity: context.inputs.intensity ?? LIGHT_DEFAULTS.intensity,
|
|
161
|
-
coneangle: context.props.coneangle
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
var sceneRegistration = {
|
|
165
|
-
kind: "definition-v1",
|
|
166
|
-
moduleId: sceneModuleId("Scene"),
|
|
167
|
-
definition: sceneDefinition,
|
|
168
|
-
loadExecute: async () => executeScene
|
|
169
|
-
};
|
|
170
|
-
var lightRegistration = {
|
|
171
|
-
kind: "definition-v1",
|
|
172
|
-
moduleId: sceneModuleId("Light"),
|
|
173
|
-
definition: lightDefinition,
|
|
174
|
-
loadExecute: async () => executeLight
|
|
175
|
-
};
|
|
176
|
-
var sceneNodeRegistrations = Object.freeze([sceneRegistration, lightRegistration]);
|
|
177
|
-
var sceneNodeDefinitions = Object.freeze([
|
|
178
|
-
[sceneModuleId("Scene"), sceneDefinition],
|
|
179
|
-
[sceneModuleId("Light"), lightDefinition]
|
|
180
|
-
]);
|
|
181
|
-
|
|
182
|
-
// packages/runtime/src/builtins/index.ts
|
|
183
|
-
var builtinNodeRegistrations = Object.freeze([
|
|
184
|
-
...coreNodeRegistrations,
|
|
185
|
-
...geoNodeRegistrations,
|
|
186
|
-
...mathNodeRegistrations,
|
|
187
|
-
...popNodeRegistrations,
|
|
188
|
-
...sceneNodeRegistrations
|
|
189
|
-
]);
|
|
190
|
-
var registrationsById = new Map(
|
|
191
|
-
builtinNodeRegistrations.map((registration) => [
|
|
192
|
-
registration.moduleId,
|
|
193
|
-
registration
|
|
194
|
-
])
|
|
195
|
-
);
|
|
196
|
-
function builtinNodeRegistration(moduleId) {
|
|
197
|
-
return registrationsById.get(moduleId);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// packages/runtime/src/builtins/image/contactSheet.ts
|
|
201
|
-
var contactSheetDefinition = {
|
|
202
|
-
apiVersion: 1,
|
|
203
|
-
label: "Contact Sheet",
|
|
204
|
-
description: "Lay images out as one labelled grid.",
|
|
205
|
-
icon: "LayoutGrid",
|
|
206
|
-
runsOn: "portable",
|
|
207
|
-
capabilities: ["assets"],
|
|
208
|
-
inputs: {
|
|
209
|
-
images: { kind: "data", type: "image", variadic: true },
|
|
210
|
-
/** More images after the wired ones: image values or project-relative paths. */
|
|
211
|
-
list: { kind: "data", type: "array" }
|
|
212
|
-
},
|
|
213
|
-
outputs: {
|
|
214
|
-
image: { kind: "data", type: "image" },
|
|
215
|
-
asset: { kind: "data", type: "asset" }
|
|
216
|
-
},
|
|
217
|
-
props: {
|
|
218
|
-
columns: { type: "int", default: 0, min: 0, max: 64, description: "0: as square as the count allows." },
|
|
219
|
-
gap: { type: "int", default: 16, min: 0, max: 512 },
|
|
220
|
-
background: { type: "color", default: [1, 1, 1, 1], label: "Background" },
|
|
221
|
-
cellWidth: { type: "int", default: 0, min: 0, max: 8192, description: "0: images at their own size. Otherwise each is scaled to fit this width." },
|
|
222
|
-
labels: { type: "string", default: "", description: "One label per line, in image order." },
|
|
223
|
-
labelSize: { type: "int", default: 14, min: 6, max: 128 },
|
|
224
|
-
labelColor: { type: "color", default: [0.1, 0.1, 0.1, 1], label: "Label Colour" },
|
|
225
|
-
filename: { type: "string", default: "contact-sheet.png", label: "Filename" }
|
|
226
|
-
}
|
|
227
|
-
};
|
|
228
|
-
function contactSheetLayout(sizes, options = {}) {
|
|
229
|
-
const count = sizes.length;
|
|
230
|
-
if (!count) throw new Error("cascade.image.ContactSheet needs at least one image");
|
|
231
|
-
for (const [width, height] of sizes) {
|
|
232
|
-
if (!(width > 0 && height > 0)) throw new Error(`cascade.image.ContactSheet: an image is ${width}x${height}`);
|
|
233
|
-
}
|
|
234
|
-
const gap = Math.max(0, Math.round(options.gap ?? 16));
|
|
235
|
-
const columns = Math.min(count, options.columns && options.columns > 0 ? Math.round(options.columns) : Math.ceil(Math.sqrt(count)));
|
|
236
|
-
const rows = Math.ceil(count / columns);
|
|
237
|
-
const scaled = Boolean(options.cellWidth && options.cellWidth > 0);
|
|
238
|
-
const cellWidth = scaled ? Math.round(options.cellWidth) : Math.max(...sizes.map(([width]) => width));
|
|
239
|
-
const cellHeight = scaled ? Math.max(...sizes.map(([width, height]) => Math.round(height * cellWidth / width))) : Math.max(...sizes.map(([, height]) => height));
|
|
240
|
-
const labelHeight = Math.max(0, Math.round(options.labelHeight ?? 0));
|
|
241
|
-
const cells = sizes.map(([width, height], index) => {
|
|
242
|
-
const column = index % columns;
|
|
243
|
-
const row = Math.floor(index / columns);
|
|
244
|
-
const fit = Math.min(cellWidth / width, cellHeight / height);
|
|
245
|
-
const scale = scaled ? fit : Math.min(1, fit);
|
|
246
|
-
const drawnWidth = Math.max(1, Math.round(width * scale));
|
|
247
|
-
const drawnHeight = Math.max(1, Math.round(height * scale));
|
|
248
|
-
const left = gap + column * (cellWidth + gap);
|
|
249
|
-
const top = gap + row * (cellHeight + labelHeight + gap);
|
|
250
|
-
return {
|
|
251
|
-
x: left + Math.floor((cellWidth - drawnWidth) / 2),
|
|
252
|
-
y: top + Math.floor((cellHeight - drawnHeight) / 2),
|
|
253
|
-
width: drawnWidth,
|
|
254
|
-
height: drawnHeight,
|
|
255
|
-
labelX: left,
|
|
256
|
-
labelY: top + cellHeight
|
|
257
|
-
};
|
|
258
|
-
});
|
|
259
|
-
return {
|
|
260
|
-
width: gap + columns * (cellWidth + gap),
|
|
261
|
-
height: gap + rows * (cellHeight + labelHeight + gap),
|
|
262
|
-
columns,
|
|
263
|
-
rows,
|
|
264
|
-
cell: [cellWidth, cellHeight],
|
|
265
|
-
labelHeight,
|
|
266
|
-
cells
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
function host() {
|
|
270
|
-
const globals = globalThis;
|
|
271
|
-
const Canvas = globals.OffscreenCanvas;
|
|
272
|
-
const createBitmap = globals.createImageBitmap;
|
|
273
|
-
if (!Canvas || !createBitmap || !globals.Blob) {
|
|
274
|
-
throw new Error("cascade.image.ContactSheet needs OffscreenCanvas and createImageBitmap, which this host does not provide");
|
|
275
|
-
}
|
|
276
|
-
const BlobType = globals.Blob;
|
|
277
|
-
return {
|
|
278
|
-
surface: (width, height) => new Canvas(width, height),
|
|
279
|
-
decode: (bytes) => createBitmap(new BlobType([bytes]))
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
function css(colour, fallback) {
|
|
283
|
-
const [r = 0, g = 0, b = 0, a = 1] = colour ?? fallback;
|
|
284
|
-
return `rgba(${Math.round(r * 255)}, ${Math.round(g * 255)}, ${Math.round(b * 255)}, ${a})`;
|
|
285
|
-
}
|
|
286
|
-
async function composeContactSheet(images, options = {}) {
|
|
287
|
-
const canvas = host();
|
|
288
|
-
const bitmaps = [];
|
|
289
|
-
try {
|
|
290
|
-
for (const bytes of images) bitmaps.push(await canvas.decode(bytes));
|
|
291
|
-
const labels = options.labels ?? [];
|
|
292
|
-
const labelSize = Math.round(options.labelSize ?? 14);
|
|
293
|
-
const labelled = labels.some((label) => label.trim().length > 0);
|
|
294
|
-
const layout = contactSheetLayout(bitmaps.map((bitmap) => [bitmap.width, bitmap.height]), {
|
|
295
|
-
columns: options.columns,
|
|
296
|
-
gap: options.gap,
|
|
297
|
-
cellWidth: options.cellWidth,
|
|
298
|
-
labelHeight: labelled ? Math.round(labelSize * 1.8) : 0
|
|
299
|
-
});
|
|
300
|
-
const surface = canvas.surface(layout.width, layout.height);
|
|
301
|
-
const context = surface.getContext("2d");
|
|
302
|
-
if (!context) throw new Error("cascade.image.ContactSheet: no 2D context");
|
|
303
|
-
context.fillStyle = css(options.background, [1, 1, 1, 1]);
|
|
304
|
-
context.fillRect(0, 0, layout.width, layout.height);
|
|
305
|
-
context.imageSmoothingEnabled = true;
|
|
306
|
-
context.imageSmoothingQuality = "high";
|
|
307
|
-
layout.cells.forEach((cell, index) => context.drawImage(bitmaps[index], cell.x, cell.y, cell.width, cell.height));
|
|
308
|
-
if (labelled) {
|
|
309
|
-
context.fillStyle = css(options.labelColor, [0.1, 0.1, 0.1, 1]);
|
|
310
|
-
context.font = `${labelSize}px sans-serif`;
|
|
311
|
-
context.textBaseline = "top";
|
|
312
|
-
layout.cells.forEach((cell, index) => {
|
|
313
|
-
const label = labels[index];
|
|
314
|
-
if (label) context.fillText(label, cell.labelX, cell.labelY + Math.round((layout.labelHeight - labelSize) / 2), layout.cell[0]);
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
const blob = await surface.convertToBlob({ type: "image/png" });
|
|
318
|
-
return { bytes: new Uint8Array(await blob.arrayBuffer()), layout };
|
|
319
|
-
} finally {
|
|
320
|
-
for (const bitmap of bitmaps) bitmap.close?.();
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
function imageReference(value) {
|
|
324
|
-
if (typeof value === "string" && value) return { path: value };
|
|
325
|
-
const candidate = value?.path;
|
|
326
|
-
return typeof candidate === "string" && candidate ? { path: candidate } : void 0;
|
|
327
|
-
}
|
|
328
|
-
async function executeContactSheet(context) {
|
|
329
|
-
const { props } = context;
|
|
330
|
-
const references = [...context.inputs.images, ...context.inputs.list ?? []].map(imageReference).filter((reference) => reference !== void 0);
|
|
331
|
-
const bytes = [];
|
|
332
|
-
for (const reference of references) {
|
|
333
|
-
bytes.push(await context.capabilities.assets.read(reference, { signal: context.signal }));
|
|
334
|
-
}
|
|
335
|
-
const { bytes: sheet, layout } = await composeContactSheet(bytes, {
|
|
336
|
-
columns: props.columns,
|
|
337
|
-
gap: props.gap,
|
|
338
|
-
cellWidth: props.cellWidth,
|
|
339
|
-
labels: props.labels ? props.labels.split("\n") : [],
|
|
340
|
-
labelSize: props.labelSize,
|
|
341
|
-
background: props.background,
|
|
342
|
-
labelColor: props.labelColor
|
|
343
|
-
});
|
|
344
|
-
const asset = await context.capabilities.assets.write(
|
|
345
|
-
sheet,
|
|
346
|
-
{ mediaType: "image/png", suggestedName: props.filename },
|
|
347
|
-
{ signal: context.signal }
|
|
348
|
-
);
|
|
349
|
-
context.outputs.asset.set(asset);
|
|
350
|
-
context.outputs.image.set({
|
|
351
|
-
path: asset.path ?? props.filename,
|
|
352
|
-
size: [layout.width, layout.height],
|
|
353
|
-
channels: "rgba",
|
|
354
|
-
depth: "u8",
|
|
355
|
-
space: "srgb"
|
|
356
|
-
});
|
|
357
|
-
}
|
|
358
|
-
var contactSheetRegistration = {
|
|
359
|
-
kind: "definition-v1",
|
|
360
|
-
moduleId: "cascade.image.ContactSheet",
|
|
361
|
-
definition: contactSheetDefinition,
|
|
362
|
-
loadExecute: async () => executeContactSheet
|
|
363
|
-
};
|
|
364
|
-
|
|
365
|
-
// packages/runtime/src/builtins/image/index.ts
|
|
366
|
-
var imageNodeRegistrations = Object.freeze([contactSheetRegistration]);
|
|
367
|
-
|
|
368
|
-
// packages/runtime/src/builtins/headless.ts
|
|
369
|
-
var headlessOnlyNodeRegistrations = Object.freeze([...imageNodeRegistrations]);
|
|
370
|
-
var headlessNodeRegistrations = Object.freeze([...builtinNodeRegistrations, ...headlessOnlyNodeRegistrations]);
|
|
371
|
-
var headlessOnlyById = new Map(
|
|
372
|
-
headlessOnlyNodeRegistrations.map((registration) => [registration.moduleId, registration])
|
|
373
|
-
);
|
|
374
|
-
function headlessNodeRegistration(moduleId) {
|
|
375
|
-
return builtinNodeRegistration(moduleId) ?? headlessOnlyById.get(moduleId);
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
// src/cli/assertNodes.ts
|
|
379
|
-
import { inflateSync } from "node:zlib";
|
|
380
|
-
var AssertionFailed = class extends Error {
|
|
381
|
-
constructor(nodeId, moduleId, detail, message2) {
|
|
382
|
-
const extra = typeof message2 === "string" && message2.trim() ? ` ${message2.trim()}` : "";
|
|
383
|
-
super(`Assertion failed in "${nodeId}" (${moduleId}): ${detail}.${extra}`);
|
|
384
|
-
this.name = "AssertionFailed";
|
|
385
|
-
}
|
|
386
|
-
};
|
|
387
|
-
var message = { type: "string", default: "" };
|
|
388
|
-
var rangeDefinition = {
|
|
389
|
-
apiVersion: 1,
|
|
390
|
-
runsOn: "portable",
|
|
391
|
-
label: "Assert Range",
|
|
392
|
-
description: "Fails the run unless value is a finite number in [min, max]; passes value through",
|
|
393
|
-
icon: "ShieldCheck",
|
|
394
|
-
inputs: { value: { kind: "data", type: "float", default: 0 } },
|
|
395
|
-
outputs: { value: { kind: "data", type: "float" } },
|
|
396
|
-
props: { min: { type: "float", default: 0 }, max: { type: "float", default: 1 }, message }
|
|
397
|
-
};
|
|
398
|
-
var equalsDefinition = {
|
|
399
|
-
apiVersion: 1,
|
|
400
|
-
runsOn: "portable",
|
|
401
|
-
label: "Assert Equals",
|
|
402
|
-
description: "Fails the run unless value equals expected (JSON-equal; numbers within tolerance); passes value through",
|
|
403
|
-
icon: "ShieldCheck",
|
|
404
|
-
inputs: { value: { kind: "data", type: "any", default: null } },
|
|
405
|
-
outputs: { value: { kind: "data", type: "any" } },
|
|
406
|
-
props: { expected: { type: "any", default: null }, tolerance: { type: "float", default: 0, min: 0 }, message }
|
|
407
|
-
};
|
|
408
|
-
var trueDefinition = {
|
|
409
|
-
apiVersion: 1,
|
|
410
|
-
runsOn: "portable",
|
|
411
|
-
label: "Assert True",
|
|
412
|
-
description: "Fails the run unless value is true (wire a condition, or give the prop an expression); passes value through",
|
|
413
|
-
icon: "ShieldCheck",
|
|
414
|
-
inputs: { value: { kind: "data", type: "bool", default: false } },
|
|
415
|
-
outputs: { value: { kind: "data", type: "bool" } },
|
|
416
|
-
props: { message }
|
|
417
|
-
};
|
|
418
|
-
var notBlankDefinition = {
|
|
419
|
-
apiVersion: 1,
|
|
420
|
-
runsOn: "portable",
|
|
421
|
-
label: "Assert Not Blank",
|
|
422
|
-
description: "Fails the run when an image (PNG or PPM) is one flat colour or fully transparent; passes the image through",
|
|
423
|
-
icon: "ShieldCheck",
|
|
424
|
-
capabilities: ["assets"],
|
|
425
|
-
inputs: { image: { kind: "data", type: "image" } },
|
|
426
|
-
outputs: { image: { kind: "data", type: "image" } },
|
|
427
|
-
props: {
|
|
428
|
-
tolerance: { type: "int", default: 0, min: 0, max: 255, step: 1 },
|
|
429
|
-
message
|
|
430
|
-
}
|
|
431
|
-
};
|
|
432
|
-
var rangeRegistration = {
|
|
433
|
-
kind: "definition-v1",
|
|
434
|
-
moduleId: "cascade.assert.Range",
|
|
435
|
-
definition: rangeDefinition,
|
|
436
|
-
loadExecute: async () => ({ nodeId, inputs, props, outputs }) => {
|
|
437
|
-
const value = inputs.value;
|
|
438
|
-
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
439
|
-
throw new AssertionFailed(nodeId, "cascade.assert.Range", `value ${String(value)} is not a finite number`, props.message);
|
|
440
|
-
}
|
|
441
|
-
if (value < props.min || value > props.max) {
|
|
442
|
-
throw new AssertionFailed(nodeId, "cascade.assert.Range", `value ${value} is outside [${props.min}, ${props.max}]`, props.message);
|
|
443
|
-
}
|
|
444
|
-
outputs.value.set(value);
|
|
445
|
-
}
|
|
446
|
-
};
|
|
447
|
-
var equalsRegistration = {
|
|
448
|
-
kind: "definition-v1",
|
|
449
|
-
moduleId: "cascade.assert.Equals",
|
|
450
|
-
definition: equalsDefinition,
|
|
451
|
-
loadExecute: async () => ({ nodeId, inputs, props, outputs }) => {
|
|
452
|
-
if (!deepEqual(inputs.value, props.expected, props.tolerance)) {
|
|
453
|
-
throw new AssertionFailed(nodeId, "cascade.assert.Equals", `got ${preview(inputs.value)}, expected ${preview(props.expected)}`, props.message);
|
|
454
|
-
}
|
|
455
|
-
outputs.value.set(inputs.value);
|
|
456
|
-
}
|
|
457
|
-
};
|
|
458
|
-
var trueRegistration = {
|
|
459
|
-
kind: "definition-v1",
|
|
460
|
-
moduleId: "cascade.assert.True",
|
|
461
|
-
definition: trueDefinition,
|
|
462
|
-
loadExecute: async () => ({ nodeId, inputs, props, outputs }) => {
|
|
463
|
-
if (inputs.value !== true) throw new AssertionFailed(nodeId, "cascade.assert.True", `value is ${preview(inputs.value)}`, props.message);
|
|
464
|
-
outputs.value.set(true);
|
|
465
|
-
}
|
|
466
|
-
};
|
|
467
|
-
var notBlankRegistration = {
|
|
468
|
-
kind: "definition-v1",
|
|
469
|
-
moduleId: "cascade.assert.NotBlank",
|
|
470
|
-
definition: notBlankDefinition,
|
|
471
|
-
loadExecute: async () => async ({ nodeId, inputs, props, outputs, capabilities, signal }) => {
|
|
472
|
-
const image = inputs.image;
|
|
473
|
-
const ref = typeof image === "string" ? { path: image } : image;
|
|
474
|
-
if (!ref || typeof ref.path !== "string" || !ref.path) {
|
|
475
|
-
throw new AssertionFailed(nodeId, "cascade.assert.NotBlank", "no image arrived", props.message);
|
|
476
|
-
}
|
|
477
|
-
const bytes = await capabilities.assets.read(ref, { signal });
|
|
478
|
-
const pixels = decodeImage(bytes);
|
|
479
|
-
if (!pixels) throw new AssertionFailed(nodeId, "cascade.assert.NotBlank", `${ref.path} is not a PNG or PPM this node can read`, props.message);
|
|
480
|
-
const verdict = blankness(pixels, props.tolerance);
|
|
481
|
-
if (verdict) throw new AssertionFailed(nodeId, "cascade.assert.NotBlank", `${ref.path} (${pixels.width}x${pixels.height}) is ${verdict}`, props.message);
|
|
482
|
-
outputs.image.set(inputs.image);
|
|
483
|
-
}
|
|
484
|
-
};
|
|
485
|
-
var assertNodeRegistrations = Object.freeze([
|
|
486
|
-
equalsRegistration,
|
|
487
|
-
notBlankRegistration,
|
|
488
|
-
rangeRegistration,
|
|
489
|
-
trueRegistration
|
|
490
|
-
]);
|
|
491
|
-
function preview(value) {
|
|
492
|
-
const text = JSON.stringify(value) ?? String(value);
|
|
493
|
-
return text.length > 120 ? `${text.slice(0, 117)}...` : text;
|
|
494
|
-
}
|
|
495
|
-
function deepEqual(a, b, tolerance) {
|
|
496
|
-
if (typeof a === "number" && typeof b === "number") return a === b || Math.abs(a - b) <= tolerance;
|
|
497
|
-
if (Array.isArray(a) && Array.isArray(b)) return a.length === b.length && a.every((item, index) => deepEqual(item, b[index], tolerance));
|
|
498
|
-
if (a && b && typeof a === "object" && typeof b === "object" && !Array.isArray(a) && !Array.isArray(b)) {
|
|
499
|
-
const keys = Object.keys(a);
|
|
500
|
-
if (keys.length !== Object.keys(b).length) return false;
|
|
501
|
-
return keys.every((key) => key in b && deepEqual(a[key], b[key], tolerance));
|
|
502
|
-
}
|
|
503
|
-
return a === b || a == null && b == null;
|
|
504
|
-
}
|
|
505
|
-
function blankness(pixels, tolerance = 0) {
|
|
506
|
-
const { channels, data } = pixels;
|
|
507
|
-
const alpha = channels === 2 || channels === 4 ? channels - 1 : -1;
|
|
508
|
-
const colour = alpha === -1 ? channels : channels - 1;
|
|
509
|
-
const min = new Array(channels).fill(255);
|
|
510
|
-
const max = new Array(channels).fill(0);
|
|
511
|
-
let opaque = alpha === -1;
|
|
512
|
-
for (let index = 0; index < data.length; index += channels) {
|
|
513
|
-
if (alpha !== -1 && data[index + alpha] > tolerance) opaque = true;
|
|
514
|
-
for (let channel = 0; channel < channels; channel += 1) {
|
|
515
|
-
const value = data[index + channel];
|
|
516
|
-
if (value < min[channel]) min[channel] = value;
|
|
517
|
-
if (value > max[channel]) max[channel] = value;
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
if (!opaque) return "fully transparent";
|
|
521
|
-
const spread = Math.max(...max.map((value, channel) => value - min[channel]));
|
|
522
|
-
if (spread <= tolerance) return colour === 1 ? `one flat grey (${min[0]})` : `one flat colour (rgb ${min.slice(0, 3).join(", ")})`;
|
|
523
|
-
return null;
|
|
524
|
-
}
|
|
525
|
-
function decodeImage(bytes) {
|
|
526
|
-
if (bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) return decodePng(bytes);
|
|
527
|
-
if (bytes[0] === 80 && (bytes[1] === 54 || bytes[1] === 53)) return decodePnm(bytes);
|
|
528
|
-
return null;
|
|
529
|
-
}
|
|
530
|
-
function decodePnm(bytes) {
|
|
531
|
-
const fields = [];
|
|
532
|
-
let index = 2;
|
|
533
|
-
while (fields.length < 3 && index < bytes.length) {
|
|
534
|
-
while (index < bytes.length && /\s/.test(String.fromCharCode(bytes[index]))) index += 1;
|
|
535
|
-
if (bytes[index] === 35) {
|
|
536
|
-
while (index < bytes.length && bytes[index] !== 10) index += 1;
|
|
537
|
-
continue;
|
|
538
|
-
}
|
|
539
|
-
let field = "";
|
|
540
|
-
while (index < bytes.length && !/\s/.test(String.fromCharCode(bytes[index]))) field += String.fromCharCode(bytes[index++]);
|
|
541
|
-
fields.push(field);
|
|
542
|
-
}
|
|
543
|
-
const [width, height, maxValue] = fields.map(Number);
|
|
544
|
-
if (!width || !height || maxValue !== 255) return null;
|
|
545
|
-
const channels = bytes[1] === 54 ? 3 : 1;
|
|
546
|
-
return { width, height, channels, data: bytes.subarray(index + 1, index + 1 + width * height * channels) };
|
|
547
|
-
}
|
|
548
|
-
function decodePng(bytes) {
|
|
549
|
-
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
550
|
-
let offset = 8;
|
|
551
|
-
let width = 0;
|
|
552
|
-
let height = 0;
|
|
553
|
-
let channels = 0;
|
|
554
|
-
const idat = [];
|
|
555
|
-
while (offset + 8 <= bytes.length) {
|
|
556
|
-
const length = view.getUint32(offset);
|
|
557
|
-
const type = String.fromCharCode(...bytes.subarray(offset + 4, offset + 8));
|
|
558
|
-
const body = bytes.subarray(offset + 8, offset + 8 + length);
|
|
559
|
-
if (type === "IHDR") {
|
|
560
|
-
width = view.getUint32(offset + 8);
|
|
561
|
-
height = view.getUint32(offset + 12);
|
|
562
|
-
const depth = body[8];
|
|
563
|
-
const colourType = body[9];
|
|
564
|
-
const interlace = body[12];
|
|
565
|
-
channels = { 0: 1, 4: 2, 2: 3, 6: 4 }[colourType] ?? 0;
|
|
566
|
-
if (depth !== 8 || !channels || interlace !== 0) return null;
|
|
567
|
-
} else if (type === "IDAT") idat.push(body);
|
|
568
|
-
else if (type === "IEND") break;
|
|
569
|
-
offset += 12 + length;
|
|
570
|
-
}
|
|
571
|
-
if (!width || !height || !idat.length) return null;
|
|
572
|
-
const raw = inflateSync(Buffer.concat(idat));
|
|
573
|
-
const stride = width * channels;
|
|
574
|
-
const data = new Uint8Array(stride * height);
|
|
575
|
-
for (let row = 0; row < height; row += 1) {
|
|
576
|
-
const filter = raw[row * (stride + 1)];
|
|
577
|
-
const line = raw.subarray(row * (stride + 1) + 1, (row + 1) * (stride + 1));
|
|
578
|
-
const out = data.subarray(row * stride, (row + 1) * stride);
|
|
579
|
-
const previous = row > 0 ? data.subarray((row - 1) * stride, row * stride) : new Uint8Array(stride);
|
|
580
|
-
for (let x = 0; x < stride; x += 1) {
|
|
581
|
-
const left = x >= channels ? out[x - channels] : 0;
|
|
582
|
-
const up = previous[x];
|
|
583
|
-
const upLeft = x >= channels ? previous[x - channels] : 0;
|
|
584
|
-
const value = line[x];
|
|
585
|
-
switch (filter) {
|
|
586
|
-
case 0:
|
|
587
|
-
out[x] = value;
|
|
588
|
-
break;
|
|
589
|
-
case 1:
|
|
590
|
-
out[x] = value + left & 255;
|
|
591
|
-
break;
|
|
592
|
-
case 2:
|
|
593
|
-
out[x] = value + up & 255;
|
|
594
|
-
break;
|
|
595
|
-
case 3:
|
|
596
|
-
out[x] = value + (left + up >> 1) & 255;
|
|
597
|
-
break;
|
|
598
|
-
case 4: {
|
|
599
|
-
const estimate = left + up - upLeft;
|
|
600
|
-
const a = Math.abs(estimate - left);
|
|
601
|
-
const b = Math.abs(estimate - up);
|
|
602
|
-
const c = Math.abs(estimate - upLeft);
|
|
603
|
-
out[x] = value + (a <= b && a <= c ? left : b <= c ? up : upLeft) & 255;
|
|
604
|
-
break;
|
|
605
|
-
}
|
|
606
|
-
default:
|
|
607
|
-
return null;
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
return { width, height, channels, data };
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
// src/cli/headlessBuiltins.ts
|
|
615
|
-
var headlessBuiltinRegistrations = Object.freeze([
|
|
616
|
-
...headlessNodeRegistrations,
|
|
617
|
-
...assertNodeRegistrations
|
|
618
|
-
]);
|
|
619
|
-
var asserts = new Map(assertNodeRegistrations.map((registration) => [registration.moduleId, registration]));
|
|
620
|
-
function headlessBuiltin(moduleId) {
|
|
621
|
-
return headlessNodeRegistration(moduleId) ?? asserts.get(moduleId);
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
export {
|
|
625
|
-
builtinNodeRegistrations,
|
|
626
|
-
builtinNodeRegistration,
|
|
627
|
-
composeContactSheet,
|
|
628
|
-
headlessBuiltinRegistrations,
|
|
629
|
-
headlessBuiltin
|
|
630
|
-
};
|
|
631
|
-
//# sourceMappingURL=chunk-36P5K3SD.js.map
|