topotopo 0.2.0 → 0.3.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/README.md +19 -2
- package/dist/cli.js +67 -4
- package/dist/graph/engine.js +14 -0
- package/dist/graph/types.d.ts +17 -0
- package/dist/host/artifacts.d.ts +21 -0
- package/dist/host/artifacts.js +58 -0
- package/dist/host/export-targets.d.ts +33 -0
- package/dist/host/export-targets.js +84 -0
- package/dist/io/targets.d.ts +31 -0
- package/dist/io/targets.js +75 -0
- package/dist/mcp/docs.d.ts +1 -1
- package/dist/mcp/docs.js +15 -2
- package/dist/mcp/tools.d.ts +1 -1
- package/dist/mcp/tools.js +87 -34
- package/dist/nodes/code.js +32 -6
- package/dist/viewer/app/camera.js +26 -6
- package/dist/viewer/app/export-popover.js +68 -0
- package/dist/viewer/app/image-view.js +114 -0
- package/dist/viewer/app/keymap.js +15 -3
- package/dist/viewer/app/layers.js +23 -4
- package/dist/viewer/app/main.js +70 -14
- package/dist/viewer/app/outliner.js +56 -15
- package/dist/viewer/app/outputs.css +73 -0
- package/dist/viewer/app/outputs.js +240 -0
- package/dist/viewer/app/select.js +13 -2
- package/dist/viewer/app/status.js +20 -0
- package/dist/viewer/app/style.css +1 -0
- package/dist/viewer/index.html +19 -5
- package/dist/viewer/outputs.d.ts +54 -0
- package/dist/viewer/outputs.js +436 -0
- package/dist/viewer/server.d.ts +5 -0
- package/dist/viewer/server.js +48 -0
- package/dist/workspace.d.ts +8 -2
- package/dist/workspace.js +37 -3
- package/package.json +4 -3
package/dist/workspace.js
CHANGED
|
@@ -11,7 +11,7 @@ import { didYouMean, renameExprRefs } from './graph/params.js';
|
|
|
11
11
|
import { migrateGraph } from './graph/migrate.js';
|
|
12
12
|
const NAME_RE = /^[A-Za-z_][\w.-]*$/;
|
|
13
13
|
const GEOMETRY_EXTS = new Set(['obj', 'stl', 'ply', 'glb', 'gltf', 'geo', 'bgeo', 'blend', 'csv', 'json', 'points.json']);
|
|
14
|
-
const IMAGE_EXTS = new Set(['png']);
|
|
14
|
+
const IMAGE_EXTS = new Set(['png', 'jpg', 'jpeg', 'webp']);
|
|
15
15
|
/** Lower-case extension of a file name without the dot; ".points.json" is one extension, dot-files have none. */
|
|
16
16
|
export function inputExt(file) {
|
|
17
17
|
const b = file.toLowerCase().replace(/^.*[\\/]/, '');
|
|
@@ -41,15 +41,17 @@ export class Workspace {
|
|
|
41
41
|
listeners = new Set();
|
|
42
42
|
/** the inputs folder given to the constructor (WorkspaceOptions.inputs), if any */
|
|
43
43
|
inputsAt;
|
|
44
|
+
exportsAt;
|
|
44
45
|
constructor(dir, engine, opts = {}) {
|
|
45
46
|
this.dir = path.resolve(dir);
|
|
46
47
|
this.engine = engine;
|
|
47
48
|
this.inputsAt = opts.inputs === undefined ? undefined : path.resolve(opts.inputs);
|
|
49
|
+
this.exportsAt = opts.exports === undefined ? undefined : path.resolve(opts.exports);
|
|
48
50
|
engine.graphResolver = (n) => this.graphs.get(n);
|
|
49
51
|
}
|
|
50
52
|
get graphDir() { return path.join(this.dir, 'graphs'); }
|
|
51
53
|
get assetDir() { return path.join(this.dir, 'assets'); }
|
|
52
|
-
get exportDir() { return path.join(this.dir, 'exports'); }
|
|
54
|
+
get exportDir() { return this.exportsAt ?? path.join(this.dir, 'exports'); }
|
|
53
55
|
/**
|
|
54
56
|
* files people drop in: meshes, guide curves and points, PNG masks and heightmaps (read as "inputs/<path>");
|
|
55
57
|
* <dir>/inputs unless the constructor was given another folder
|
|
@@ -168,6 +170,10 @@ export class Workspace {
|
|
|
168
170
|
base.params = { ...(base.params ?? {}), ...patch.params };
|
|
169
171
|
if (patch.output)
|
|
170
172
|
base.output = patch.output;
|
|
173
|
+
if (patch.outputs)
|
|
174
|
+
base.outputs = { ...base.outputs, ...patch.outputs };
|
|
175
|
+
if (patch.export !== undefined)
|
|
176
|
+
base.export = patch.export;
|
|
171
177
|
if (patch.description)
|
|
172
178
|
base.description = patch.description;
|
|
173
179
|
return base;
|
|
@@ -253,6 +259,9 @@ export class Workspace {
|
|
|
253
259
|
delete g.nodes[n];
|
|
254
260
|
if (g.output === n)
|
|
255
261
|
delete g.output;
|
|
262
|
+
for (const [id, out] of Object.entries(g.outputs ?? {}))
|
|
263
|
+
if (out.node === n)
|
|
264
|
+
delete g.outputs[id];
|
|
256
265
|
break;
|
|
257
266
|
}
|
|
258
267
|
case 'connect': {
|
|
@@ -282,6 +291,9 @@ export class Workspace {
|
|
|
282
291
|
setRef(r.node, r.idx, op.to);
|
|
283
292
|
if (g.output === n)
|
|
284
293
|
g.output = op.to;
|
|
294
|
+
for (const out of Object.values(g.outputs ?? {}))
|
|
295
|
+
if (out.node === n)
|
|
296
|
+
out.node = op.to;
|
|
285
297
|
// expression references: npoints("old"), ch("old/param") …
|
|
286
298
|
const touched = [];
|
|
287
299
|
for (const [k, spec] of Object.entries(g.nodes)) {
|
|
@@ -312,6 +324,28 @@ export class Workspace {
|
|
|
312
324
|
case 'bypass':
|
|
313
325
|
g.nodes[need(op.node, where)].bypass = op.value ?? true;
|
|
314
326
|
break;
|
|
327
|
+
case 'export': {
|
|
328
|
+
// the target of the default output, or of a named one; null removes it (validated with the graph)
|
|
329
|
+
if (op.export === undefined)
|
|
330
|
+
throw new Error(`${where}: give "export": a format ("glb"), {format, path?, ...options}, or null`);
|
|
331
|
+
if (op.output === undefined) {
|
|
332
|
+
if (op.export === null)
|
|
333
|
+
delete g.export;
|
|
334
|
+
else
|
|
335
|
+
g.export = op.export;
|
|
336
|
+
break;
|
|
337
|
+
}
|
|
338
|
+
const out = g.outputs?.[op.output];
|
|
339
|
+
if (!out) {
|
|
340
|
+
const s = didYouMean(op.output, Object.keys(g.outputs ?? {}));
|
|
341
|
+
throw new Error(`${where}: no output "${op.output}"${s.length ? ` — did you mean ${s.join(', ')}?` : ''} (publish it in "outputs" first)`);
|
|
342
|
+
}
|
|
343
|
+
if (op.export === null)
|
|
344
|
+
delete out.export;
|
|
345
|
+
else
|
|
346
|
+
out.export = op.export;
|
|
347
|
+
break;
|
|
348
|
+
}
|
|
315
349
|
case 'insert': {
|
|
316
350
|
const after = need(op.after, `${where} after`);
|
|
317
351
|
if (!op.node || !NAME_RE.test(op.node) || g.nodes[op.node])
|
|
@@ -327,7 +361,7 @@ export class Workspace {
|
|
|
327
361
|
notes.push(`inserted "${op.node}" after "${after}"${consumers.length ? `; now feeds ${consumers.map((c) => c.node).join(', ')}` : ''}`);
|
|
328
362
|
break;
|
|
329
363
|
}
|
|
330
|
-
default: throw new Error(`${where}: unknown op. Use set, add, remove, connect, rename, output, vars, bypass, replace, insert`);
|
|
364
|
+
default: throw new Error(`${where}: unknown op. Use set, add, remove, connect, rename, output, vars, bypass, replace, insert, export`);
|
|
331
365
|
}
|
|
332
366
|
}
|
|
333
367
|
return { graph: g, notes };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "topotopo",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "An open-source procedural geometry engine: node graphs in JSON, cooked headless and deterministic, exported to Unreal, Blender and Houdini. Built for LLM agents through MCP, and for people through the CLI.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"mcp": "node src/mcp/server.ts",
|
|
39
39
|
"preview": "node scripts/preview.ts --examples",
|
|
40
40
|
"cook": "node src/cli.ts",
|
|
41
|
-
"test": "node test/smoke.ts && node test/golden.ts && node test/property.ts && node test/fuzz.ts && node test/docs.ts && node test/portability.ts && node test/examples.ts && node scripts/gen-notice.ts --check && node test/io.ts && node test/import.ts && node test/interop.ts && node test/mcp.ts && node test/engine.ts && node test/viewer.ts && node test/viewer-logic.ts && node test/topology.ts && node test/deform.ts && node test/cloth.ts && node test/arrays.ts && node test/bugs.ts && node test/uv.ts && node test/polyedit.ts && node test/bevel.ts && node test/measure.ts && node test/render.ts && node test/packed.ts && node test/heightfield.ts && node test/remesh.ts && node test/pcg.ts && node test/scatterkernel.ts && node test/splines.ts && node test/shelf.ts && node test/textures.ts && node test/pool.ts && node test/kernelsloader.ts && node test/kernels.ts && node test/sdfgrid.ts && node test/remeshquad.ts && node test/erosionkernel.ts && node test/erosionsimd.ts && node test/particles.ts && node test/rbd.ts && node test/limits.ts",
|
|
41
|
+
"test": "node test/smoke.ts && node test/golden.ts && node test/property.ts && node test/fuzz.ts && node test/docs.ts && node test/portability.ts && node test/examples.ts && node scripts/gen-notice.ts --check && node test/io.ts && node test/import.ts && node test/interop.ts && node test/mcp.ts && node test/engine.ts && node test/viewer.ts && node test/viewer-logic.ts && node test/topology.ts && node test/deform.ts && node test/cloth.ts && node test/arrays.ts && node test/bugs.ts && node test/uv.ts && node test/polyedit.ts && node test/bevel.ts && node test/measure.ts && node test/render.ts && node test/packed.ts && node test/heightfield.ts && node test/remesh.ts && node test/pcg.ts && node test/scatterkernel.ts && node test/splines.ts && node test/shelf.ts && node test/textures.ts && node test/pool.ts && node test/kernelsloader.ts && node test/kernels.ts && node test/sdfgrid.ts && node test/remeshquad.ts && node test/erosionkernel.ts && node test/erosionsimd.ts && node test/particles.ts && node test/rbd.ts && node test/limits.ts && node test/viewer-outputs.ts",
|
|
42
42
|
"test:limits": "node test/limits.ts",
|
|
43
43
|
"kernels:build": "node scripts/kernels-build.ts",
|
|
44
44
|
"test:kernels": "node test/scatterkernel.ts && node test/kernelsloader.ts && node test/kernels.ts && node test/sdfgrid.ts && node test/remeshquad.ts && node test/erosionkernel.ts && node test/erosionsimd.ts",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"test:portability": "node test/portability.ts",
|
|
64
64
|
"test:examples": "node test/examples.ts",
|
|
65
65
|
"test:interop": "node test/interop.ts",
|
|
66
|
-
"test:viewer": "node test/viewer.ts && node test/viewer-logic.ts",
|
|
66
|
+
"test:viewer": "node test/viewer.ts && node test/viewer-logic.ts && node test/viewer-outputs.ts",
|
|
67
67
|
"showcase": "node test/showcase.ts",
|
|
68
68
|
"export:demo": "node scripts/export-demo.ts",
|
|
69
69
|
"demo:footage": "node scripts/demo-footage.ts",
|
|
@@ -99,6 +99,7 @@
|
|
|
99
99
|
"@modelcontextprotocol/sdk": "^1.32.0",
|
|
100
100
|
"d3-delaunay": "^6.0.4",
|
|
101
101
|
"earcut": "^3.2.4",
|
|
102
|
+
"fflate": "0.8.3",
|
|
102
103
|
"manifold-3d": "^3.5.4",
|
|
103
104
|
"meshoptimizer": "^1.3.0",
|
|
104
105
|
"opentype.js": "^2.0.0",
|