@field/cascade 0.4.0 → 0.5.1
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 +18 -0
- package/ARCHITECTURE.md +53 -7
- package/CHANGELOG.md +47 -0
- package/CONTRIBUTING.md +33 -0
- package/DESIGN.md +9 -6
- package/README.md +80 -4
- package/dist/assets/{CodeEditor-BNOJIDzL.js → CodeEditor-dOrU3aQg.js} +7 -7
- package/dist/assets/{CodePanel-2wp2G0Fj.js → CodePanel-Bqy85qen.js} +2 -2
- package/dist/assets/{CustomNodeDialog-DNqaVBqA.js → CustomNodeDialog-DkZlOgjs.js} +1 -1
- package/dist/assets/{ProjectSettings-DcdYF2E1.js → ProjectSettings-D192mr6g.js} +2 -2
- package/dist/assets/{SettingsDialog-D2xVvyiR.js → SettingsDialog-BTeeIE3T.js} +1 -1
- package/dist/assets/{VersionHistoryDialog-DW288ykF.js → VersionHistoryDialog-TZQKkn3Y.js} +1 -1
- package/dist/assets/{core-B1y38i95.js → core-DwbcGL0o.js} +2 -2
- package/dist/assets/{cssMode-BLucnaln.js → cssMode-Dcjn356x.js} +1 -1
- package/dist/assets/definitions-C_SY6Bhg.js +1 -0
- package/dist/assets/{editor.api-B3Et3Pph.js → editor.api-D7Q83606.js} +1 -1
- package/dist/assets/{freemarker2-DVlPoano.js → freemarker2-DCCiHlV6.js} +1 -1
- package/dist/assets/geo-CT-wtvaE.js +1 -0
- package/dist/assets/{handlebars-B5FZBAMR.js → handlebars-BCxC8xu1.js} +1 -1
- package/dist/assets/{html-FodD8KbR.js → html-COwepzSd.js} +1 -1
- package/dist/assets/{htmlMode-CsG57VCD.js → htmlMode-Dpg7H0rx.js} +1 -1
- package/dist/assets/{image-B3F-nq25.js → image-CMfMMxlC.js} +3 -3
- package/dist/assets/index-De1cIZ9N.js +212 -0
- package/dist/assets/{index-Y2ock1cw.css → index-ilgbOu6G.css} +1 -1
- package/dist/assets/{javascript-B3gonF_H.js → javascript-CSwWxfLr.js} +1 -1
- package/dist/assets/{jsonMode-Y3w1ahZg.js → jsonMode-BXRriTpj.js} +1 -1
- package/dist/assets/{liquid-CTpWXIYO.js → liquid-Cmkfyogc.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-CODBdKEZ.js → lspLanguageFeatures-xH9JbZGO.js} +1 -1
- package/dist/assets/{mdx-CDAQJZIz.js → mdx-BzrNjNvK.js} +1 -1
- package/dist/assets/nodeTypeUtils-BDJsc2Ks.js +1 -0
- package/dist/assets/pop-BdKEHslJ.js +1 -0
- package/dist/assets/{python-LOIlxJU-.js → python-D4E9jbx7.js} +1 -1
- package/dist/assets/{razor-CllPQSHo.js → razor-B3x9cIEM.js} +1 -1
- package/dist/assets/{tsMode-CO28ut8t.js → tsMode-dhQYPNMZ.js} +1 -1
- package/dist/assets/{typescript-ruU9wKQ_.js → typescript-CITkDxAE.js} +1 -1
- package/dist/assets/{workers-Bc1Ywp4-.js → workers-BQvF9bbO.js} +1 -1
- package/dist/assets/{xml-DoXP2Dh1.js → xml-DvHlU3A8.js} +1 -1
- package/dist/assets/{yaml-D9YPyGiJ.js → yaml-uznsLgs8.js} +1 -1
- package/dist/cli/index.js +16227 -12672
- package/dist/cli/runtime/io.ts +31 -25
- package/dist/contracts/definition.d.ts +21 -2
- package/dist/contracts/index.d.ts +2 -0
- package/dist/contracts/index.js +2 -0
- package/dist/contracts/particles.d.ts +54 -0
- package/dist/contracts/particles.js +167 -0
- package/dist/contracts/scene.d.ts +129 -0
- package/dist/contracts/scene.js +73 -0
- package/dist/contracts/schema.js +1 -1
- package/dist/contracts/validate.js +4 -2
- package/dist/contracts/values.d.ts +3 -2
- package/dist/contracts/values.js +9 -0
- package/dist/index.html +3 -3
- package/dist/io.d.ts +4 -16
- package/dist/io.js +26 -8
- package/dist/player/app.js +810 -0
- package/dist/player/embed.d.ts +4 -0
- package/dist/player/embed.js +77 -0
- package/dist/player/types.d.ts +35 -0
- package/dist/runtime/builtins/core/index.d.ts +3 -2
- package/dist/runtime/builtins/core/index.js +6 -2
- package/dist/runtime/builtins/core/structural.d.ts +168 -0
- package/dist/runtime/builtins/core/structural.js +175 -0
- package/dist/runtime/builtins/core/time.d.ts +165 -0
- package/dist/runtime/builtins/core/time.js +110 -0
- package/dist/runtime/builtins/geo/definitions.d.ts +247 -0
- package/dist/runtime/builtins/geo/definitions.js +70 -0
- package/dist/runtime/builtins/geo/index.d.ts +2 -1
- package/dist/runtime/builtins/geo/index.js +3 -1
- package/dist/runtime/builtins/geo/render.d.ts +87 -0
- package/dist/runtime/builtins/geo/render.js +87 -0
- package/dist/runtime/builtins/geo/svgExport.d.ts +11 -0
- package/dist/runtime/builtins/geo/svgExport.js +10 -0
- package/dist/runtime/builtins/index.d.ts +5 -2
- package/dist/runtime/builtins/index.js +13 -3
- package/dist/runtime/builtins/pop/definitions.d.ts +2120 -0
- package/dist/runtime/builtins/pop/definitions.js +815 -0
- package/dist/runtime/builtins/pop/index.d.ts +2 -0
- package/dist/runtime/builtins/pop/index.js +2 -0
- package/dist/runtime/builtins/scene/definitions.d.ts +356 -0
- package/dist/runtime/builtins/scene/definitions.js +224 -0
- package/dist/runtime/builtins/scene/index.d.ts +2 -0
- package/dist/runtime/builtins/scene/index.js +2 -0
- package/dist/runtime/geometry/render.d.ts +109 -0
- package/dist/runtime/geometry/render.js +145 -0
- package/dist/runtime/geometry/svg.d.ts +29 -0
- package/dist/runtime/geometry/svg.js +11 -5
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/pop/cache.d.ts +27 -0
- package/dist/runtime/pop/cache.js +123 -0
- package/dist/runtime/pop/forces.d.ts +202 -0
- package/dist/runtime/pop/forces.js +519 -0
- package/dist/runtime/pop/index.d.ts +5 -0
- package/dist/runtime/pop/index.js +5 -0
- package/dist/runtime/pop/state.d.ts +136 -0
- package/dist/runtime/pop/state.js +283 -0
- package/dist/runtime/pop/trail.d.ts +62 -0
- package/dist/runtime/pop/trail.js +142 -0
- package/dist/runtime/runtime.js +221 -3
- package/dist/runtime/scene/index.d.ts +50 -0
- package/dist/runtime/scene/index.js +94 -0
- package/dist/studio/panel.d.ts +68 -1
- package/doc/HEADLESS_GPU.md +4 -4
- package/doc/NODE_REFERENCE.md +372 -1
- package/doc/PROJECT_AUTHORING.md +16 -4
- package/doc/WEB_PLAYER.md +131 -0
- package/package.json +16 -2
- package/dist/assets/geo-DhyFdBXX.js +0 -1
- package/dist/assets/index-CC6YQw2n.js +0 -212
- package/dist/assets/nodeTypeUtils-BBA1JqHx.js +0 -1
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import type { NodeExecutionContext } from "@field/cascade/contracts";
|
|
2
|
+
/**
|
|
3
|
+
* `cascade.core.Time` — the clock, as a value the graph can carry.
|
|
4
|
+
*
|
|
5
|
+
* Built 2026-09-09, from Marcus scrubbing the timeline on `particle-type` and
|
|
6
|
+
* seeing nothing move: *"when i jump to a different time on the timeline i dont
|
|
7
|
+
* actually see the pop simulation animating in the viewer."*
|
|
8
|
+
*
|
|
9
|
+
* The cause was not the viewer. `cascade.pop.Simulate` takes the frame on an
|
|
10
|
+
* **input**, its own comment says *"drive it with `$F`"*, and **that was not
|
|
11
|
+
* possible**: expressions attach to props, and an input port has no expression
|
|
12
|
+
* field. So the sketch had a constant in there and no graph in the system could
|
|
13
|
+
* read the clock through a port at all.
|
|
14
|
+
*
|
|
15
|
+
* ## Why a node rather than an expression on the input
|
|
16
|
+
*
|
|
17
|
+
* Making inputs expression-bearing is the other fix, and it is the wrong one.
|
|
18
|
+
* An input is a *wire*, and a wire that is sometimes a formula means every
|
|
19
|
+
* consumer of every input has two ways to get a value — which is the shape that
|
|
20
|
+
* made props themselves complicated (a value, an expression, a channel, and a
|
|
21
|
+
* resolution order between them). Doing it again on the input side doubles that
|
|
22
|
+
* surface for one use.
|
|
23
|
+
*
|
|
24
|
+
* The node is also the more honest picture. Time is an input to the graph in
|
|
25
|
+
* the same way a camera is, and a graph that shows where the clock enters can
|
|
26
|
+
* be read; one where any of two hundred ports might secretly be `$F` cannot.
|
|
27
|
+
*
|
|
28
|
+
* ## Why the props carry the expressions
|
|
29
|
+
*
|
|
30
|
+
* `frame` and `time` are props with declared default expressions — `$F` and
|
|
31
|
+
* `$T` — which is the one mechanism that already reads the clock and updates a
|
|
32
|
+
* node's time dependency. Nothing here calls a clock: the node is a pure
|
|
33
|
+
* function of its props, and the props are where the binding lives. That keeps
|
|
34
|
+
* `execute` deterministic and testable, which a node reading a global clock
|
|
35
|
+
* would not be.
|
|
36
|
+
*
|
|
37
|
+
* They are props rather than fixed values so you can override one: pinning
|
|
38
|
+
* `frame` to a constant is exactly what a still render wants, and it is a
|
|
39
|
+
* one-field edit rather than a rewire.
|
|
40
|
+
*/
|
|
41
|
+
export declare const timeDefinition: {
|
|
42
|
+
readonly apiVersion: 1;
|
|
43
|
+
readonly label: "Time";
|
|
44
|
+
readonly description: "The current frame and time, as values the graph can read.";
|
|
45
|
+
readonly icon: "Clock";
|
|
46
|
+
readonly runsOn: "portable";
|
|
47
|
+
readonly inputs: {};
|
|
48
|
+
readonly outputs: {
|
|
49
|
+
/**
|
|
50
|
+
* The whole frame, as an integer — Houdini's `$F`.
|
|
51
|
+
*
|
|
52
|
+
* An `int` rather than a `float`, and that is the point of having two
|
|
53
|
+
* outputs. Anything that **counts** frames needs an integer: a feedback
|
|
54
|
+
* container's step count, a sequence index, a modulo. Narrowing is never
|
|
55
|
+
* implicit in Cascade, so a float frame simply could not be wired to a step
|
|
56
|
+
* count, and the alternative — truncating silently somewhere downstream —
|
|
57
|
+
* is a simulation running 3 steps when the graph said 3.7.
|
|
58
|
+
*/
|
|
59
|
+
readonly frame: {
|
|
60
|
+
readonly kind: "data";
|
|
61
|
+
readonly type: "int";
|
|
62
|
+
readonly description: "The whole frame. Houdini's $F.";
|
|
63
|
+
};
|
|
64
|
+
/** The fractional frame — Houdini's `$FF`. For anything that moves. */
|
|
65
|
+
readonly fframe: {
|
|
66
|
+
readonly kind: "data";
|
|
67
|
+
readonly type: "float";
|
|
68
|
+
readonly description: "The fractional frame, for sub-frame motion. Houdini's $FF.";
|
|
69
|
+
};
|
|
70
|
+
readonly time: {
|
|
71
|
+
readonly kind: "data";
|
|
72
|
+
readonly type: "float";
|
|
73
|
+
readonly description: "The playhead in seconds.";
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
readonly props: {
|
|
77
|
+
readonly frame: {
|
|
78
|
+
readonly type: "int";
|
|
79
|
+
readonly default: 1;
|
|
80
|
+
readonly expression: "$F";
|
|
81
|
+
readonly label: "Frame";
|
|
82
|
+
readonly description: "Bound to $F. Replace with a number to pin a still, or with any expression.";
|
|
83
|
+
};
|
|
84
|
+
readonly fframe: {
|
|
85
|
+
readonly type: "float";
|
|
86
|
+
readonly default: 1;
|
|
87
|
+
readonly expression: "$FF";
|
|
88
|
+
readonly label: "Fractional Frame";
|
|
89
|
+
readonly description: "Bound to $FF.";
|
|
90
|
+
};
|
|
91
|
+
readonly time: {
|
|
92
|
+
readonly type: "float";
|
|
93
|
+
readonly default: 0;
|
|
94
|
+
readonly expression: "$T";
|
|
95
|
+
readonly label: "Time";
|
|
96
|
+
readonly description: "Bound to $T, in seconds.";
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
export declare function executeTime(context: NodeExecutionContext<typeof timeDefinition>): void;
|
|
101
|
+
export declare const timeRegistration: {
|
|
102
|
+
kind: "definition-v1";
|
|
103
|
+
moduleId: string;
|
|
104
|
+
definition: {
|
|
105
|
+
readonly apiVersion: 1;
|
|
106
|
+
readonly label: "Time";
|
|
107
|
+
readonly description: "The current frame and time, as values the graph can read.";
|
|
108
|
+
readonly icon: "Clock";
|
|
109
|
+
readonly runsOn: "portable";
|
|
110
|
+
readonly inputs: {};
|
|
111
|
+
readonly outputs: {
|
|
112
|
+
/**
|
|
113
|
+
* The whole frame, as an integer — Houdini's `$F`.
|
|
114
|
+
*
|
|
115
|
+
* An `int` rather than a `float`, and that is the point of having two
|
|
116
|
+
* outputs. Anything that **counts** frames needs an integer: a feedback
|
|
117
|
+
* container's step count, a sequence index, a modulo. Narrowing is never
|
|
118
|
+
* implicit in Cascade, so a float frame simply could not be wired to a step
|
|
119
|
+
* count, and the alternative — truncating silently somewhere downstream —
|
|
120
|
+
* is a simulation running 3 steps when the graph said 3.7.
|
|
121
|
+
*/
|
|
122
|
+
readonly frame: {
|
|
123
|
+
readonly kind: "data";
|
|
124
|
+
readonly type: "int";
|
|
125
|
+
readonly description: "The whole frame. Houdini's $F.";
|
|
126
|
+
};
|
|
127
|
+
/** The fractional frame — Houdini's `$FF`. For anything that moves. */
|
|
128
|
+
readonly fframe: {
|
|
129
|
+
readonly kind: "data";
|
|
130
|
+
readonly type: "float";
|
|
131
|
+
readonly description: "The fractional frame, for sub-frame motion. Houdini's $FF.";
|
|
132
|
+
};
|
|
133
|
+
readonly time: {
|
|
134
|
+
readonly kind: "data";
|
|
135
|
+
readonly type: "float";
|
|
136
|
+
readonly description: "The playhead in seconds.";
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
readonly props: {
|
|
140
|
+
readonly frame: {
|
|
141
|
+
readonly type: "int";
|
|
142
|
+
readonly default: 1;
|
|
143
|
+
readonly expression: "$F";
|
|
144
|
+
readonly label: "Frame";
|
|
145
|
+
readonly description: "Bound to $F. Replace with a number to pin a still, or with any expression.";
|
|
146
|
+
};
|
|
147
|
+
readonly fframe: {
|
|
148
|
+
readonly type: "float";
|
|
149
|
+
readonly default: 1;
|
|
150
|
+
readonly expression: "$FF";
|
|
151
|
+
readonly label: "Fractional Frame";
|
|
152
|
+
readonly description: "Bound to $FF.";
|
|
153
|
+
};
|
|
154
|
+
readonly time: {
|
|
155
|
+
readonly type: "float";
|
|
156
|
+
readonly default: 0;
|
|
157
|
+
readonly expression: "$T";
|
|
158
|
+
readonly label: "Time";
|
|
159
|
+
readonly description: "Bound to $T, in seconds.";
|
|
160
|
+
};
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
loadExecute: () => Promise<typeof executeTime>;
|
|
164
|
+
};
|
|
165
|
+
//# sourceMappingURL=time.d.ts.map
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cascade.core.Time` — the clock, as a value the graph can carry.
|
|
3
|
+
*
|
|
4
|
+
* Built 2026-09-09, from Marcus scrubbing the timeline on `particle-type` and
|
|
5
|
+
* seeing nothing move: *"when i jump to a different time on the timeline i dont
|
|
6
|
+
* actually see the pop simulation animating in the viewer."*
|
|
7
|
+
*
|
|
8
|
+
* The cause was not the viewer. `cascade.pop.Simulate` takes the frame on an
|
|
9
|
+
* **input**, its own comment says *"drive it with `$F`"*, and **that was not
|
|
10
|
+
* possible**: expressions attach to props, and an input port has no expression
|
|
11
|
+
* field. So the sketch had a constant in there and no graph in the system could
|
|
12
|
+
* read the clock through a port at all.
|
|
13
|
+
*
|
|
14
|
+
* ## Why a node rather than an expression on the input
|
|
15
|
+
*
|
|
16
|
+
* Making inputs expression-bearing is the other fix, and it is the wrong one.
|
|
17
|
+
* An input is a *wire*, and a wire that is sometimes a formula means every
|
|
18
|
+
* consumer of every input has two ways to get a value — which is the shape that
|
|
19
|
+
* made props themselves complicated (a value, an expression, a channel, and a
|
|
20
|
+
* resolution order between them). Doing it again on the input side doubles that
|
|
21
|
+
* surface for one use.
|
|
22
|
+
*
|
|
23
|
+
* The node is also the more honest picture. Time is an input to the graph in
|
|
24
|
+
* the same way a camera is, and a graph that shows where the clock enters can
|
|
25
|
+
* be read; one where any of two hundred ports might secretly be `$F` cannot.
|
|
26
|
+
*
|
|
27
|
+
* ## Why the props carry the expressions
|
|
28
|
+
*
|
|
29
|
+
* `frame` and `time` are props with declared default expressions — `$F` and
|
|
30
|
+
* `$T` — which is the one mechanism that already reads the clock and updates a
|
|
31
|
+
* node's time dependency. Nothing here calls a clock: the node is a pure
|
|
32
|
+
* function of its props, and the props are where the binding lives. That keeps
|
|
33
|
+
* `execute` deterministic and testable, which a node reading a global clock
|
|
34
|
+
* would not be.
|
|
35
|
+
*
|
|
36
|
+
* They are props rather than fixed values so you can override one: pinning
|
|
37
|
+
* `frame` to a constant is exactly what a still render wants, and it is a
|
|
38
|
+
* one-field edit rather than a rewire.
|
|
39
|
+
*/
|
|
40
|
+
export const timeDefinition = {
|
|
41
|
+
apiVersion: 1,
|
|
42
|
+
label: "Time",
|
|
43
|
+
description: "The current frame and time, as values the graph can read.",
|
|
44
|
+
icon: "Clock",
|
|
45
|
+
runsOn: "portable",
|
|
46
|
+
inputs: {},
|
|
47
|
+
outputs: {
|
|
48
|
+
/**
|
|
49
|
+
* The whole frame, as an integer — Houdini's `$F`.
|
|
50
|
+
*
|
|
51
|
+
* An `int` rather than a `float`, and that is the point of having two
|
|
52
|
+
* outputs. Anything that **counts** frames needs an integer: a feedback
|
|
53
|
+
* container's step count, a sequence index, a modulo. Narrowing is never
|
|
54
|
+
* implicit in Cascade, so a float frame simply could not be wired to a step
|
|
55
|
+
* count, and the alternative — truncating silently somewhere downstream —
|
|
56
|
+
* is a simulation running 3 steps when the graph said 3.7.
|
|
57
|
+
*/
|
|
58
|
+
frame: {
|
|
59
|
+
kind: "data",
|
|
60
|
+
type: "int",
|
|
61
|
+
description: "The whole frame. Houdini's $F.",
|
|
62
|
+
},
|
|
63
|
+
/** The fractional frame — Houdini's `$FF`. For anything that moves. */
|
|
64
|
+
fframe: {
|
|
65
|
+
kind: "data",
|
|
66
|
+
type: "float",
|
|
67
|
+
description: "The fractional frame, for sub-frame motion. Houdini's $FF.",
|
|
68
|
+
},
|
|
69
|
+
time: {
|
|
70
|
+
kind: "data",
|
|
71
|
+
type: "float",
|
|
72
|
+
description: "The playhead in seconds.",
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
props: {
|
|
76
|
+
frame: {
|
|
77
|
+
type: "int",
|
|
78
|
+
default: 1,
|
|
79
|
+
expression: "$F",
|
|
80
|
+
label: "Frame",
|
|
81
|
+
description: "Bound to $F. Replace with a number to pin a still, or with any expression.",
|
|
82
|
+
},
|
|
83
|
+
fframe: {
|
|
84
|
+
type: "float",
|
|
85
|
+
default: 1,
|
|
86
|
+
expression: "$FF",
|
|
87
|
+
label: "Fractional Frame",
|
|
88
|
+
description: "Bound to $FF.",
|
|
89
|
+
},
|
|
90
|
+
time: {
|
|
91
|
+
type: "float",
|
|
92
|
+
default: 0,
|
|
93
|
+
expression: "$T",
|
|
94
|
+
label: "Time",
|
|
95
|
+
description: "Bound to $T, in seconds.",
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
};
|
|
99
|
+
export function executeTime(context) {
|
|
100
|
+
context.outputs.frame.set(context.props.frame);
|
|
101
|
+
context.outputs.fframe.set(context.props.fframe);
|
|
102
|
+
context.outputs.time.set(context.props.time);
|
|
103
|
+
}
|
|
104
|
+
export const timeRegistration = {
|
|
105
|
+
kind: "definition-v1",
|
|
106
|
+
moduleId: "cascade.core.Time",
|
|
107
|
+
definition: timeDefinition,
|
|
108
|
+
loadExecute: async () => executeTime,
|
|
109
|
+
};
|
|
110
|
+
//# sourceMappingURL=time.js.map
|
|
@@ -210,6 +210,26 @@ export declare const svgExportDefinition: {
|
|
|
210
210
|
readonly default: 0;
|
|
211
211
|
readonly label: "Margin";
|
|
212
212
|
};
|
|
213
|
+
/**
|
|
214
|
+
* An explicit world rectangle, `[minX, minY, maxX, maxY]`, instead of the
|
|
215
|
+
* geometry's own bounds. All zero derives them as before.
|
|
216
|
+
*
|
|
217
|
+
* A frame sequence needs it: derived bounds give every frame its own
|
|
218
|
+
* viewBox, so a growing drawing appears to zoom out over the animation.
|
|
219
|
+
*/
|
|
220
|
+
readonly bounds: {
|
|
221
|
+
readonly type: "vec4";
|
|
222
|
+
readonly default: readonly [0, 0, 0, 0];
|
|
223
|
+
readonly label: "Bounds";
|
|
224
|
+
};
|
|
225
|
+
/** A ground behind the drawing. Fully transparent leaves the document
|
|
226
|
+
* transparent, which is what plotter work wants. */
|
|
227
|
+
readonly background: {
|
|
228
|
+
readonly type: "color";
|
|
229
|
+
readonly default: readonly [0, 0, 0, 0];
|
|
230
|
+
readonly label: "Background";
|
|
231
|
+
readonly description: "A ground behind the drawing. Transparent by default, because a plotter wants paper.";
|
|
232
|
+
};
|
|
213
233
|
readonly stroke: {
|
|
214
234
|
readonly type: "color";
|
|
215
235
|
readonly default: readonly [0, 0, 0, 1];
|
|
@@ -263,6 +283,110 @@ export declare const svgExportDefinition: {
|
|
|
263
283
|
};
|
|
264
284
|
};
|
|
265
285
|
};
|
|
286
|
+
export declare const renderDefinition: {
|
|
287
|
+
readonly apiVersion: 1;
|
|
288
|
+
readonly label: "Render";
|
|
289
|
+
readonly description: "Draw a scene through a camera, as a raster.";
|
|
290
|
+
readonly icon: "Camera";
|
|
291
|
+
readonly runsOn: "portable";
|
|
292
|
+
readonly capabilities: readonly ["assets"];
|
|
293
|
+
readonly inputs: {
|
|
294
|
+
/**
|
|
295
|
+
* A scene, or a geometry — `geometry` widens to `scene`, so wiring a
|
|
296
|
+
* geometry straight in still works and arrives through `asScene`.
|
|
297
|
+
*
|
|
298
|
+
* Taking a scene rather than a geometry is what makes the viewport and this
|
|
299
|
+
* node incapable of disagreeing about framing: both read the same object,
|
|
300
|
+
* so the picture on screen and the picture in the PNG come from one camera
|
|
301
|
+
* and one list of geometry rather than from two paths that have to be kept
|
|
302
|
+
* in step by hand.
|
|
303
|
+
*/
|
|
304
|
+
readonly scene: {
|
|
305
|
+
readonly kind: "data";
|
|
306
|
+
readonly type: "scene";
|
|
307
|
+
};
|
|
308
|
+
/**
|
|
309
|
+
* The camera, and required in the sense that matters: it may come from the
|
|
310
|
+
* scene instead, but it may not be invented. A render with an implicit
|
|
311
|
+
* camera is a render nobody can reproduce, and `cascade.core.Camera` is one
|
|
312
|
+
* node away.
|
|
313
|
+
*
|
|
314
|
+
* Wired here it **overrides** the scene's own camera, which is what lets one
|
|
315
|
+
* scene be rendered from several viewpoints without rebuilding it — and is
|
|
316
|
+
* also why the viewport's navigated camera never reaches this node. A view
|
|
317
|
+
* you dragged is not a document.
|
|
318
|
+
*/
|
|
319
|
+
readonly camera: {
|
|
320
|
+
readonly kind: "data";
|
|
321
|
+
readonly type: "camera";
|
|
322
|
+
};
|
|
323
|
+
};
|
|
324
|
+
readonly outputs: {
|
|
325
|
+
readonly image: {
|
|
326
|
+
readonly kind: "data";
|
|
327
|
+
readonly type: "image";
|
|
328
|
+
};
|
|
329
|
+
readonly asset: {
|
|
330
|
+
readonly kind: "data";
|
|
331
|
+
readonly type: "asset";
|
|
332
|
+
};
|
|
333
|
+
};
|
|
334
|
+
readonly props: {
|
|
335
|
+
/** Pixels. Separate from the camera's own `resolution`, which describes
|
|
336
|
+
* the frame the projection assumes — so a preview renders small and frames
|
|
337
|
+
* identically to the full-size render. */
|
|
338
|
+
readonly size: {
|
|
339
|
+
readonly type: "vec2i";
|
|
340
|
+
readonly default: readonly [1280, 720];
|
|
341
|
+
readonly min: 16;
|
|
342
|
+
readonly max: 8192;
|
|
343
|
+
};
|
|
344
|
+
readonly filename: {
|
|
345
|
+
readonly type: "string";
|
|
346
|
+
readonly default: "render.png";
|
|
347
|
+
readonly label: "Filename";
|
|
348
|
+
};
|
|
349
|
+
readonly background: {
|
|
350
|
+
readonly type: "color";
|
|
351
|
+
readonly default: readonly [0, 0, 0, 0];
|
|
352
|
+
readonly label: "Background";
|
|
353
|
+
};
|
|
354
|
+
/** Fallback for a primitive with no `Cd`, exactly as SvgExport's is. */
|
|
355
|
+
readonly stroke: {
|
|
356
|
+
readonly type: "color";
|
|
357
|
+
readonly default: readonly [0, 0, 0, 1];
|
|
358
|
+
readonly label: "Stroke";
|
|
359
|
+
};
|
|
360
|
+
readonly strokeWidth: {
|
|
361
|
+
readonly type: "float";
|
|
362
|
+
readonly default: 1;
|
|
363
|
+
readonly min: 0;
|
|
364
|
+
readonly max: 200;
|
|
365
|
+
readonly step: 0.05;
|
|
366
|
+
};
|
|
367
|
+
readonly opacity: {
|
|
368
|
+
readonly type: "float";
|
|
369
|
+
readonly default: 1;
|
|
370
|
+
readonly min: 0;
|
|
371
|
+
readonly max: 1;
|
|
372
|
+
readonly step: 0.01;
|
|
373
|
+
};
|
|
374
|
+
/** Points no primitive claimed. Off by default: a trail system has
|
|
375
|
+
* thousands of vertices and a dot on every one buries the strokes. */
|
|
376
|
+
readonly drawPoints: {
|
|
377
|
+
readonly type: "bool";
|
|
378
|
+
readonly default: false;
|
|
379
|
+
readonly label: "Draw Loose Points";
|
|
380
|
+
};
|
|
381
|
+
readonly pointRadius: {
|
|
382
|
+
readonly type: "float";
|
|
383
|
+
readonly default: 1.5;
|
|
384
|
+
readonly min: 0;
|
|
385
|
+
readonly max: 50;
|
|
386
|
+
readonly step: 0.1;
|
|
387
|
+
};
|
|
388
|
+
};
|
|
389
|
+
};
|
|
266
390
|
export declare const geoNodeDefinitions: readonly [readonly ["cascade.geo.Rectangle", {
|
|
267
391
|
readonly apiVersion: 1;
|
|
268
392
|
readonly label: "Rectangle";
|
|
@@ -470,6 +594,26 @@ export declare const geoNodeDefinitions: readonly [readonly ["cascade.geo.Rectan
|
|
|
470
594
|
readonly default: 0;
|
|
471
595
|
readonly label: "Margin";
|
|
472
596
|
};
|
|
597
|
+
/**
|
|
598
|
+
* An explicit world rectangle, `[minX, minY, maxX, maxY]`, instead of the
|
|
599
|
+
* geometry's own bounds. All zero derives them as before.
|
|
600
|
+
*
|
|
601
|
+
* A frame sequence needs it: derived bounds give every frame its own
|
|
602
|
+
* viewBox, so a growing drawing appears to zoom out over the animation.
|
|
603
|
+
*/
|
|
604
|
+
readonly bounds: {
|
|
605
|
+
readonly type: "vec4";
|
|
606
|
+
readonly default: readonly [0, 0, 0, 0];
|
|
607
|
+
readonly label: "Bounds";
|
|
608
|
+
};
|
|
609
|
+
/** A ground behind the drawing. Fully transparent leaves the document
|
|
610
|
+
* transparent, which is what plotter work wants. */
|
|
611
|
+
readonly background: {
|
|
612
|
+
readonly type: "color";
|
|
613
|
+
readonly default: readonly [0, 0, 0, 0];
|
|
614
|
+
readonly label: "Background";
|
|
615
|
+
readonly description: "A ground behind the drawing. Transparent by default, because a plotter wants paper.";
|
|
616
|
+
};
|
|
473
617
|
readonly stroke: {
|
|
474
618
|
readonly type: "color";
|
|
475
619
|
readonly default: readonly [0, 0, 0, 1];
|
|
@@ -522,5 +666,108 @@ export declare const geoNodeDefinitions: readonly [readonly ["cascade.geo.Rectan
|
|
|
522
666
|
readonly description: "Decimal places on emitted coordinates.";
|
|
523
667
|
};
|
|
524
668
|
};
|
|
669
|
+
}], readonly ["cascade.geo.Render", {
|
|
670
|
+
readonly apiVersion: 1;
|
|
671
|
+
readonly label: "Render";
|
|
672
|
+
readonly description: "Draw a scene through a camera, as a raster.";
|
|
673
|
+
readonly icon: "Camera";
|
|
674
|
+
readonly runsOn: "portable";
|
|
675
|
+
readonly capabilities: readonly ["assets"];
|
|
676
|
+
readonly inputs: {
|
|
677
|
+
/**
|
|
678
|
+
* A scene, or a geometry — `geometry` widens to `scene`, so wiring a
|
|
679
|
+
* geometry straight in still works and arrives through `asScene`.
|
|
680
|
+
*
|
|
681
|
+
* Taking a scene rather than a geometry is what makes the viewport and this
|
|
682
|
+
* node incapable of disagreeing about framing: both read the same object,
|
|
683
|
+
* so the picture on screen and the picture in the PNG come from one camera
|
|
684
|
+
* and one list of geometry rather than from two paths that have to be kept
|
|
685
|
+
* in step by hand.
|
|
686
|
+
*/
|
|
687
|
+
readonly scene: {
|
|
688
|
+
readonly kind: "data";
|
|
689
|
+
readonly type: "scene";
|
|
690
|
+
};
|
|
691
|
+
/**
|
|
692
|
+
* The camera, and required in the sense that matters: it may come from the
|
|
693
|
+
* scene instead, but it may not be invented. A render with an implicit
|
|
694
|
+
* camera is a render nobody can reproduce, and `cascade.core.Camera` is one
|
|
695
|
+
* node away.
|
|
696
|
+
*
|
|
697
|
+
* Wired here it **overrides** the scene's own camera, which is what lets one
|
|
698
|
+
* scene be rendered from several viewpoints without rebuilding it — and is
|
|
699
|
+
* also why the viewport's navigated camera never reaches this node. A view
|
|
700
|
+
* you dragged is not a document.
|
|
701
|
+
*/
|
|
702
|
+
readonly camera: {
|
|
703
|
+
readonly kind: "data";
|
|
704
|
+
readonly type: "camera";
|
|
705
|
+
};
|
|
706
|
+
};
|
|
707
|
+
readonly outputs: {
|
|
708
|
+
readonly image: {
|
|
709
|
+
readonly kind: "data";
|
|
710
|
+
readonly type: "image";
|
|
711
|
+
};
|
|
712
|
+
readonly asset: {
|
|
713
|
+
readonly kind: "data";
|
|
714
|
+
readonly type: "asset";
|
|
715
|
+
};
|
|
716
|
+
};
|
|
717
|
+
readonly props: {
|
|
718
|
+
/** Pixels. Separate from the camera's own `resolution`, which describes
|
|
719
|
+
* the frame the projection assumes — so a preview renders small and frames
|
|
720
|
+
* identically to the full-size render. */
|
|
721
|
+
readonly size: {
|
|
722
|
+
readonly type: "vec2i";
|
|
723
|
+
readonly default: readonly [1280, 720];
|
|
724
|
+
readonly min: 16;
|
|
725
|
+
readonly max: 8192;
|
|
726
|
+
};
|
|
727
|
+
readonly filename: {
|
|
728
|
+
readonly type: "string";
|
|
729
|
+
readonly default: "render.png";
|
|
730
|
+
readonly label: "Filename";
|
|
731
|
+
};
|
|
732
|
+
readonly background: {
|
|
733
|
+
readonly type: "color";
|
|
734
|
+
readonly default: readonly [0, 0, 0, 0];
|
|
735
|
+
readonly label: "Background";
|
|
736
|
+
};
|
|
737
|
+
/** Fallback for a primitive with no `Cd`, exactly as SvgExport's is. */
|
|
738
|
+
readonly stroke: {
|
|
739
|
+
readonly type: "color";
|
|
740
|
+
readonly default: readonly [0, 0, 0, 1];
|
|
741
|
+
readonly label: "Stroke";
|
|
742
|
+
};
|
|
743
|
+
readonly strokeWidth: {
|
|
744
|
+
readonly type: "float";
|
|
745
|
+
readonly default: 1;
|
|
746
|
+
readonly min: 0;
|
|
747
|
+
readonly max: 200;
|
|
748
|
+
readonly step: 0.05;
|
|
749
|
+
};
|
|
750
|
+
readonly opacity: {
|
|
751
|
+
readonly type: "float";
|
|
752
|
+
readonly default: 1;
|
|
753
|
+
readonly min: 0;
|
|
754
|
+
readonly max: 1;
|
|
755
|
+
readonly step: 0.01;
|
|
756
|
+
};
|
|
757
|
+
/** Points no primitive claimed. Off by default: a trail system has
|
|
758
|
+
* thousands of vertices and a dot on every one buries the strokes. */
|
|
759
|
+
readonly drawPoints: {
|
|
760
|
+
readonly type: "bool";
|
|
761
|
+
readonly default: false;
|
|
762
|
+
readonly label: "Draw Loose Points";
|
|
763
|
+
};
|
|
764
|
+
readonly pointRadius: {
|
|
765
|
+
readonly type: "float";
|
|
766
|
+
readonly default: 1.5;
|
|
767
|
+
readonly min: 0;
|
|
768
|
+
readonly max: 50;
|
|
769
|
+
readonly step: 0.1;
|
|
770
|
+
};
|
|
771
|
+
};
|
|
525
772
|
}]];
|
|
526
773
|
//# sourceMappingURL=definitions.d.ts.map
|
|
@@ -118,6 +118,22 @@ export const svgExportDefinition = {
|
|
|
118
118
|
},
|
|
119
119
|
height: { type: "float", default: 0, min: 0, label: "Height" },
|
|
120
120
|
margin: { type: "float", default: 0, label: "Margin" },
|
|
121
|
+
/**
|
|
122
|
+
* An explicit world rectangle, `[minX, minY, maxX, maxY]`, instead of the
|
|
123
|
+
* geometry's own bounds. All zero derives them as before.
|
|
124
|
+
*
|
|
125
|
+
* A frame sequence needs it: derived bounds give every frame its own
|
|
126
|
+
* viewBox, so a growing drawing appears to zoom out over the animation.
|
|
127
|
+
*/
|
|
128
|
+
bounds: { type: "vec4", default: [0, 0, 0, 0], label: "Bounds" },
|
|
129
|
+
/** A ground behind the drawing. Fully transparent leaves the document
|
|
130
|
+
* transparent, which is what plotter work wants. */
|
|
131
|
+
background: {
|
|
132
|
+
type: "color",
|
|
133
|
+
default: [0, 0, 0, 0],
|
|
134
|
+
label: "Background",
|
|
135
|
+
description: "A ground behind the drawing. Transparent by default, because a plotter wants paper.",
|
|
136
|
+
},
|
|
121
137
|
stroke: {
|
|
122
138
|
type: "color",
|
|
123
139
|
default: [0, 0, 0, 1],
|
|
@@ -171,6 +187,59 @@ export const svgExportDefinition = {
|
|
|
171
187
|
},
|
|
172
188
|
},
|
|
173
189
|
};
|
|
190
|
+
export const renderDefinition = {
|
|
191
|
+
apiVersion: 1,
|
|
192
|
+
label: "Render",
|
|
193
|
+
description: "Draw a scene through a camera, as a raster.",
|
|
194
|
+
icon: "Camera",
|
|
195
|
+
runsOn: "portable",
|
|
196
|
+
capabilities: ["assets"],
|
|
197
|
+
inputs: {
|
|
198
|
+
/**
|
|
199
|
+
* A scene, or a geometry — `geometry` widens to `scene`, so wiring a
|
|
200
|
+
* geometry straight in still works and arrives through `asScene`.
|
|
201
|
+
*
|
|
202
|
+
* Taking a scene rather than a geometry is what makes the viewport and this
|
|
203
|
+
* node incapable of disagreeing about framing: both read the same object,
|
|
204
|
+
* so the picture on screen and the picture in the PNG come from one camera
|
|
205
|
+
* and one list of geometry rather than from two paths that have to be kept
|
|
206
|
+
* in step by hand.
|
|
207
|
+
*/
|
|
208
|
+
scene: { kind: "data", type: "scene" },
|
|
209
|
+
/**
|
|
210
|
+
* The camera, and required in the sense that matters: it may come from the
|
|
211
|
+
* scene instead, but it may not be invented. A render with an implicit
|
|
212
|
+
* camera is a render nobody can reproduce, and `cascade.core.Camera` is one
|
|
213
|
+
* node away.
|
|
214
|
+
*
|
|
215
|
+
* Wired here it **overrides** the scene's own camera, which is what lets one
|
|
216
|
+
* scene be rendered from several viewpoints without rebuilding it — and is
|
|
217
|
+
* also why the viewport's navigated camera never reaches this node. A view
|
|
218
|
+
* you dragged is not a document.
|
|
219
|
+
*/
|
|
220
|
+
camera: { kind: "data", type: "camera" },
|
|
221
|
+
},
|
|
222
|
+
outputs: {
|
|
223
|
+
image: { kind: "data", type: "image" },
|
|
224
|
+
asset: { kind: "data", type: "asset" },
|
|
225
|
+
},
|
|
226
|
+
props: {
|
|
227
|
+
/** Pixels. Separate from the camera's own `resolution`, which describes
|
|
228
|
+
* the frame the projection assumes — so a preview renders small and frames
|
|
229
|
+
* identically to the full-size render. */
|
|
230
|
+
size: { type: "vec2i", default: [1280, 720], min: 16, max: 8192 },
|
|
231
|
+
filename: { type: "string", default: "render.png", label: "Filename" },
|
|
232
|
+
background: { type: "color", default: [0, 0, 0, 0], label: "Background" },
|
|
233
|
+
/** Fallback for a primitive with no `Cd`, exactly as SvgExport's is. */
|
|
234
|
+
stroke: { type: "color", default: [0, 0, 0, 1], label: "Stroke" },
|
|
235
|
+
strokeWidth: { type: "float", default: 1, min: 0, max: 200, step: 0.05 },
|
|
236
|
+
opacity: { type: "float", default: 1, min: 0, max: 1, step: 0.01 },
|
|
237
|
+
/** Points no primitive claimed. Off by default: a trail system has
|
|
238
|
+
* thousands of vertices and a dot on every one buries the strokes. */
|
|
239
|
+
drawPoints: { type: "bool", default: false, label: "Draw Loose Points" },
|
|
240
|
+
pointRadius: { type: "float", default: 1.5, min: 0, max: 50, step: 0.1 },
|
|
241
|
+
},
|
|
242
|
+
};
|
|
174
243
|
export const geoNodeDefinitions = Object.freeze([
|
|
175
244
|
["cascade.geo.Rectangle", rectangleDefinition],
|
|
176
245
|
["cascade.geo.Circle", circleDefinition],
|
|
@@ -178,5 +247,6 @@ export const geoNodeDefinitions = Object.freeze([
|
|
|
178
247
|
["cascade.geo.Merge", mergeDefinition],
|
|
179
248
|
["cascade.geo.CopyToPoints", copyToPointsDefinition],
|
|
180
249
|
["cascade.geo.SvgExport", svgExportDefinition],
|
|
250
|
+
["cascade.geo.Render", renderDefinition],
|
|
181
251
|
]);
|
|
182
252
|
//# sourceMappingURL=definitions.js.map
|
|
@@ -2,6 +2,7 @@ import type { DefinitionNodeRegistration } from "../../types.js";
|
|
|
2
2
|
import { copyToPointsRegistration } from "./copyToPoints.js";
|
|
3
3
|
import { circleRegistration, rectangleRegistration } from "./generators.js";
|
|
4
4
|
import { mergeRegistration } from "./merge.js";
|
|
5
|
+
import { renderRegistration } from "./render.js";
|
|
5
6
|
import { svgExportRegistration } from "./svgExport.js";
|
|
6
7
|
import { transformRegistration } from "./transform.js";
|
|
7
8
|
/**
|
|
@@ -16,7 +17,7 @@ import { transformRegistration } from "./transform.js";
|
|
|
16
17
|
*
|
|
17
18
|
* The namespace lives in `namespace.ts`, once.
|
|
18
19
|
*/
|
|
19
|
-
export { circleRegistration, copyToPointsRegistration, mergeRegistration, rectangleRegistration, svgExportRegistration, transformRegistration, };
|
|
20
|
+
export { circleRegistration, copyToPointsRegistration, mergeRegistration, rectangleRegistration, renderRegistration, svgExportRegistration, transformRegistration, };
|
|
20
21
|
export { GEO_NAMESPACE, geoModuleId } from "./namespace.js";
|
|
21
22
|
export declare const geoNodeRegistrations: readonly DefinitionNodeRegistration[];
|
|
22
23
|
export declare function geoNodeRegistration(moduleId: string): DefinitionNodeRegistration | undefined;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { copyToPointsRegistration } from "./copyToPoints.js";
|
|
2
2
|
import { circleRegistration, rectangleRegistration } from "./generators.js";
|
|
3
3
|
import { mergeRegistration } from "./merge.js";
|
|
4
|
+
import { renderRegistration } from "./render.js";
|
|
4
5
|
import { svgExportRegistration } from "./svgExport.js";
|
|
5
6
|
import { transformRegistration } from "./transform.js";
|
|
6
7
|
/**
|
|
@@ -15,7 +16,7 @@ import { transformRegistration } from "./transform.js";
|
|
|
15
16
|
*
|
|
16
17
|
* The namespace lives in `namespace.ts`, once.
|
|
17
18
|
*/
|
|
18
|
-
export { circleRegistration, copyToPointsRegistration, mergeRegistration, rectangleRegistration, svgExportRegistration, transformRegistration, };
|
|
19
|
+
export { circleRegistration, copyToPointsRegistration, mergeRegistration, rectangleRegistration, renderRegistration, svgExportRegistration, transformRegistration, };
|
|
19
20
|
export { GEO_NAMESPACE, geoModuleId } from "./namespace.js";
|
|
20
21
|
export const geoNodeRegistrations = Object.freeze([
|
|
21
22
|
rectangleRegistration,
|
|
@@ -23,6 +24,7 @@ export const geoNodeRegistrations = Object.freeze([
|
|
|
23
24
|
transformRegistration,
|
|
24
25
|
mergeRegistration,
|
|
25
26
|
copyToPointsRegistration,
|
|
27
|
+
renderRegistration,
|
|
26
28
|
svgExportRegistration,
|
|
27
29
|
]);
|
|
28
30
|
const registrationsById = new Map(geoNodeRegistrations.map((registration) => [
|