@womp/spark-agent 4.3.0 → 4.4.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/dist/capabilities/scene.js +14 -9
- package/dist/scene-metadata.js +8 -8
- package/dist/sdk-scene-host.js +1 -3
- package/dist/womp-scene-api.d.ts +2 -2
- package/dist/womp-scene-api.js +6 -7
- package/package.json +2 -2
- package/.env.example +0 -6
|
@@ -37,7 +37,7 @@ export function createSceneCapability(host) {
|
|
|
37
37
|
skills: [
|
|
38
38
|
{
|
|
39
39
|
name: "scene-editing",
|
|
40
|
-
version: "
|
|
40
|
+
version: "39",
|
|
41
41
|
description: "Inspect the open scene and edit its objects, materials, curves, and environment.",
|
|
42
42
|
instructions: `Read the scene first and keep its revision and object IDs. read() includes health.
|
|
43
43
|
Use womp.scene.health() to refresh whole-scene health or womp.scene.health(objectIds) to check specific objects (mapped to their owning Areas).
|
|
@@ -62,7 +62,7 @@ Point defaults: position/rotation/handles zero, profile size {x:1,y:1,z:1} in pr
|
|
|
62
62
|
Removing all points is supported. One point renders a single profile primitive, not a path.
|
|
63
63
|
Curves render sampled profiles, not a continuous sweep. For smooth curves, start with nodeSetDensity(curveId, 250) and nodeSetBlend(curveId, 3).
|
|
64
64
|
Density increases sampling and primitive cost; the 3 mm blend softens joins, not sample positions. Adjust blend to preserve thin features and the intended silhouette; these settings do not guarantee continuity.
|
|
65
|
-
nodeSetUnionResolution(unionId, resolution) sets
|
|
65
|
+
nodeSetUnionResolution(unionId, resolution) sets a dimensionless detail level, clamped to 0.01–0.65: higher is finer and costs more voxels. Set the owning outermost Area, not a nested Union. Material emission ranges from 0 to 1.
|
|
66
66
|
nodeSetBlend and mirror goop take radii in millimetres before parent scaling, regardless of project units, and clamp to 0–500 mm. This does not apply to the FlowIR Boolean Blend port, which takes native units; geometry-nodes-reference gives its conversion.
|
|
67
67
|
V1/V2 curve transforms are read-only;
|
|
68
68
|
edit their points instead. Handles and closure are available only on V3 Bezier curves.
|
|
@@ -81,21 +81,26 @@ Never replace a parametric graph with ordinary primitives to color it. Ordinary
|
|
|
81
81
|
nodeSetColor writes the node color field (used by lights); it does not replace a geometry object's material color.
|
|
82
82
|
Do not recolor a shared material unless every object using it should change. Create and assign the material in the same edit as the scene geometry that uses it; a Geometry Nodes graph instead consumes a material ID created in an earlier edit.
|
|
83
83
|
Create primitives, curves, and text inside Areas/Unions. Respect tree order for subtraction and intersection.
|
|
84
|
-
Groups are organizational only; move and rotate their child Areas individually, not the Group.
|
|
84
|
+
Groups are organizational only; move and rotate their child Areas individually, not the Group.
|
|
85
|
+
An Area is an outermost Union with no Union ancestor: it has its own modeller, bounds, and volumetric resolution. Nested Unions share that Area's resolution, even through Groups.
|
|
86
|
+
Choose Area boundaries for evaluation needs, not individual editability: parts within an Area remain independently editable. Sibling Areas under a Group can overlap without blending together, while each blends internally and has independent resolution. Keep required shared smooth joins or Boolean evaluation within one Area; overlapping independent Areas are not a watertight Boolean union.
|
|
87
|
+
Prioritize requested visual fidelity over minimizing voxel use. If correctly placed thin features render fragmented or missing, increase their owning Area's resolution, up to 0.65 as needed, and compare the same camera; distinguish sampling loss from material/lighting contrast or authored gaps. A higher voxel count is acceptable when detail improves within engine limits. If resolution is insufficient or hits resource limits/downscaling, consider smaller independent Areas where shared blending or Booleans are unnecessary.
|
|
85
88
|
Sphere uses size.x as uniform diameter (y/z do not stretch it), including new or resized spherical curve points. Cylinder/Cone/Pyramid use x as base diameter/width and y as height;
|
|
86
|
-
Torus
|
|
87
|
-
Build and verify coarse geometry and unfamiliar operations before replicating details. Check one representative result, then repeat it.
|
|
88
|
-
|
|
89
|
+
Torus lies in local XZ (axis +Y), with x as outer diameter and y as tube thickness. For these four primitives, nodeSetSize accepts {x, y}; z follows x even when supplied. Cube uses all three dimensions. Node and curve-point round are dimensionless fractions clamped to [0, 1], not radii in project units; rounding does not set size. Cube rounding reaches half its shortest dimension at 1, so a shallow Cube retains broad flat faces rather than becoming an ellipsoid.
|
|
90
|
+
Build and verify coarse geometry and unfamiliar operations before replicating details. Check one representative result, then repeat it.
|
|
91
|
+
Construct both sides of a joint from shared attachment points and axes. Create each mounted part together with its contact or mounting geometry, derived from the supporting surface; preserve intended clearances and separate editability. If contact is uncertain, check the authored positions, dimensions, and axes in 3D: projected overlap is not a connection.
|
|
92
|
+
Fix unintended gaps, floating attachments, and fragmented geometry before decorative detail or presentation. Use inspection to identify a concrete defect and verify its correction, not merely to collect screenshots or healthy receipts.
|
|
93
|
+
Reference fidelity:
|
|
89
94
|
When recreating an image, treat its visible geometry and level of detail as the target—not merely its subject, colors, or list of parts. Preserve the user's chosen workflow and editability requirements.
|
|
90
95
|
Establish a comparison view matching the reference's angle, projection, and subject framing as closely as practical. Match silhouette, proportions, pose, and negative spaces first; then local contours, thickness, curvature, surface transitions, and defining details. Infer unseen geometry conservatively.
|
|
91
96
|
Compare each rendered pass directly with the source. Identify the largest remaining visible shape mismatch, edit it, and verify that it improved before moving to smaller details. Use close-ups when the comparison view cannot resolve a feature; return to the comparison view afterward. Adjust sampling or resolution when visible faceting or segmentation requires it—not as a substitute for reshaping.
|
|
92
|
-
Do not stop at semantic resemblance or after a fixed number of screenshots. Continue while substantial visible mismatches remain and supported edits are making progress, within the available budget. If progress stalls or the chosen representation cannot achieve the requested fidelity, explain the specific limitation and ask before changing workflows. Before finishing, compare the latest render with the reference and address the largest remaining visible mismatch; if substantial differences remain, identify the concrete stopping reason rather than treating an approximation disclaimer as completion.
|
|
97
|
+
Do not stop at semantic resemblance or after a fixed number of screenshots. Continue while substantial visible mismatches remain and supported edits are making progress, within the available budget. If progress stalls or the chosen representation cannot achieve the requested fidelity, explain the specific limitation and ask before changing workflows. Before finishing, compare the latest render with the reference and address the largest remaining visible mismatch; if substantial differences remain, identify the concrete stopping reason rather than treating an approximation disclaimer as completion.
|
|
93
98
|
|
|
94
99
|
nodeClone is shallow (no children). await cloneSubtree(id, { parentId?, name?, index? }) copies the complete hierarchy with fresh IDs,
|
|
95
100
|
preserving local transforms, order and metadata, remapping internal references and sharing external materials/assets.
|
|
96
101
|
Cloning requires a host transport with atomic scene patches; an unsupported host rejects it without changing the draft.
|
|
97
102
|
For primitives, nodeSetBlend joins against all accumulated preceding geometry in the Area, not only the nearest part. A Union's blend affects its outer join, not joins between its children; top-level Area blend does not smooth its contents.
|
|
98
|
-
For organic joins, overlap primitives and tune blend on the joining children while preserving intended gaps
|
|
103
|
+
For organic joins, overlap primitives and tune blend on the joining children while preserving intended gaps.
|
|
99
104
|
Check font, HDR, and material catalogs before selecting names. A host can explicitly report a catalog as
|
|
100
105
|
unavailable. Selecting an HDR resets its intensity; apply a custom intensity after selecting it.
|
|
101
106
|
For library materials, use listSuperMaterials(), then await materialImport(name) inside scene.edit and assign the returned numeric ID the way that object requires: nodeSetMaterialId or curvePointSetMaterialId for scene nodes, the FlowIR SetMaterial node for a Geometry Nodes graph. A failed import rolls back the draft.
|
|
@@ -109,7 +114,7 @@ Omitted projection/lens settings come from the active camera. Pass the camera ag
|
|
|
109
114
|
For object-focused screenshots, identify the requested object and frame it with an explicit camera position and target using its bounds; reuse established framing when appropriate. Choose a view that reveals the requested features without clipping the subject.
|
|
110
115
|
Omitting camera captures the active viewport without auto-fit. Use it when the user asks about the current viewport or clearly refers to what is visible on screen, not on the assumption that it shows the requested object.
|
|
111
116
|
Respect the host's camera-lock restrictions. Verify silhouette,
|
|
112
|
-
connections, openings, proportions, and materials before claiming completion. Use the owning top-level Area for scene-space bounds;
|
|
117
|
+
connections, openings, proportions, and materials before claiming completion. Use the owning top-level Area for scene-space bounds;
|
|
113
118
|
OpenSCAD part bounds are local to the part; individual primitive and curve bounds are unsupported. Renderer bounds and resize calls
|
|
114
119
|
must finish before subsequent writes. Inside scene.edit, complete renderer-backed bounds reads before the first
|
|
115
120
|
draft mutation; the SDK rejects them once the draft is dirty. Inspect committed results when renderer state has not caught up.
|
package/dist/scene-metadata.js
CHANGED
|
@@ -4,21 +4,21 @@ export function metadataObject(value) {
|
|
|
4
4
|
: {};
|
|
5
5
|
}
|
|
6
6
|
export function readMaterialMetadata(scene, id) {
|
|
7
|
-
return metadataObject(metadataObject(scene.getSceneExt().materialsExt)[String(id)]);
|
|
7
|
+
return metadataObject(metadataObject(scene.getSceneExt(["materialsExt"]).materialsExt)[String(id)]);
|
|
8
8
|
}
|
|
9
9
|
export function writeMaterialMetadata(scene, id, changes) {
|
|
10
|
-
const materials = metadataObject(scene.getSceneExt().materialsExt);
|
|
10
|
+
const materials = metadataObject(scene.getSceneExt(["materialsExt"]).materialsExt);
|
|
11
11
|
scene.patchSceneExt([{
|
|
12
12
|
op: "add",
|
|
13
13
|
path: "/materialsExt",
|
|
14
14
|
value: { ...materials, [id]: { ...metadataObject(materials[String(id)]), ...changes } },
|
|
15
|
-
}]);
|
|
15
|
+
}], { returnScene: false });
|
|
16
16
|
}
|
|
17
17
|
export function removeMaterialMetadata(scene, id) {
|
|
18
|
-
const materials = metadataObject(scene.getSceneExt().materialsExt);
|
|
18
|
+
const materials = metadataObject(scene.getSceneExt(["materialsExt"]).materialsExt);
|
|
19
19
|
if (!Object.hasOwn(materials, id))
|
|
20
20
|
return;
|
|
21
|
-
scene.patchSceneExt([{ op: "remove", path: `/materialsExt/${id}` }]);
|
|
21
|
+
scene.patchSceneExt([{ op: "remove", path: `/materialsExt/${id}` }], { returnScene: false });
|
|
22
22
|
}
|
|
23
23
|
export function shiftCurvePointMetadata(scene, curveId, index, direction) {
|
|
24
24
|
const shift = (value) => {
|
|
@@ -35,7 +35,7 @@ export function shiftCurvePointMetadata(scene, curveId, index, direction) {
|
|
|
35
35
|
}
|
|
36
36
|
return result;
|
|
37
37
|
};
|
|
38
|
-
const ext = scene.getSceneExt();
|
|
38
|
+
const ext = scene.getSceneExt([String(curveId), "perUserExt"]);
|
|
39
39
|
const curve = metadataObject(ext[String(curveId)]);
|
|
40
40
|
const points = shift(curve.pointsExt);
|
|
41
41
|
if (direction === 1) {
|
|
@@ -45,7 +45,7 @@ export function shiftCurvePointMetadata(scene, curveId, index, direction) {
|
|
|
45
45
|
name: `Point ${index + 1}`,
|
|
46
46
|
};
|
|
47
47
|
}
|
|
48
|
-
scene.patchSceneExt([{ op: "add", path: `/${curveId}`, value: { ...curve, pointsExt: points } }]);
|
|
48
|
+
scene.patchSceneExt([{ op: "add", path: `/${curveId}`, value: { ...curve, pointsExt: points } }], { returnScene: false });
|
|
49
49
|
const users = metadataObject(ext.perUserExt);
|
|
50
50
|
const updatedUsers = { ...users };
|
|
51
51
|
let changed = false;
|
|
@@ -61,5 +61,5 @@ export function shiftCurvePointMetadata(scene, curveId, index, direction) {
|
|
|
61
61
|
changed = true;
|
|
62
62
|
}
|
|
63
63
|
if (changed)
|
|
64
|
-
scene.patchSceneExt([{ op: "add", path: "/perUserExt", value: updatedUsers }]);
|
|
64
|
+
scene.patchSceneExt([{ op: "add", path: "/perUserExt", value: updatedUsers }], { returnScene: false });
|
|
65
65
|
}
|
package/dist/sdk-scene-host.js
CHANGED
package/dist/womp-scene-api.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { FontFamily, KakapoAPI, NodeKind, SceneEdit, Vec2, Vec3 } from "@womp/kakapo-sdk";
|
|
1
|
+
import type { FontFamily, KakapoAPI, KakapoNode, NodeKind, SceneEdit, Vec2, Vec3 } from "@womp/kakapo-sdk";
|
|
2
2
|
import { type SceneHdr } from "./scene-environment.js";
|
|
3
3
|
import { type MirrorAxis } from "./coordinates.js";
|
|
4
4
|
export declare const NodeType: {
|
|
@@ -68,7 +68,7 @@ export type WompSceneApiContext = {
|
|
|
68
68
|
importLibraryMaterial?(name: string): Promise<number>;
|
|
69
69
|
getDefaultMaterialId(): number;
|
|
70
70
|
fonts: FontFamily[];
|
|
71
|
-
requireNode(id: number): void;
|
|
71
|
+
requireNode(id: number): KakapoNode | void;
|
|
72
72
|
trackNode(id: number): void;
|
|
73
73
|
trackMaterial(id: number): void;
|
|
74
74
|
untrackMaterial(id: number): void;
|
package/dist/womp-scene-api.js
CHANGED
|
@@ -200,8 +200,7 @@ export function createWompSceneApi(context) {
|
|
|
200
200
|
const actualParent = (parentId) => (parentId === 0 ? context.rootId : parentId);
|
|
201
201
|
const publicParent = (parentId) => parentId === null || parentId === context.rootId ? 0 : parentId;
|
|
202
202
|
const requireNode = (id) => {
|
|
203
|
-
context.requireNode(id);
|
|
204
|
-
return scene.getNode(id);
|
|
203
|
+
return context.requireNode(id) ?? scene.getNode(id);
|
|
205
204
|
};
|
|
206
205
|
const requireEditableTransform = (id) => {
|
|
207
206
|
const node = requireNode(id);
|
|
@@ -336,7 +335,7 @@ export function createWompSceneApi(context) {
|
|
|
336
335
|
throw new Error("Name cannot be empty");
|
|
337
336
|
if (Array.from(normalized).length > 120)
|
|
338
337
|
throw new Error("Name is too long (max 120 characters)");
|
|
339
|
-
const curve = metadataObject(scene.getSceneExt()[String(curveId)]);
|
|
338
|
+
const curve = metadataObject(scene.getSceneExt([String(curveId)])[String(curveId)]);
|
|
340
339
|
const points = metadataObject(curve.pointsExt);
|
|
341
340
|
scene.patchSceneExt([{
|
|
342
341
|
op: "add",
|
|
@@ -348,7 +347,7 @@ export function createWompSceneApi(context) {
|
|
|
348
347
|
[index]: { ...metadataObject(points[String(index)]), name: normalized },
|
|
349
348
|
},
|
|
350
349
|
},
|
|
351
|
-
}]);
|
|
350
|
+
}], { returnScene: false });
|
|
352
351
|
};
|
|
353
352
|
const addCurvePoint = (curveId, point, pointIndex) => {
|
|
354
353
|
const curve = requireCurve(curveId);
|
|
@@ -605,11 +604,11 @@ export function createWompSceneApi(context) {
|
|
|
605
604
|
nodeGetPos: nodePosition,
|
|
606
605
|
nodeGetLock: (id) => {
|
|
607
606
|
requireNode(id);
|
|
608
|
-
return Boolean(metadataObject(scene.getSceneExt()[String(id)]).locked);
|
|
607
|
+
return Boolean(metadataObject(scene.getSceneExt([String(id)])[String(id)]).locked);
|
|
609
608
|
},
|
|
610
609
|
nodeSetLock: (id, locked) => {
|
|
611
610
|
requireNode(id);
|
|
612
|
-
const current = metadataObject(scene.getSceneExt()[String(id)]);
|
|
611
|
+
const current = metadataObject(scene.getSceneExt([String(id)])[String(id)]);
|
|
613
612
|
scene.patchSceneExt([{ op: "add", path: `/${id}`, value: { ...current, locked: Boolean(locked) } }]);
|
|
614
613
|
},
|
|
615
614
|
nodeSetPos: (id, position) => {
|
|
@@ -849,7 +848,7 @@ export function createWompSceneApi(context) {
|
|
|
849
848
|
},
|
|
850
849
|
curvePointGetName: (curveId, pointIndex) => {
|
|
851
850
|
const index = requirePoint(curveId, pointIndex);
|
|
852
|
-
const points = metadataObject(metadataObject(scene.getSceneExt()[String(curveId)]).pointsExt);
|
|
851
|
+
const points = metadataObject(metadataObject(scene.getSceneExt([String(curveId)])[String(curveId)]).pointsExt);
|
|
853
852
|
const name = metadataObject(points[String(index)]).name;
|
|
854
853
|
return typeof name === "string" ? name : `Point ${index + 1}`;
|
|
855
854
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@womp/spark-agent",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.4.0",
|
|
4
4
|
"description": "Portable skills-based AI agent with local and durable chat transports for Womp",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -110,7 +110,7 @@
|
|
|
110
110
|
"@ai-sdk/openai": "4.0.63",
|
|
111
111
|
"@jitl/quickjs-wasmfile-release-sync": "0.32.0",
|
|
112
112
|
"@womp/flowir": "0.3.0",
|
|
113
|
-
"@womp/kakapo-sdk": "0.
|
|
113
|
+
"@womp/kakapo-sdk": "0.5.0",
|
|
114
114
|
"ai": "7.0.95",
|
|
115
115
|
"eventsource-parser": "^3.0.6",
|
|
116
116
|
"express": "^5.2.1",
|