@field/cascade 0.4.0 → 0.5.2
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 +68 -0
- package/CONTRIBUTING.md +33 -0
- package/DESIGN.md +9 -6
- package/README.md +80 -4
- package/dist/assets/{CodeEditor-BNOJIDzL.js → CodeEditor-BHej8kM9.js} +7 -7
- package/dist/assets/{CodePanel-2wp2G0Fj.js → CodePanel-CT3eirK8.js} +2 -2
- package/dist/assets/{CustomNodeDialog-DNqaVBqA.js → CustomNodeDialog-BG0m7_Rv.js} +1 -1
- package/dist/assets/{ProjectSettings-DcdYF2E1.js → ProjectSettings-BxoLWJG6.js} +2 -2
- package/dist/assets/{SettingsDialog-D2xVvyiR.js → SettingsDialog-r9PzZ22z.js} +1 -1
- package/dist/assets/{VersionHistoryDialog-DW288ykF.js → VersionHistoryDialog-B6zUV6Dy.js} +1 -1
- package/dist/assets/{core-B1y38i95.js → core-wwx5881P.js} +2 -2
- package/dist/assets/{cssMode-BLucnaln.js → cssMode-DY5T2Or0.js} +1 -1
- package/dist/assets/definitions-BgCvRHyR.js +1 -0
- package/dist/assets/{editor.api-B3Et3Pph.js → editor.api-mkORHEMm.js} +1 -1
- package/dist/assets/{freemarker2-DVlPoano.js → freemarker2-CIWlk0sw.js} +1 -1
- package/dist/assets/geo-CIxgs0oE.js +1 -0
- package/dist/assets/{handlebars-B5FZBAMR.js → handlebars-t4jbj3Br.js} +1 -1
- package/dist/assets/{html-FodD8KbR.js → html-Ctx7UOlY.js} +1 -1
- package/dist/assets/{htmlMode-CsG57VCD.js → htmlMode-BKNZxVw7.js} +1 -1
- package/dist/assets/{image-B3F-nq25.js → image-BCBFz0gD.js} +3 -3
- package/dist/assets/index-CeqTfMbr.js +212 -0
- package/dist/assets/{index-Y2ock1cw.css → index-ilgbOu6G.css} +1 -1
- package/dist/assets/{javascript-B3gonF_H.js → javascript-Da_TJBzH.js} +1 -1
- package/dist/assets/{jsonMode-Y3w1ahZg.js → jsonMode-Ftt5d1nV.js} +1 -1
- package/dist/assets/{liquid-CTpWXIYO.js → liquid-D5kWYG57.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-CODBdKEZ.js → lspLanguageFeatures-B-93LC_L.js} +1 -1
- package/dist/assets/{mdx-CDAQJZIz.js → mdx-DGT3C_qs.js} +1 -1
- package/dist/assets/nodeTypeUtils-BDJsc2Ks.js +1 -0
- package/dist/assets/pop-BJGN5Ac4.js +1 -0
- package/dist/assets/{python-LOIlxJU-.js → python-Bz3Eew5S.js} +1 -1
- package/dist/assets/{razor-CllPQSHo.js → razor-CFDdKpKI.js} +1 -1
- package/dist/assets/{tsMode-CO28ut8t.js → tsMode-BaCINWBI.js} +1 -1
- package/dist/assets/{typescript-ruU9wKQ_.js → typescript-BoOWspVs.js} +1 -1
- package/dist/assets/{workers-Bc1Ywp4-.js → workers-dSWyDxsQ.js} +1 -1
- package/dist/assets/{xml-DoXP2Dh1.js → xml-eFi1_vYt.js} +1 -1
- package/dist/assets/{yaml-D9YPyGiJ.js → yaml-a7xrJHxm.js} +1 -1
- package/dist/cli/index.js +16266 -12653
- 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,87 @@
|
|
|
1
|
+
import type { NodeExecutionContext } from "@field/cascade/contracts";
|
|
2
|
+
import { renderDefinition } from "./definitions.js";
|
|
3
|
+
export declare function executeRender(context: NodeExecutionContext<typeof renderDefinition>): Promise<void>;
|
|
4
|
+
export declare const renderRegistration: {
|
|
5
|
+
kind: "definition-v1";
|
|
6
|
+
moduleId: string;
|
|
7
|
+
definition: {
|
|
8
|
+
readonly apiVersion: 1;
|
|
9
|
+
readonly label: "Render";
|
|
10
|
+
readonly description: "Draw a scene through a camera, as a raster.";
|
|
11
|
+
readonly icon: "Camera";
|
|
12
|
+
readonly runsOn: "portable";
|
|
13
|
+
readonly capabilities: readonly ["assets"];
|
|
14
|
+
readonly inputs: {
|
|
15
|
+
readonly scene: {
|
|
16
|
+
readonly kind: "data";
|
|
17
|
+
readonly type: "scene";
|
|
18
|
+
};
|
|
19
|
+
readonly camera: {
|
|
20
|
+
readonly kind: "data";
|
|
21
|
+
readonly type: "camera";
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
readonly outputs: {
|
|
25
|
+
readonly image: {
|
|
26
|
+
readonly kind: "data";
|
|
27
|
+
readonly type: "image";
|
|
28
|
+
};
|
|
29
|
+
readonly asset: {
|
|
30
|
+
readonly kind: "data";
|
|
31
|
+
readonly type: "asset";
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
readonly props: {
|
|
35
|
+
readonly size: {
|
|
36
|
+
readonly type: "vec2i";
|
|
37
|
+
readonly default: readonly [1280, 720];
|
|
38
|
+
readonly min: 16;
|
|
39
|
+
readonly max: 8192;
|
|
40
|
+
};
|
|
41
|
+
readonly filename: {
|
|
42
|
+
readonly type: "string";
|
|
43
|
+
readonly default: "render.png";
|
|
44
|
+
readonly label: "Filename";
|
|
45
|
+
};
|
|
46
|
+
readonly background: {
|
|
47
|
+
readonly type: "color";
|
|
48
|
+
readonly default: readonly [0, 0, 0, 0];
|
|
49
|
+
readonly label: "Background";
|
|
50
|
+
};
|
|
51
|
+
readonly stroke: {
|
|
52
|
+
readonly type: "color";
|
|
53
|
+
readonly default: readonly [0, 0, 0, 1];
|
|
54
|
+
readonly label: "Stroke";
|
|
55
|
+
};
|
|
56
|
+
readonly strokeWidth: {
|
|
57
|
+
readonly type: "float";
|
|
58
|
+
readonly default: 1;
|
|
59
|
+
readonly min: 0;
|
|
60
|
+
readonly max: 200;
|
|
61
|
+
readonly step: 0.05;
|
|
62
|
+
};
|
|
63
|
+
readonly opacity: {
|
|
64
|
+
readonly type: "float";
|
|
65
|
+
readonly default: 1;
|
|
66
|
+
readonly min: 0;
|
|
67
|
+
readonly max: 1;
|
|
68
|
+
readonly step: 0.01;
|
|
69
|
+
};
|
|
70
|
+
readonly drawPoints: {
|
|
71
|
+
readonly type: "bool";
|
|
72
|
+
readonly default: false;
|
|
73
|
+
readonly label: "Draw Loose Points";
|
|
74
|
+
};
|
|
75
|
+
readonly pointRadius: {
|
|
76
|
+
readonly type: "float";
|
|
77
|
+
readonly default: 1.5;
|
|
78
|
+
readonly min: 0;
|
|
79
|
+
readonly max: 50;
|
|
80
|
+
readonly step: 0.1;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
loadExecute: () => Promise<typeof executeRender>;
|
|
85
|
+
};
|
|
86
|
+
export { renderDefinition } from "./definitions.js";
|
|
87
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { asScene } from "@field/cascade/contracts";
|
|
2
|
+
import { renderScene, renderToPng, } from "../../geometry/render.js";
|
|
3
|
+
import { renderDefinition } from "./definitions.js";
|
|
4
|
+
import { geoModuleId } from "./namespace.js";
|
|
5
|
+
/**
|
|
6
|
+
* `cascade.geo.Render` — the 3D-to-2D half of `PLAN viewport.md`.
|
|
7
|
+
*
|
|
8
|
+
* Beside `SvgExport` rather than in a namespace of its own, and the naming
|
|
9
|
+
* argument is in the plan: `cascade.geo.Render` puts it next to the node it
|
|
10
|
+
* shares a style vocabulary with, while `cascade.render.Scene` would start a
|
|
11
|
+
* namespace holding one node — a promise rather than a structure.
|
|
12
|
+
*
|
|
13
|
+
* **It is a node and not a viewport button** because a render is part of the
|
|
14
|
+
* document: it has a resolution, it is what a series renders per instance, and
|
|
15
|
+
* `cascade run --frames` has to produce it without a browser. A button produces
|
|
16
|
+
* a file; a node produces a value other nodes consume, and the second is the
|
|
17
|
+
* whole point of the graph.
|
|
18
|
+
*
|
|
19
|
+
* `portable` with only `assets`, like `SvgExport`: both hosts supply
|
|
20
|
+
* `OffscreenCanvas`, so nothing here needs a GPU. The plan argues for the CPU
|
|
21
|
+
* path first on the grounds that this vault's work is lines and a node that
|
|
22
|
+
* runs in every host — including CI — is worth more than one that is faster in
|
|
23
|
+
* one.
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* The one host assumption, and it lives here rather than in the renderer.
|
|
27
|
+
*
|
|
28
|
+
* Both hosts supply `OffscreenCanvas` — the browser natively, the headless host
|
|
29
|
+
* through @napi-rs/canvas — so a `portable` node can draw. `packages/runtime`
|
|
30
|
+
* itself compiles without a DOM lib and must not reach for a global, which is
|
|
31
|
+
* why the renderer takes a factory and this is where it comes from.
|
|
32
|
+
*/
|
|
33
|
+
function hostSurface(width, height) {
|
|
34
|
+
const factory = globalThis
|
|
35
|
+
.OffscreenCanvas;
|
|
36
|
+
if (!factory) {
|
|
37
|
+
throw new Error("cascade.geo.Render needs OffscreenCanvas, which this host does not provide");
|
|
38
|
+
}
|
|
39
|
+
return new factory(width, height);
|
|
40
|
+
}
|
|
41
|
+
export async function executeRender(context) {
|
|
42
|
+
const { props } = context;
|
|
43
|
+
const scene = asScene(context.inputs.scene);
|
|
44
|
+
/**
|
|
45
|
+
* The camera input wins over the scene's own, so one scene can be rendered
|
|
46
|
+
* from several viewpoints without being rebuilt.
|
|
47
|
+
*
|
|
48
|
+
* And a render still refuses to invent one. The viewport may fall back to
|
|
49
|
+
* whatever camera you have navigated to, because a view is a way of looking;
|
|
50
|
+
* a render is a document, and a document with an implicit camera is one
|
|
51
|
+
* nobody can reproduce — including `cascade run --frames`, which has no
|
|
52
|
+
* viewport to borrow from.
|
|
53
|
+
*/
|
|
54
|
+
const camera = context.inputs.camera ?? scene.camera;
|
|
55
|
+
if (!camera) {
|
|
56
|
+
throw new Error("cascade.geo.Render has no camera — wire a cascade.core.Camera to its camera input, or into the scene");
|
|
57
|
+
}
|
|
58
|
+
const surface = renderScene(scene.geometry, {
|
|
59
|
+
camera,
|
|
60
|
+
size: [props.size[0], props.size[1]],
|
|
61
|
+
...(props.background[3] > 0 ? { background: props.background } : {}),
|
|
62
|
+
stroke: props.stroke,
|
|
63
|
+
strokeWidth: props.strokeWidth,
|
|
64
|
+
opacity: props.opacity,
|
|
65
|
+
pointRadius: props.pointRadius,
|
|
66
|
+
drawPoints: props.drawPoints,
|
|
67
|
+
surface: hostSurface,
|
|
68
|
+
});
|
|
69
|
+
const bytes = await renderToPng(surface);
|
|
70
|
+
const asset = await context.capabilities.assets.write(bytes, { mediaType: "image/png", suggestedName: props.filename }, { signal: context.signal });
|
|
71
|
+
context.outputs.asset.set(asset);
|
|
72
|
+
context.outputs.image.set({
|
|
73
|
+
path: asset.path ?? props.filename,
|
|
74
|
+
size: [surface.width, surface.height],
|
|
75
|
+
channels: "rgba",
|
|
76
|
+
depth: "u8",
|
|
77
|
+
space: "srgb",
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
export const renderRegistration = {
|
|
81
|
+
kind: "definition-v1",
|
|
82
|
+
moduleId: geoModuleId("Render"),
|
|
83
|
+
definition: renderDefinition,
|
|
84
|
+
loadExecute: async () => executeRender,
|
|
85
|
+
};
|
|
86
|
+
export { renderDefinition } from "./definitions.js";
|
|
87
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -71,6 +71,17 @@ export declare const svgExportRegistration: {
|
|
|
71
71
|
readonly default: 0;
|
|
72
72
|
readonly label: "Margin";
|
|
73
73
|
};
|
|
74
|
+
readonly bounds: {
|
|
75
|
+
readonly type: "vec4";
|
|
76
|
+
readonly default: readonly [0, 0, 0, 0];
|
|
77
|
+
readonly label: "Bounds";
|
|
78
|
+
};
|
|
79
|
+
readonly background: {
|
|
80
|
+
readonly type: "color";
|
|
81
|
+
readonly default: readonly [0, 0, 0, 0];
|
|
82
|
+
readonly label: "Background";
|
|
83
|
+
readonly description: "A ground behind the drawing. Transparent by default, because a plotter wants paper.";
|
|
84
|
+
};
|
|
74
85
|
readonly stroke: {
|
|
75
86
|
readonly type: "color";
|
|
76
87
|
readonly default: readonly [0, 0, 0, 1];
|
|
@@ -28,6 +28,16 @@ export async function executeSvgExport(context) {
|
|
|
28
28
|
width: props.width,
|
|
29
29
|
height: props.height,
|
|
30
30
|
margin: props.margin,
|
|
31
|
+
// All-zero means "derive", because a zero-area rectangle is not a frame
|
|
32
|
+
// anyone would ask for and a separate boolean for it would be a second
|
|
33
|
+
// way to say the same thing.
|
|
34
|
+
...(props.bounds.some((value) => value !== 0)
|
|
35
|
+
? { bounds: [props.bounds[0], props.bounds[1], props.bounds[2], props.bounds[3]] }
|
|
36
|
+
: {}),
|
|
37
|
+
// Only when it would show: a fully transparent ground and no ground at all
|
|
38
|
+
// are the same document, and emitting a rect for it would put a shape in
|
|
39
|
+
// the file that a plotter would try to draw.
|
|
40
|
+
...(props.background[3] > 0 ? { background: props.background } : {}),
|
|
31
41
|
stroke: props.stroke,
|
|
32
42
|
strokeWidth: props.strokeWidth,
|
|
33
43
|
opacity: props.opacity,
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import type { DefinitionNodeRegistration } from "../types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Every reserved built-in, in one list, so that a caller does not have to know
|
|
4
|
-
* how many namespaces there are. `cascade.core.*` is structural and routing
|
|
5
|
-
* `cascade.geo.*` is the geometry set.
|
|
4
|
+
* how many namespaces there are. `cascade.core.*` is structural and routing,
|
|
5
|
+
* `cascade.geo.*` is the geometry set, and `cascade.pop.*` is the particle
|
|
6
|
+
* set — which speaks the same `geometry` type as `geo`, so any of its outputs
|
|
7
|
+
* fits any geometry node's input. `cascade.scene.*` is the assembly: geometry
|
|
8
|
+
* plus a viewpoint plus lights, which is what the Viewer's 3D mode renders.
|
|
6
9
|
*/
|
|
7
10
|
export declare const builtinNodeRegistrations: readonly DefinitionNodeRegistration[];
|
|
8
11
|
export declare function builtinNodeRegistration(moduleId: string): DefinitionNodeRegistration | undefined;
|
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import { coreNodeRegistrations } from "./core/index.js";
|
|
2
2
|
import { geoNodeRegistrations } from "./geo/index.js";
|
|
3
|
+
import { popNodeRegistrations } from "./pop/index.js";
|
|
4
|
+
import { sceneNodeRegistrations } from "./scene/index.js";
|
|
3
5
|
/**
|
|
4
6
|
* Every reserved built-in, in one list, so that a caller does not have to know
|
|
5
|
-
* how many namespaces there are. `cascade.core.*` is structural and routing
|
|
6
|
-
* `cascade.geo.*` is the geometry set.
|
|
7
|
+
* how many namespaces there are. `cascade.core.*` is structural and routing,
|
|
8
|
+
* `cascade.geo.*` is the geometry set, and `cascade.pop.*` is the particle
|
|
9
|
+
* set — which speaks the same `geometry` type as `geo`, so any of its outputs
|
|
10
|
+
* fits any geometry node's input. `cascade.scene.*` is the assembly: geometry
|
|
11
|
+
* plus a viewpoint plus lights, which is what the Viewer's 3D mode renders.
|
|
7
12
|
*/
|
|
8
|
-
export const builtinNodeRegistrations = Object.freeze([
|
|
13
|
+
export const builtinNodeRegistrations = Object.freeze([
|
|
14
|
+
...coreNodeRegistrations,
|
|
15
|
+
...geoNodeRegistrations,
|
|
16
|
+
...popNodeRegistrations,
|
|
17
|
+
...sceneNodeRegistrations,
|
|
18
|
+
]);
|
|
9
19
|
const registrationsById = new Map(builtinNodeRegistrations.map((registration) => [
|
|
10
20
|
registration.moduleId,
|
|
11
21
|
registration,
|