@field/cascade 0.10.0 → 0.11.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 +20 -3
- package/CHANGELOG.md +187 -0
- package/README.md +1 -2
- package/dist/assets/{CodeEditor-DSZBpzdy.js → CodeEditor-4O7FQ__R.js} +4 -4
- package/dist/assets/{CodePanel-sY6sZa7B.js → CodePanel-BU-autmq.js} +2 -2
- package/dist/assets/{CustomNodeDialog-BRKnqZhp.js → CustomNodeDialog-BRpDfOV5.js} +1 -1
- package/dist/assets/{OpenGraphDialog-ZsgL-iwr.js → OpenGraphDialog-BwbRlC0X.js} +1 -1
- package/dist/assets/{ProjectSettings-Cw17nNe3.js → ProjectSettings-DLOXLxcA.js} +1 -1
- package/dist/assets/{SettingsDialog-p25h3tj0.js → SettingsDialog-Bz8JxISH.js} +1 -1
- package/dist/assets/{VersionHistoryDialog-DzFLUotB.js → VersionHistoryDialog-D5Z0nJ5-.js} +1 -1
- package/dist/assets/{core-BICrEt0y.js → core-Yqi0Ni61.js} +1 -1
- package/dist/assets/{cssMode-D7TXw57I.js → cssMode-CxUzc4vp.js} +1 -1
- package/dist/assets/{definitions-DUww2Rt-.js → definitions-GreEMXLV.js} +1 -1
- package/dist/assets/{editor.api-DvkCO3ko.js → editor.api-BNFb25CX.js} +1 -1
- package/dist/assets/{freemarker2-BA2lxsF1.js → freemarker2-0ZDnWxeM.js} +1 -1
- package/dist/assets/geo-u0n_jOsD.js +1 -0
- package/dist/assets/{handlebars-BcDiyPd8.js → handlebars-Cy18MoaD.js} +1 -1
- package/dist/assets/{html-C7O4TyhX.js → html-B-2Dx7nq.js} +1 -1
- package/dist/assets/{htmlMode-WaDGF3Mj.js → htmlMode-DUAc9B_d.js} +1 -1
- package/dist/assets/{image-DR4oeyJB.js → image-cAa-Nu9O.js} +1 -1
- package/dist/assets/{index-DyvDC6pS.js → index-5ZtDAuy2.js} +42 -41
- package/dist/assets/{javascript-CpIEK7tz.js → javascript-DeQsDqP5.js} +1 -1
- package/dist/assets/{jsonMode-B2FltW0f.js → jsonMode-BiFwJVSk.js} +1 -1
- package/dist/assets/{liquid-CN6FFHZE.js → liquid-BLoHH68a.js} +1 -1
- package/dist/assets/{lspLanguageFeatures-QhV9XtLp.js → lspLanguageFeatures-CNFgm1Kv.js} +1 -1
- package/dist/assets/math-DioIQOPJ.js +1 -0
- package/dist/assets/{mdx-DE89pafV.js → mdx-CFXQVNfs.js} +1 -1
- package/dist/assets/pop-DC_TQG9t.js +1 -0
- package/dist/assets/{python-ByTllTB9.js → python-Cf7S7p2E.js} +1 -1
- package/dist/assets/{razor-USYlRRCE.js → razor-CMHBcG-g.js} +1 -1
- package/dist/assets/{tsMode-BXpN8iUz.js → tsMode-BEih0GDj.js} +1 -1
- package/dist/assets/{typescript-DInBjGQQ.js → typescript-COEKYD_a.js} +1 -1
- package/dist/assets/{workers-C7Ye5B7D.js → workers-BNhAhMNn.js} +1 -1
- package/dist/assets/{xml-U0Uocqyo.js → xml-CPiMpnPl.js} +1 -1
- package/dist/assets/{yaml-CBw_PVYf.js → yaml-Bgp1ITLR.js} +1 -1
- package/dist/cli/Graph-ZJJTRQTM.js +2975 -0
- package/dist/cli/chunk-2KXB47FP.js +115 -0
- package/dist/cli/chunk-35D343DC.js +1447 -0
- package/dist/cli/chunk-36P5K3SD.js +631 -0
- package/dist/cli/chunk-3JTJHF7V.js +267 -0
- package/dist/cli/chunk-4UDFYF5G.js +132 -0
- package/dist/cli/chunk-53NMBJAO.js +35 -0
- package/dist/cli/chunk-A4OAMOZH.js +310 -0
- package/dist/cli/chunk-BIJO5OFS.js +71 -0
- package/dist/cli/chunk-BP7UKF36.js +376 -0
- package/dist/cli/chunk-CKS2FQWR.js +89 -0
- package/dist/cli/chunk-CO22XHNG.js +593 -0
- package/dist/cli/chunk-D6BUOHUG.js +634 -0
- package/dist/cli/chunk-DEQSEFFH.js +153 -0
- package/dist/cli/chunk-DUIUFVU2.js +241 -0
- package/dist/cli/chunk-EUIAC3U3.js +3006 -0
- package/dist/cli/chunk-FCDXJ6EK.js +2208 -0
- package/dist/cli/chunk-GFS6W3C5.js +308 -0
- package/dist/cli/chunk-HFHWYL55.js +139 -0
- package/dist/cli/chunk-HSNOBIVT.js +263 -0
- package/dist/cli/chunk-ICH7N5PN.js +26 -0
- package/dist/cli/chunk-J7VK7MNF.js +418 -0
- package/dist/cli/chunk-KH4MUBKF.js +1551 -0
- package/dist/cli/chunk-MIIEFUGG.js +623 -0
- package/dist/cli/chunk-OWWBYLHC.js +136 -0
- package/dist/cli/chunk-POMMNKZZ.js +672 -0
- package/dist/cli/chunk-QBBKRNGY.js +90 -0
- package/dist/cli/chunk-QQPA2ZHH.js +273 -0
- package/dist/cli/chunk-RLCAJBVR.js +224 -0
- package/dist/cli/chunk-RQZ4SX5R.js +1125 -0
- package/dist/cli/chunk-RUU3YWXU.js +99 -0
- package/dist/cli/chunk-RXDIMXN5.js +98 -0
- package/dist/cli/chunk-SGJAET2L.js +197 -0
- package/dist/cli/chunk-VVGSLVSF.js +151 -0
- package/dist/cli/chunk-WD62JIP6.js +118 -0
- package/dist/cli/chunk-WIH4TEIS.js +104 -0
- package/dist/cli/chunk-WKURDVYP.js +1119 -0
- package/dist/cli/chunk-WPUDGEFY.js +20 -0
- package/dist/cli/chunk-XWDSKG7N.js +1301 -0
- package/dist/cli/chunk-YAT5Y25U.js +121 -0
- package/dist/cli/chunk-ZL4JTG5Y.js +37 -0
- package/dist/cli/cliCommands-UQSFGEHF.js +3464 -0
- package/dist/cli/commands-Q23M26QM.js +1292 -0
- package/dist/cli/definitions-HF2FTHYU.js +32 -0
- package/dist/cli/doctorCommand-B7BPQMN6.js +76 -0
- package/dist/cli/edit-JHCPTQFT.js +28 -0
- package/dist/cli/editorCommands-UIF5YLUZ.js +33 -0
- package/dist/cli/encode-HAUZTYPT.js +17 -0
- package/dist/cli/frames-LSAUBZ7P.js +16 -0
- package/dist/cli/geo-4RNK3QVN.js +43 -0
- package/dist/cli/graphCommands-6BMAKGQE.js +184 -0
- package/dist/cli/graphFile-VPSQ6OF7.js +286 -0
- package/dist/cli/headlessCanvas-5XLDZT7M.js +15 -0
- package/dist/cli/helpCommand-3VRE3KVO.js +155 -0
- package/dist/cli/index.js +100 -30756
- package/dist/cli/math-ZRMLKU2D.js +16 -0
- package/dist/cli/mcp-ZLEEMYGF.js +164 -0
- package/dist/cli/parity-KINARCP2.js +328 -0
- package/dist/cli/pop-USDFXB7H.js +39 -0
- package/dist/cli/project-K3QIPGBB.js +12 -0
- package/dist/cli/projectDefinition-DMTZN2NE.js +27 -0
- package/dist/cli/projectRuntime-Z5PJOH47.js +48 -0
- package/dist/cli/registerStandardNodes-S2VLMF6J.js +3081 -0
- package/dist/cli/render-YURAPPUI.js +436 -0
- package/dist/cli/runCommand-PI764LEG.js +198 -0
- package/dist/cli/runner-RA6UKEPD.js +37 -0
- package/dist/cli/runtime/image.ts +277 -0
- package/dist/cli/runtime/stage.ts +4 -1
- package/dist/cli/stageRunner-KUNIMQKJ.js +10 -0
- package/dist/cli/verbs-RCE3K4VQ.js +19 -0
- package/dist/cli/webBuild-GT4PZT5D.js +37 -0
- package/dist/contracts/documentFormat.d.ts +18 -0
- package/dist/contracts/documentFormat.js +195 -0
- package/dist/contracts/editor.d.ts +17 -0
- package/dist/contracts/index.d.ts +1 -0
- package/dist/contracts/index.js +1 -0
- package/dist/image.d.ts +141 -0
- package/dist/image.js +127 -0
- package/dist/index.html +1 -1
- package/dist/player/editor.js +32 -7
- package/dist/runtime/builtins/headless.d.ts +19 -0
- package/dist/runtime/builtins/headless.js +25 -0
- package/dist/runtime/builtins/image/contactSheet.d.ts +226 -0
- package/dist/runtime/builtins/image/contactSheet.js +199 -0
- package/dist/runtime/builtins/image/index.d.ts +9 -0
- package/dist/runtime/builtins/image/index.js +9 -0
- package/dist/stage.js +4 -1
- package/doc/CLI_REFERENCE.md +73 -2
- package/doc/EDITOR_EXPORT.md +11 -2
- package/doc/MCP.md +17 -1
- package/doc/NODE_REFERENCE.md +142 -0
- package/doc/PROJECT_AUTHORING.md +127 -7
- package/package.json +16 -4
- package/dist/assets/ExportDialog-C7dVGua4.js +0 -358
- package/dist/assets/ExportDialog-DOq0flMV.css +0 -1
- package/dist/assets/geo-C2RHOVHC.js +0 -1
- package/dist/assets/math-DaDEgWKt.js +0 -1
- package/dist/assets/pop-pLH7L0PW.js +0 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// src/cli/sequence.ts
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
function sequenceWidth(end) {
|
|
4
|
+
return Math.max(4, String(Math.floor(end)).length);
|
|
5
|
+
}
|
|
6
|
+
function sequenceFileName(nodeId, frame, source, width, port) {
|
|
7
|
+
const extension = path.extname(source) || ".png";
|
|
8
|
+
const safe = (text) => text.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
9
|
+
const stem = port ? `${safe(nodeId)}.${safe(port)}` : safe(nodeId);
|
|
10
|
+
return `${stem}.${String(Math.floor(frame)).padStart(width, "0")}${extension}`;
|
|
11
|
+
}
|
|
12
|
+
function imagePath(value) {
|
|
13
|
+
if (typeof value === "string") return value || null;
|
|
14
|
+
if (value && typeof value === "object") {
|
|
15
|
+
const candidate = value.path;
|
|
16
|
+
if (typeof candidate === "string" && candidate) return candidate;
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
sequenceWidth,
|
|
23
|
+
sequenceFileName,
|
|
24
|
+
imagePath
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=chunk-ICH7N5PN.js.map
|
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
// packages/contracts/src/geometry.ts
|
|
2
|
+
var POSITION_ATTRIBUTE = "P";
|
|
3
|
+
var PRIMITIVE_KINDS = ["poly", "bezier", "mesh", "packed"];
|
|
4
|
+
var BEZIER_STRIDE = 3;
|
|
5
|
+
var STORAGES = /* @__PURE__ */ new Set(["f32", "f64", "i32", "u8"]);
|
|
6
|
+
var NAME = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
7
|
+
var RESERVED_NAMES = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
|
|
8
|
+
function fail(code, message) {
|
|
9
|
+
throw new TypeError(`geometry/${code}: ${message}`);
|
|
10
|
+
}
|
|
11
|
+
function emptyTopology() {
|
|
12
|
+
return {
|
|
13
|
+
vertexPoints: new Int32Array(0),
|
|
14
|
+
offsets: Int32Array.of(0),
|
|
15
|
+
kinds: new Uint8Array(0),
|
|
16
|
+
closed: new Uint8Array(0)
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function arrayType(storage) {
|
|
20
|
+
if (storage === "f64") return Float64Array;
|
|
21
|
+
if (storage === "f32") return Float32Array;
|
|
22
|
+
if (storage === "i32") return Int32Array;
|
|
23
|
+
return Uint8Array;
|
|
24
|
+
}
|
|
25
|
+
function validStoredNumber(storage, value) {
|
|
26
|
+
if (!Number.isFinite(value)) return false;
|
|
27
|
+
if (storage === "f64" || storage === "f32") return true;
|
|
28
|
+
if (!Number.isInteger(value)) return false;
|
|
29
|
+
return storage === "u8" ? value >= 0 && value <= 255 : value >= -2147483648 && value <= 2147483647;
|
|
30
|
+
}
|
|
31
|
+
function attributeArray(storage, length) {
|
|
32
|
+
if (!Number.isSafeInteger(length) || length < 0)
|
|
33
|
+
fail("attribute-length", "attribute array length must be a non-negative safe integer");
|
|
34
|
+
if (storage === "f64") return new Float64Array(length);
|
|
35
|
+
if (storage === "f32") return new Float32Array(length);
|
|
36
|
+
if (storage === "i32") return new Int32Array(length);
|
|
37
|
+
return new Uint8Array(length);
|
|
38
|
+
}
|
|
39
|
+
function attributeArrayFrom(storage, values) {
|
|
40
|
+
const array = attributeArray(storage, values.length);
|
|
41
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
42
|
+
const value = values[index];
|
|
43
|
+
if (!validStoredNumber(storage, value))
|
|
44
|
+
fail(
|
|
45
|
+
"attribute-value",
|
|
46
|
+
`${String(value)} cannot be represented as ${storage}`
|
|
47
|
+
);
|
|
48
|
+
array[index] = value;
|
|
49
|
+
if (!Number.isFinite(array[index]))
|
|
50
|
+
fail("attribute-value", `${String(value)} overflows ${storage}`);
|
|
51
|
+
}
|
|
52
|
+
return array;
|
|
53
|
+
}
|
|
54
|
+
function isStringAttribute(attribute) {
|
|
55
|
+
return attribute.storage === "string";
|
|
56
|
+
}
|
|
57
|
+
function levelCount(geometry, level) {
|
|
58
|
+
if (level === "point") return geometry.pointCount;
|
|
59
|
+
if (level === "vertex") return geometry.vertexCount;
|
|
60
|
+
if (level === "primitive") return geometry.primitiveCount;
|
|
61
|
+
return 1;
|
|
62
|
+
}
|
|
63
|
+
function checkName(name, path) {
|
|
64
|
+
if (!NAME.test(name) || RESERVED_NAMES.has(name))
|
|
65
|
+
fail("invalid-name", `${path}.${name} is not a valid attribute name`);
|
|
66
|
+
}
|
|
67
|
+
function checkAttributeSet(set, count, level) {
|
|
68
|
+
for (const [name, attribute] of Object.entries(set)) {
|
|
69
|
+
checkName(name, level);
|
|
70
|
+
if (isStringAttribute(attribute)) {
|
|
71
|
+
if (!(attribute.data instanceof Int32Array))
|
|
72
|
+
fail("attribute-storage", `${level}.${name} string indices must be Int32Array`);
|
|
73
|
+
if (attribute.size !== 1)
|
|
74
|
+
fail("string-size", `${level}.${name} string attributes have size 1`);
|
|
75
|
+
if (attribute.data.length !== count)
|
|
76
|
+
fail(
|
|
77
|
+
"attribute-length",
|
|
78
|
+
`${level}.${name} has ${attribute.data.length} entries for ${count} elements`
|
|
79
|
+
);
|
|
80
|
+
for (const index of attribute.data)
|
|
81
|
+
if (index < -1 || index >= attribute.table.length)
|
|
82
|
+
fail(
|
|
83
|
+
"string-index",
|
|
84
|
+
`${level}.${name} references table entry ${index}`
|
|
85
|
+
);
|
|
86
|
+
if (!Array.isArray(attribute.table) || attribute.table.some((item) => typeof item !== "string"))
|
|
87
|
+
fail("string-table", `${level}.${name} needs a string table`);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (!Number.isInteger(attribute.size) || attribute.size < 1)
|
|
91
|
+
fail("attribute-size", `${level}.${name} needs a size of at least 1`);
|
|
92
|
+
if (!STORAGES.has(attribute.storage))
|
|
93
|
+
fail(
|
|
94
|
+
"attribute-storage",
|
|
95
|
+
`${level}.${name} has an unknown storage ${String(attribute.storage)}`
|
|
96
|
+
);
|
|
97
|
+
if (!(attribute.data instanceof arrayType(attribute.storage)))
|
|
98
|
+
fail(
|
|
99
|
+
"attribute-storage",
|
|
100
|
+
`${level}.${name} declares ${attribute.storage} but uses ${attribute.data?.constructor?.name ?? "unknown storage"}`
|
|
101
|
+
);
|
|
102
|
+
if (attribute.data.length !== attribute.size * count)
|
|
103
|
+
fail(
|
|
104
|
+
"attribute-length",
|
|
105
|
+
`${level}.${name} has ${attribute.data.length} values for ${count} elements of size ${attribute.size}`
|
|
106
|
+
);
|
|
107
|
+
for (const value of attribute.data)
|
|
108
|
+
if (!Number.isFinite(value))
|
|
109
|
+
fail("non-finite", `${level}.${name} contains ${String(value)}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function checkGroups(groups, count, level) {
|
|
113
|
+
for (const [name, mask] of Object.entries(groups)) {
|
|
114
|
+
checkName(name, level);
|
|
115
|
+
if (mask.length !== count)
|
|
116
|
+
fail(
|
|
117
|
+
"group-length",
|
|
118
|
+
`${level}.${name} covers ${mask.length} of ${count} elements`
|
|
119
|
+
);
|
|
120
|
+
for (const member of mask)
|
|
121
|
+
if (member !== 0 && member !== 1)
|
|
122
|
+
fail("group-mask", `${level}.${name} contains ${member}; masks contain only 0 or 1`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function createGeometry(parts) {
|
|
126
|
+
const pointCount = parts.pointCount;
|
|
127
|
+
if (!Number.isSafeInteger(pointCount) || pointCount < 0)
|
|
128
|
+
fail("point-count", "pointCount must be a non-negative safe integer");
|
|
129
|
+
const topology = parts.topology ?? emptyTopology();
|
|
130
|
+
if (!(topology.vertexPoints instanceof Int32Array) || !(topology.offsets instanceof Int32Array) || !(topology.kinds instanceof Uint8Array) || !(topology.closed instanceof Uint8Array))
|
|
131
|
+
fail("topology-storage", "topology uses Int32Array indices and Uint8Array flags");
|
|
132
|
+
const primitiveCount = topology.offsets.length - 1;
|
|
133
|
+
if (primitiveCount < 0)
|
|
134
|
+
fail("offsets", "topology.offsets needs primitiveCount + 1 entries");
|
|
135
|
+
if (topology.offsets[0] !== 0)
|
|
136
|
+
fail("offsets", "topology.offsets starts at 0");
|
|
137
|
+
for (let index = 1; index <= primitiveCount; index += 1)
|
|
138
|
+
if (topology.offsets[index] < topology.offsets[index - 1])
|
|
139
|
+
fail("offsets", "topology.offsets must not decrease");
|
|
140
|
+
const vertexCount = topology.offsets[primitiveCount];
|
|
141
|
+
if (vertexCount !== topology.vertexPoints.length)
|
|
142
|
+
fail(
|
|
143
|
+
"offsets",
|
|
144
|
+
`topology.offsets ends at ${vertexCount} for ${topology.vertexPoints.length} vertices`
|
|
145
|
+
);
|
|
146
|
+
if (topology.kinds.length !== primitiveCount || topology.closed.length !== primitiveCount)
|
|
147
|
+
fail(
|
|
148
|
+
"topology-length",
|
|
149
|
+
`topology.kinds and topology.closed need ${primitiveCount} entries`
|
|
150
|
+
);
|
|
151
|
+
for (const point2 of topology.vertexPoints)
|
|
152
|
+
if (point2 < 0 || point2 >= pointCount)
|
|
153
|
+
fail("vertex-point", `vertex references point ${point2}`);
|
|
154
|
+
for (const kind of topology.kinds)
|
|
155
|
+
if (kind >= PRIMITIVE_KINDS.length)
|
|
156
|
+
fail("primitive-kind", `unknown primitive kind ${kind}`);
|
|
157
|
+
for (const closed of topology.closed)
|
|
158
|
+
if (closed !== 0 && closed !== 1)
|
|
159
|
+
fail("closed-mask", `topology.closed contains ${closed}; flags contain only 0 or 1`);
|
|
160
|
+
const bezier = PRIMITIVE_KINDS.indexOf("bezier");
|
|
161
|
+
for (let index = 0; index < primitiveCount; index += 1) {
|
|
162
|
+
if (topology.kinds[index] !== bezier) continue;
|
|
163
|
+
const count = topology.offsets[index + 1] - topology.offsets[index];
|
|
164
|
+
const closed = topology.closed[index] === 1;
|
|
165
|
+
const minimum = closed ? BEZIER_STRIDE : BEZIER_STRIDE + 1;
|
|
166
|
+
if (count < minimum || (count - (closed ? 0 : 1)) % BEZIER_STRIDE !== 0)
|
|
167
|
+
fail(
|
|
168
|
+
"bezier-arity",
|
|
169
|
+
`primitive ${index} has ${count} vertices, and a ${closed ? "closed" : "open"} bezier needs ${closed ? "3n" : "3n + 1"}`
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
const point = parts.point;
|
|
173
|
+
const position = point[POSITION_ATTRIBUTE];
|
|
174
|
+
if (position === void 0)
|
|
175
|
+
fail("missing-position", "point.P is required on every geometry");
|
|
176
|
+
if (isStringAttribute(position))
|
|
177
|
+
fail("position-storage", "point.P must be a numeric attribute");
|
|
178
|
+
if (position.size !== 2 && position.size !== 3)
|
|
179
|
+
fail("position-size", "point.P must have a size of 2 or 3");
|
|
180
|
+
checkAttributeSet(point, pointCount, "point");
|
|
181
|
+
const vertex = parts.vertex ?? {};
|
|
182
|
+
checkAttributeSet(vertex, vertexCount, "vertex");
|
|
183
|
+
const primitive = parts.primitive ?? {};
|
|
184
|
+
checkAttributeSet(primitive, primitiveCount, "primitive");
|
|
185
|
+
const pointGroups = parts.pointGroups ?? {};
|
|
186
|
+
checkGroups(pointGroups, pointCount, "pointGroups");
|
|
187
|
+
const primitiveGroups = parts.primitiveGroups ?? {};
|
|
188
|
+
checkGroups(primitiveGroups, primitiveCount, "primitiveGroups");
|
|
189
|
+
const detail = parts.detail ?? {};
|
|
190
|
+
for (const [name, value] of Object.entries(detail)) {
|
|
191
|
+
checkName(name, "detail");
|
|
192
|
+
if (typeof value === "number") {
|
|
193
|
+
if (!Number.isFinite(value))
|
|
194
|
+
fail("non-finite", `detail.${name} contains ${String(value)}`);
|
|
195
|
+
} else if (typeof value !== "string") {
|
|
196
|
+
if (!Array.isArray(value) || value.some((item) => !Number.isFinite(item)))
|
|
197
|
+
fail("detail-value", `detail.${name} must be a finite number, string, or finite number array`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return freezeGeometry({
|
|
201
|
+
kind: "geometry",
|
|
202
|
+
pointCount,
|
|
203
|
+
vertexCount,
|
|
204
|
+
primitiveCount,
|
|
205
|
+
topology,
|
|
206
|
+
point,
|
|
207
|
+
vertex,
|
|
208
|
+
primitive,
|
|
209
|
+
detail,
|
|
210
|
+
pointGroups,
|
|
211
|
+
primitiveGroups
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
function freezeGeometry(geometry) {
|
|
215
|
+
for (const level of ["point", "vertex", "primitive"]) {
|
|
216
|
+
const set = geometry[level];
|
|
217
|
+
for (const attribute of Object.values(set)) {
|
|
218
|
+
if (isStringAttribute(attribute)) Object.freeze(attribute.table);
|
|
219
|
+
Object.freeze(attribute);
|
|
220
|
+
}
|
|
221
|
+
Object.freeze(set);
|
|
222
|
+
}
|
|
223
|
+
Object.freeze(geometry.topology);
|
|
224
|
+
for (const value of Object.values(geometry.detail))
|
|
225
|
+
if (Array.isArray(value)) Object.freeze(value);
|
|
226
|
+
Object.freeze(geometry.detail);
|
|
227
|
+
Object.freeze(geometry.pointGroups);
|
|
228
|
+
Object.freeze(geometry.primitiveGroups);
|
|
229
|
+
return Object.freeze(geometry);
|
|
230
|
+
}
|
|
231
|
+
function emptyGeometry(positionSize = 2) {
|
|
232
|
+
return createGeometry({
|
|
233
|
+
pointCount: 0,
|
|
234
|
+
point: {
|
|
235
|
+
[POSITION_ATTRIBUTE]: {
|
|
236
|
+
storage: "f64",
|
|
237
|
+
size: positionSize,
|
|
238
|
+
data: new Float64Array(0)
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
function isRecord(value) {
|
|
244
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
245
|
+
}
|
|
246
|
+
function finiteNumbers(value) {
|
|
247
|
+
return Array.isArray(value) && value.every((item) => typeof item === "number" && Number.isFinite(item));
|
|
248
|
+
}
|
|
249
|
+
function fromJsonAttributeSet(raw, level) {
|
|
250
|
+
if (raw === void 0) return {};
|
|
251
|
+
const result = {};
|
|
252
|
+
for (const [name, attribute] of Object.entries(raw)) {
|
|
253
|
+
if (!isRecord(attribute))
|
|
254
|
+
fail("attribute-shape", `${level}.${name} must be an object`);
|
|
255
|
+
if (attribute.storage === "string") {
|
|
256
|
+
const table = attribute.table;
|
|
257
|
+
if (!Array.isArray(table) || table.some((item) => typeof item !== "string"))
|
|
258
|
+
fail("string-table", `${level}.${name} needs a string table`);
|
|
259
|
+
if (!int32Numbers(attribute.data))
|
|
260
|
+
fail("attribute-data", `${level}.${name} needs 32-bit integer indices`);
|
|
261
|
+
result[name] = {
|
|
262
|
+
storage: "string",
|
|
263
|
+
size: 1,
|
|
264
|
+
table: [...table],
|
|
265
|
+
data: Int32Array.from(attribute.data)
|
|
266
|
+
};
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
if (typeof attribute.storage !== "string" || !STORAGES.has(attribute.storage))
|
|
270
|
+
fail(
|
|
271
|
+
"attribute-storage",
|
|
272
|
+
`${level}.${name} has an unknown storage ${String(attribute.storage)}`
|
|
273
|
+
);
|
|
274
|
+
if (!finiteNumbers(attribute.data))
|
|
275
|
+
fail("attribute-data", `${level}.${name} needs finite numeric data`);
|
|
276
|
+
const size = attribute.size;
|
|
277
|
+
if (typeof size !== "number" || !Number.isInteger(size) || size < 1)
|
|
278
|
+
fail("attribute-size", `${level}.${name} needs a size of at least 1`);
|
|
279
|
+
result[name] = {
|
|
280
|
+
storage: attribute.storage,
|
|
281
|
+
size,
|
|
282
|
+
data: attributeArrayFrom(
|
|
283
|
+
attribute.storage,
|
|
284
|
+
attribute.data
|
|
285
|
+
)
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
return result;
|
|
289
|
+
}
|
|
290
|
+
function groupsFromJson(raw, count, level) {
|
|
291
|
+
if (raw === void 0) return {};
|
|
292
|
+
const result = {};
|
|
293
|
+
for (const [name, indices] of Object.entries(raw)) {
|
|
294
|
+
if (!finiteNumbers(indices))
|
|
295
|
+
fail("group-indices", `${level}.${name} must be a list of indices`);
|
|
296
|
+
const mask = new Uint8Array(count);
|
|
297
|
+
for (const index of indices) {
|
|
298
|
+
if (!Number.isInteger(index) || index < 0 || index >= count)
|
|
299
|
+
fail("group-indices", `${level}.${name} references element ${index}`);
|
|
300
|
+
mask[index] = 1;
|
|
301
|
+
}
|
|
302
|
+
result[name] = mask;
|
|
303
|
+
}
|
|
304
|
+
return result;
|
|
305
|
+
}
|
|
306
|
+
function geometryFromJson(value) {
|
|
307
|
+
if (!isRecord(value) || value.kind !== "geometry")
|
|
308
|
+
fail("not-geometry", "a geometry literal needs kind: 'geometry'");
|
|
309
|
+
const pointCount = value.pointCount;
|
|
310
|
+
if (!Number.isSafeInteger(pointCount) || pointCount < 0)
|
|
311
|
+
fail("point-count", "pointCount must be a non-negative safe integer");
|
|
312
|
+
const rawTopology = value.topology;
|
|
313
|
+
let topology = emptyTopology();
|
|
314
|
+
if (rawTopology !== void 0) {
|
|
315
|
+
if (!isRecord(rawTopology))
|
|
316
|
+
fail("topology-shape", "topology must be an object");
|
|
317
|
+
if (!int32Numbers(rawTopology.vertexPoints) || !int32Numbers(rawTopology.offsets))
|
|
318
|
+
fail("topology-shape", "topology needs vertexPoints and offsets");
|
|
319
|
+
const primitiveCount = rawTopology.offsets.length - 1;
|
|
320
|
+
if (primitiveCount < 0)
|
|
321
|
+
fail("offsets", "topology.offsets needs primitiveCount + 1 entries");
|
|
322
|
+
const kinds = rawTopology.kinds;
|
|
323
|
+
const closed = rawTopology.closed;
|
|
324
|
+
if (kinds !== void 0 && !byteNumbers(kinds))
|
|
325
|
+
fail("topology-shape", "topology.kinds must be numeric");
|
|
326
|
+
if (closed !== void 0 && (!byteNumbers(closed) || closed.some((item) => item !== 0 && item !== 1)))
|
|
327
|
+
fail("topology-shape", "topology.closed must be numeric");
|
|
328
|
+
topology = {
|
|
329
|
+
vertexPoints: Int32Array.from(rawTopology.vertexPoints),
|
|
330
|
+
offsets: Int32Array.from(rawTopology.offsets),
|
|
331
|
+
kinds: kinds === void 0 ? new Uint8Array(primitiveCount) : Uint8Array.from(kinds),
|
|
332
|
+
closed: closed === void 0 ? new Uint8Array(primitiveCount) : Uint8Array.from(closed)
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
const detail = {};
|
|
336
|
+
for (const [name, item] of Object.entries(value.detail ?? {})) {
|
|
337
|
+
if (typeof item === "number" || typeof item === "string")
|
|
338
|
+
detail[name] = item;
|
|
339
|
+
else if (finiteNumbers(item)) detail[name] = [...item];
|
|
340
|
+
else
|
|
341
|
+
fail(
|
|
342
|
+
"detail-value",
|
|
343
|
+
`detail.${name} must be a number, string, or number array`
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
return createGeometry({
|
|
347
|
+
pointCount,
|
|
348
|
+
point: fromJsonAttributeSet(value.point, "point"),
|
|
349
|
+
vertex: fromJsonAttributeSet(value.vertex, "vertex"),
|
|
350
|
+
primitive: fromJsonAttributeSet(value.primitive, "primitive"),
|
|
351
|
+
detail,
|
|
352
|
+
topology,
|
|
353
|
+
pointGroups: groupsFromJson(value.pointGroups, pointCount, "pointGroups"),
|
|
354
|
+
primitiveGroups: groupsFromJson(
|
|
355
|
+
value.primitiveGroups,
|
|
356
|
+
topology.offsets.length - 1,
|
|
357
|
+
"primitiveGroups"
|
|
358
|
+
)
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
function isGeometryJson(value) {
|
|
362
|
+
try {
|
|
363
|
+
geometryFromJson(value);
|
|
364
|
+
return true;
|
|
365
|
+
} catch {
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
function isGeometryFileRef(value) {
|
|
370
|
+
if (!isRecord(value) || value.kind !== "geometry-file") return false;
|
|
371
|
+
if (typeof value.path !== "string" || value.path.length === 0) return false;
|
|
372
|
+
if (value.format !== "npy" && value.format !== "json") return false;
|
|
373
|
+
if (value.format === "npy" && value.attribute === void 0) return false;
|
|
374
|
+
if (value.attribute !== void 0) {
|
|
375
|
+
const attribute = value.attribute;
|
|
376
|
+
if (!isRecord(attribute)) return false;
|
|
377
|
+
if (attribute.level !== "point" && attribute.level !== "vertex" && attribute.level !== "primitive")
|
|
378
|
+
return false;
|
|
379
|
+
if (typeof attribute.name !== "string" || !NAME.test(attribute.name) || RESERVED_NAMES.has(attribute.name))
|
|
380
|
+
return false;
|
|
381
|
+
if (typeof attribute.size !== "number" || !Number.isInteger(attribute.size) || attribute.size < 1)
|
|
382
|
+
return false;
|
|
383
|
+
if (typeof attribute.storage !== "string" || !STORAGES.has(attribute.storage))
|
|
384
|
+
return false;
|
|
385
|
+
}
|
|
386
|
+
for (const key of ["pointCount", "primitiveCount"]) {
|
|
387
|
+
const count = value[key];
|
|
388
|
+
if (count !== void 0 && (typeof count !== "number" || !Number.isSafeInteger(count) || count < 0))
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
return true;
|
|
392
|
+
}
|
|
393
|
+
function isGeometrySerialized(value) {
|
|
394
|
+
return isGeometryJson(value) || isGeometryFileRef(value);
|
|
395
|
+
}
|
|
396
|
+
function integerNumbers(value) {
|
|
397
|
+
return finiteNumbers(value) && value.every(Number.isSafeInteger);
|
|
398
|
+
}
|
|
399
|
+
function int32Numbers(value) {
|
|
400
|
+
return integerNumbers(value) && value.every((item) => item >= -2147483648 && item <= 2147483647);
|
|
401
|
+
}
|
|
402
|
+
function byteNumbers(value) {
|
|
403
|
+
return integerNumbers(value) && value.every((item) => item >= 0 && item <= 255);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
export {
|
|
407
|
+
POSITION_ATTRIBUTE,
|
|
408
|
+
PRIMITIVE_KINDS,
|
|
409
|
+
BEZIER_STRIDE,
|
|
410
|
+
attributeArray,
|
|
411
|
+
attributeArrayFrom,
|
|
412
|
+
isStringAttribute,
|
|
413
|
+
levelCount,
|
|
414
|
+
createGeometry,
|
|
415
|
+
emptyGeometry,
|
|
416
|
+
isGeometrySerialized
|
|
417
|
+
};
|
|
418
|
+
//# sourceMappingURL=chunk-J7VK7MNF.js.map
|