@energy8platform/golem 0.6.0 → 0.8.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 +14 -0
- package/dist/editor.css +3 -4
- package/dist/editor.js +202 -101
- package/dist/lib/cli.js +225 -118
- package/dist/lib/cli.js.map +4 -4
- package/dist/lib/e8/agent.d.ts +35 -0
- package/dist/lib/e8/host.d.ts +22 -0
- package/dist/lib/e8/node.d.ts +66 -0
- package/dist/lib/e8/runtime.d.ts +10 -0
- package/dist/lib/e8/schema.d.ts +3 -0
- package/dist/lib/e8/types.d.ts +80 -0
- package/dist/lib/e8-agent.js +6865 -0
- package/dist/lib/e8-agent.js.map +7 -0
- package/dist/lib/e8-client.js +116 -0
- package/dist/lib/e8-host.js +7005 -0
- package/dist/lib/e8-host.js.map +7 -0
- package/dist/lib/e8-runtime.js +2079 -0
- package/dist/lib/e8-runtime.js.map +7 -0
- package/dist/lib/e8-schema.js +7 -0
- package/dist/lib/e8-schema.js.map +7 -0
- package/dist/lib/editor/api.d.ts +1 -0
- package/dist/lib/editor/embed.d.ts +9 -0
- package/dist/lib/editor/server.d.ts +23 -1
- package/dist/lib/editor/store.d.ts +34 -32
- package/dist/lib/editor/timeline.d.ts +15 -0
- package/dist/lib/editor-entry.d.ts +1 -1
- package/dist/lib/editor-entry.js +226 -118
- package/dist/lib/editor-entry.js.map +4 -4
- package/dist/lib/harness.js +54 -1
- package/dist/lib/interactive-editor.js.map +1 -1
- package/dist/lib/rig-check.d.ts +11 -0
- package/dist/lib/rig-control-qa.d.ts +8 -8
- package/dist/lib/rig-format.d.ts +184 -184
- package/dist/lib/rig-import-layers.d.ts +2 -0
- package/dist/lib/rig-symbol.d.ts +5 -2
- package/dist/lib/rig-tools.d.ts +2 -1
- package/dist/lib/rig-version.d.ts +12 -0
- package/dist/lib/runtime.js +60 -3
- package/dist/lib/runtime.js.map +3 -3
- package/dist/lib/tool-schema.d.ts +3 -0
- package/dist/lib/tools.d.ts +2 -0
- package/dist/lib/tools.js +179 -58
- package/dist/lib/tools.js.map +4 -4
- package/editor.html +2 -2
- package/package.json +38 -3
- package/skills/e8-golem/SKILL.md +71 -0
- package/skills/golem-symbol-animation/SKILL.md +87 -0
- package/skills/golem-symbol-animation/agents/openai.yaml +4 -0
- package/skills/golem-symbol-animation/references/facial-controls.md +48 -0
- package/skills/golem-symbol-animation/references/game-engine-integration.md +133 -0
- package/skills/golem-symbol-animation/references/golem-authoring.md +138 -0
- package/skills/golem-symbol-animation/references/interactive-editor.md +17 -0
- package/skills/golem-symbol-animation/references/motion-craft.md +116 -0
- package/skills/golem-symbol-animation/references/packed-delivery.md +88 -0
- package/skills/golem-symbol-animation/references/quantitative-qa.md +109 -0
- package/skills/golem-symbol-animation/references/spine-rive-study.md +87 -0
- package/skills/golem-symbol-animation/scripts/atlas_parts.py +87 -0
- package/skills/golem-symbol-animation/scripts/check_package.py +71 -0
- package/skills/golem-symbol-animation/scripts/image_gates.py +143 -0
- package/skills/golem-symbol-cutting/SKILL.md +70 -0
- package/skills/golem-symbol-cutting/agents/openai.yaml +4 -0
- package/skills/golem-symbol-cutting/assets/h1/h1.atlas.png +0 -0
- package/skills/golem-symbol-cutting/assets/h1/h1.png +0 -0
- package/skills/golem-symbol-cutting/references/cutting-workflow.md +92 -0
- package/skills/golem-symbol-cutting/references/facial-layers.md +44 -0
- package/skills/golem-symbol-cutting/references/generation-workflow.md +109 -0
- package/skills/golem-symbol-cutting/references/golem-handoff.md +62 -0
- package/skills/golem-symbol-cutting/references/h1-example.md +46 -0
- package/skills/golem-symbol-cutting/references/hybrid-workflow.md +119 -0
- package/skills/golem-symbol-cutting/references/registration-and-motion.md +89 -0
- package/skills/golem-symbol-cutting/references/spine-rive-construction.md +73 -0
- package/skills/golem-symbol-cutting/scripts/atlas_parts.py +87 -0
- package/skills/golem-symbol-cutting/scripts/hybrid_parts.py +279 -0
package/dist/lib/tools.d.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
/** `@energy8platform/golem/tools` — the tool registry (node): MCP, CLI and the editor call the same list. */
|
|
2
2
|
export { tools, callTool, closeTools, type ToolDef, type ToolResult } from "./rig-api";
|
|
3
|
+
export { rigVersion, callToolVersioned } from "./rig-version";
|
|
4
|
+
export { jsonSchemaOf } from "./tool-schema";
|
package/dist/lib/tools.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/rig-api.ts
|
|
2
2
|
import { z as z3 } from "zod";
|
|
3
3
|
import { readFile as readFile9, writeFile as writeFile7, stat as stat2, mkdir as mkdir6, readdir as readdir4 } from "node:fs/promises";
|
|
4
|
-
import { dirname as dirname8, join as join9, relative as
|
|
4
|
+
import { dirname as dirname8, join as join9, relative as relative3, isAbsolute as isAbsolute2 } from "node:path";
|
|
5
5
|
|
|
6
6
|
// src/rig-io.ts
|
|
7
7
|
import { mkdir, rename, rm, writeFile } from "node:fs/promises";
|
|
@@ -24,8 +24,10 @@ var saveJson = (path, value) => saveBytes(path, JSON.stringify(value, null, 2));
|
|
|
24
24
|
// src/rig-queue.ts
|
|
25
25
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
26
26
|
import { resolve } from "node:path";
|
|
27
|
-
var pending
|
|
28
|
-
|
|
27
|
+
var { pending, active } = globalThis[Symbol.for("golem.rigQueue")] ??= {
|
|
28
|
+
pending: /* @__PURE__ */ new Map(),
|
|
29
|
+
active: new AsyncLocalStorage()
|
|
30
|
+
};
|
|
29
31
|
async function withRigQueue(path, op) {
|
|
30
32
|
const key = resolve(path);
|
|
31
33
|
const held = active.getStore();
|
|
@@ -291,7 +293,7 @@ var Key = z.object({
|
|
|
291
293
|
/** Optional independent easing for numeric-array components (for example Spine RGBA curves). */
|
|
292
294
|
componentEase: z.array(Ease).min(1).optional()
|
|
293
295
|
});
|
|
294
|
-
var Interpolation = { interpolation: z.enum(["segment", "pchip"]).optional() };
|
|
296
|
+
var Interpolation = { interpolation: z.enum(["segment", "pchip", "spline"]).optional() };
|
|
295
297
|
var Track = z.discriminatedUnion("target", [
|
|
296
298
|
z.object({ target: z.literal("control"), id: Id, prop: z.literal("value"), ...Interpolation, keys: z.array(Key).min(1) }),
|
|
297
299
|
z.object({ target: z.literal("bone"), id: Id, prop: BoneProp, ...Interpolation, keys: z.array(Key).min(1) }),
|
|
@@ -725,6 +727,57 @@ function smoothValue(track, i, t, component, loop) {
|
|
|
725
727
|
const u = (t - k[i].t) / h(i), u2 = u * u, u3 = u2 * u;
|
|
726
728
|
return (2 * u3 - 3 * u2 + 1) * v(i) + (u3 - 2 * u2 + u) * h(i) * tangent(i) + (-2 * u3 + 3 * u2) * v(i + 1) + (u3 - u2) * h(i) * tangent(i + 1);
|
|
727
729
|
}
|
|
730
|
+
function tridiagonal(a, b, c, r) {
|
|
731
|
+
const n = b.length, cp = [], x = [];
|
|
732
|
+
let beta = b[0];
|
|
733
|
+
x[0] = r[0] / beta;
|
|
734
|
+
for (let i = 1; i < n; i++) {
|
|
735
|
+
cp[i] = c[i - 1] / beta;
|
|
736
|
+
beta = b[i] - a[i] * cp[i];
|
|
737
|
+
x[i] = (r[i] - a[i] * x[i - 1]) / beta;
|
|
738
|
+
}
|
|
739
|
+
for (let i = n - 2; i >= 0; i--) x[i] -= cp[i + 1] * x[i + 1];
|
|
740
|
+
return x;
|
|
741
|
+
}
|
|
742
|
+
function splineMoments(t, v, periodic) {
|
|
743
|
+
const n = t.length, h = (j2) => t[j2 + 1] - t[j2], d = (j2) => (v[j2 + 1] - v[j2]) / h(j2);
|
|
744
|
+
if (!periodic) {
|
|
745
|
+
const a2 = [], b2 = [], c2 = [], r2 = [];
|
|
746
|
+
for (let i = 0; i < n; i++) {
|
|
747
|
+
const hp = i > 0 ? h(i - 1) : 0, hn = i < n - 1 ? h(i) : 0;
|
|
748
|
+
a2.push(hp);
|
|
749
|
+
b2.push(2 * (hp + hn));
|
|
750
|
+
c2.push(hn);
|
|
751
|
+
r2.push(6 * ((i < n - 1 ? d(i) : 0) - (i > 0 ? d(i - 1) : 0)));
|
|
752
|
+
}
|
|
753
|
+
return tridiagonal(a2, b2, c2, r2);
|
|
754
|
+
}
|
|
755
|
+
const m = n - 1, a = [], b = [], c = [], r = [];
|
|
756
|
+
for (let i = 0; i < m; i++) {
|
|
757
|
+
const p = (i + m - 1) % m;
|
|
758
|
+
a.push(h(p));
|
|
759
|
+
b.push(2 * (h(p) + h(i)));
|
|
760
|
+
c.push(h(i));
|
|
761
|
+
r.push(6 * (d(i) - d(p)));
|
|
762
|
+
}
|
|
763
|
+
const top = a[0], bottom = c[m - 1], gamma = -b[0];
|
|
764
|
+
const bb = [...b];
|
|
765
|
+
bb[0] -= gamma;
|
|
766
|
+
bb[m - 1] -= bottom * top / gamma;
|
|
767
|
+
const x = tridiagonal(a, bb, c, r), u = new Array(m).fill(0);
|
|
768
|
+
u[0] = gamma;
|
|
769
|
+
u[m - 1] = bottom;
|
|
770
|
+
const z4 = tridiagonal(a, bb, c, u);
|
|
771
|
+
const f = (x[0] + top * x[m - 1] / gamma) / (1 + z4[0] + top * z4[m - 1] / gamma);
|
|
772
|
+
const M = x.map((xi, i) => xi - f * z4[i]);
|
|
773
|
+
return [...M, M[0]];
|
|
774
|
+
}
|
|
775
|
+
function splineValue(track, i, t, component, loop) {
|
|
776
|
+
const k = track.keys, ts = k.map((x) => x.t), vs = k.map((x) => component === void 0 ? x.v : x.v[component]);
|
|
777
|
+
const M = splineMoments(ts, vs, loop && k.length > 3 && vs[0] === vs[k.length - 1]);
|
|
778
|
+
const H = ts[i + 1] - ts[i], A = (ts[i + 1] - t) / H, B = (t - ts[i]) / H;
|
|
779
|
+
return A * vs[i] + B * vs[i + 1] + ((A ** 3 - A) * M[i] + (B ** 3 - B) * M[i + 1]) * H * H / 6;
|
|
780
|
+
}
|
|
728
781
|
function sample(track, t, loop = false) {
|
|
729
782
|
const keys = track.keys;
|
|
730
783
|
if (t <= keys[0].t) return keys[0].v;
|
|
@@ -736,11 +789,13 @@ function sample(track, t, loop = false) {
|
|
|
736
789
|
if (a.ease === "step") return a.v;
|
|
737
790
|
if (typeof a.v === "number" && typeof b.v === "number") {
|
|
738
791
|
if (track.interpolation === "pchip") return smoothValue(track, i, t, void 0, loop);
|
|
792
|
+
if (track.interpolation === "spline") return splineValue(track, i, t, void 0, loop);
|
|
739
793
|
const u = ease(a.ease)((t - a.t) / (b.t - a.t));
|
|
740
794
|
return a.v + (b.v - a.v) * u;
|
|
741
795
|
}
|
|
742
796
|
if (Array.isArray(a.v) && Array.isArray(b.v) && typeof a.v[0] === "number") {
|
|
743
797
|
if (track.interpolation === "pchip") return a.v.map((_, j2) => smoothValue(track, i, t, j2, loop));
|
|
798
|
+
if (track.interpolation === "spline") return a.v.map((_, j2) => splineValue(track, i, t, j2, loop));
|
|
744
799
|
const phase = (t - a.t) / (b.t - a.t), av = a.v, bv = b.v;
|
|
745
800
|
return av.map((v, k) => v + ((bv[k] ?? v) - v) * ease(a.componentEase?.[k] ?? a.ease)(phase));
|
|
746
801
|
}
|
|
@@ -2001,8 +2056,9 @@ function createDoc(name, width, height, notes) {
|
|
|
2001
2056
|
function createSymbol(name, asset, margin = 0.15, notes) {
|
|
2002
2057
|
const mx = Math.ceil(asset.width * margin), my = Math.ceil(asset.height * margin);
|
|
2003
2058
|
const width = asset.width + 2 * mx, height = asset.height + 2 * my;
|
|
2004
|
-
const
|
|
2005
|
-
const
|
|
2059
|
+
const stem = asset.src.replace(/^.*\//, "").replace(/\.[^.]+$/, "").toLowerCase().replace(/[^a-z0-9_]/g, "_");
|
|
2060
|
+
const fromFile = stem.replace(/^[^a-z]+/, "") || (stem ? `symbol_${stem}` : "");
|
|
2061
|
+
const id = asset.id ?? (ID_RE.test(fromFile) ? fromFile : ID_RE.test(name) ? name : "symbol");
|
|
2006
2062
|
let doc = createDoc(name, width, height, notes);
|
|
2007
2063
|
doc = { ...doc, bones: [{ ...doc.bones[0], transform: { ...doc.bones[0].transform, x: width / 2, y: height - my } }] };
|
|
2008
2064
|
doc = { ...doc, assets: [RigSchema.shape.assets.element.parse({ id, src: asset.src, width: asset.width, height: asset.height })] };
|
|
@@ -2471,7 +2527,8 @@ function adjustTrack(doc, animId, track, adj) {
|
|
|
2471
2527
|
return { ...k, t: r42(adj.timeScale ? k.t * adj.timeScale : k.t), v: r42(v) };
|
|
2472
2528
|
});
|
|
2473
2529
|
const duration = Math.max(anim.duration, keys[keys.length - 1].t);
|
|
2474
|
-
const
|
|
2530
|
+
const interpolation = track.interpolation ?? tr.interpolation;
|
|
2531
|
+
const next = { ...anim, duration, tracks: anim.tracks.map((t) => same(t) ? { ...t, keys, ...interpolation && { interpolation } } : t), preset: void 0 };
|
|
2475
2532
|
return { ...doc, animations: doc.animations.map((a) => a.id === animId ? next : a) };
|
|
2476
2533
|
}
|
|
2477
2534
|
function removeAnimation(doc, id) {
|
|
@@ -2758,7 +2815,7 @@ function setGoal(doc, bone, x, y, opts) {
|
|
|
2758
2815
|
|
|
2759
2816
|
// src/rig-import-layers.ts
|
|
2760
2817
|
import { readdir, readFile } from "node:fs/promises";
|
|
2761
|
-
import { join as join2, basename as basename2 } from "node:path";
|
|
2818
|
+
import { join as join2, basename as basename2, isAbsolute, relative, sep } from "node:path";
|
|
2762
2819
|
var DEFAULT_PARENT = {
|
|
2763
2820
|
head: "neck",
|
|
2764
2821
|
neck: "torso",
|
|
@@ -2784,6 +2841,10 @@ function pngSize(buf) {
|
|
|
2784
2841
|
if (buf.readUInt32BE(12) !== 1229472850) throw new Error("not a PNG (IHDR missing)");
|
|
2785
2842
|
return [buf.readUInt32BE(16), buf.readUInt32BE(20)];
|
|
2786
2843
|
}
|
|
2844
|
+
function outsideDir(dir, file) {
|
|
2845
|
+
const r = relative(dir, join2(dir, file));
|
|
2846
|
+
return isAbsolute(file) || r === ".." || r.startsWith(".." + sep);
|
|
2847
|
+
}
|
|
2787
2848
|
async function importLayers(doc, dir, relPrefix = "layers") {
|
|
2788
2849
|
let specs;
|
|
2789
2850
|
try {
|
|
@@ -2796,6 +2857,7 @@ async function importLayers(doc, dir, relPrefix = "layers") {
|
|
|
2796
2857
|
let next = doc;
|
|
2797
2858
|
const parsed = [];
|
|
2798
2859
|
for (const s of specs) {
|
|
2860
|
+
if (outsideDir(dir, s.file)) throw new Error(`layers.json file "${s.file}" is outside the layers folder (${dir})`);
|
|
2799
2861
|
const buf = await readFile(join2(dir, s.file));
|
|
2800
2862
|
const [w, h] = pngSize(buf);
|
|
2801
2863
|
const m = basename2(s.file, ".png").match(/^(?:(\d+)_)?(.+)$/);
|
|
@@ -2883,19 +2945,20 @@ var requireSlot = (doc, id) => {
|
|
|
2883
2945
|
if (!s) throw new Error(`unknown slot "${id}"`);
|
|
2884
2946
|
return s;
|
|
2885
2947
|
};
|
|
2886
|
-
function sampled(duration, n, f
|
|
2948
|
+
function sampled(duration, n, f) {
|
|
2887
2949
|
const keys = [];
|
|
2888
2950
|
for (let i = 0; i <= n; i++) {
|
|
2889
2951
|
const t = +(duration * i / n).toFixed(4);
|
|
2890
|
-
keys.push({ t, v: +f(t).toFixed(4) + 0, ease:
|
|
2952
|
+
keys.push({ t, v: +f(t).toFixed(4) + 0, ease: "linear" });
|
|
2891
2953
|
}
|
|
2892
2954
|
return keys;
|
|
2893
2955
|
}
|
|
2894
|
-
|
|
2895
|
-
|
|
2956
|
+
var smooth = "spline";
|
|
2957
|
+
function boneTrack(bone, prop, keys, interpolation) {
|
|
2958
|
+
return { target: "bone", id: bone.id, prop, keys, ...interpolation && { interpolation } };
|
|
2896
2959
|
}
|
|
2897
|
-
function deformTrack(slot, prop, keys) {
|
|
2898
|
-
return slot.attachment ? { target: "deform", id: slot.attachment, prop, keys } : void 0;
|
|
2960
|
+
function deformTrack(slot, prop, keys, interpolation) {
|
|
2961
|
+
return slot.attachment ? { target: "deform", id: slot.attachment, prop, keys, ...interpolation && { interpolation } } : void 0;
|
|
2899
2962
|
}
|
|
2900
2963
|
var pushTrack = (tracks, t) => {
|
|
2901
2964
|
if (t) tracks.push(t);
|
|
@@ -2919,18 +2982,18 @@ var idleBreathing = {
|
|
|
2919
2982
|
const armsR = byRole(doc, "arm_r", "arm_upper_r");
|
|
2920
2983
|
const chest = slotOfBone(doc, torso);
|
|
2921
2984
|
if (chest?.attachment) {
|
|
2922
|
-
pushTrack(tracks, deformTrack(chest, "bulge", sampled(T2, 8, (t) => p.amplitude * Math.sin(w * t),
|
|
2985
|
+
pushTrack(tracks, deformTrack(chest, "bulge", sampled(T2, 8, (t) => p.amplitude * Math.sin(w * t)), smooth));
|
|
2923
2986
|
} else {
|
|
2924
2987
|
const r = torso.transform;
|
|
2925
|
-
tracks.push(boneTrack(torso, "scaleY", sampled(T2, 8, (t) => r.scaleY + p.amplitude * Math.sin(w * t),
|
|
2926
|
-
tracks.push(boneTrack(torso, "scaleX", sampled(T2, 8, (t) => r.scaleX - p.amplitude * 0.4 * Math.sin(w * t),
|
|
2988
|
+
tracks.push(boneTrack(torso, "scaleY", sampled(T2, 8, (t) => r.scaleY + p.amplitude * Math.sin(w * t)), smooth));
|
|
2989
|
+
tracks.push(boneTrack(torso, "scaleX", sampled(T2, 8, (t) => r.scaleX - p.amplitude * 0.4 * Math.sin(w * t)), smooth));
|
|
2927
2990
|
}
|
|
2928
2991
|
for (const h of heads)
|
|
2929
|
-
tracks.push(boneTrack(h, "y", sampled(T2, 8, (t) => h.transform.y - p.headBob * Math.sin(w * t + 0.4),
|
|
2992
|
+
tracks.push(boneTrack(h, "y", sampled(T2, 8, (t) => h.transform.y - p.headBob * Math.sin(w * t + 0.4)), smooth));
|
|
2930
2993
|
for (const a of armsL)
|
|
2931
|
-
tracks.push(boneTrack(a, "rotation", sampled(T2, 8, (t) => a.transform.rotation + p.armSway * Math.sin(w * t + 0.8),
|
|
2994
|
+
tracks.push(boneTrack(a, "rotation", sampled(T2, 8, (t) => a.transform.rotation + p.armSway * Math.sin(w * t + 0.8)), smooth));
|
|
2932
2995
|
for (const a of armsR)
|
|
2933
|
-
tracks.push(boneTrack(a, "rotation", sampled(T2, 8, (t) => a.transform.rotation - p.armSway * Math.sin(w * t + 0.8),
|
|
2996
|
+
tracks.push(boneTrack(a, "rotation", sampled(T2, 8, (t) => a.transform.rotation - p.armSway * Math.sin(w * t + 0.8)), smooth));
|
|
2934
2997
|
return finish(this.name, p.id, T2, true, tracks, p);
|
|
2935
2998
|
}
|
|
2936
2999
|
};
|
|
@@ -2939,22 +3002,20 @@ var winBounce = {
|
|
|
2939
3002
|
defaults: { id: "win", duration: 1.2, height: 40, bounces: 2, squash: 0.15 },
|
|
2940
3003
|
build(doc, p) {
|
|
2941
3004
|
const b = root(doc), r = b.transform, tracks = [];
|
|
2942
|
-
const yK = [[0, r.y,
|
|
2943
|
-
const sxK = [[0, r.scaleX, "ease_out"]];
|
|
2944
|
-
const syK = [[0, r.scaleY, "ease_out"]];
|
|
3005
|
+
const yK = [[0, r.y]], sxK = [[0, r.scaleX]], syK = [[0, r.scaleY]];
|
|
2945
3006
|
const per = p.duration / p.bounces;
|
|
2946
3007
|
for (let i = 0; i < p.bounces; i++) {
|
|
2947
3008
|
const t0 = i * per, h = p.height * 0.55 ** i, s = p.squash * 0.7 ** i;
|
|
2948
|
-
sxK.push([t0 + per * 0.08, r.scaleX * (1 + s)
|
|
2949
|
-
syK.push([t0 + per * 0.08, r.scaleY * (1 - s)
|
|
2950
|
-
yK.push([t0 + per * 0.08, r.y
|
|
3009
|
+
sxK.push([t0 + per * 0.08, r.scaleX * (1 + s)], [t0 + per * 0.5, r.scaleX * (1 - s * 0.6)], [t0 + per * 0.95, r.scaleX * (1 + s)]);
|
|
3010
|
+
syK.push([t0 + per * 0.08, r.scaleY * (1 - s)], [t0 + per * 0.5, r.scaleY * (1 + s * 0.6)], [t0 + per * 0.95, r.scaleY * (1 - s)]);
|
|
3011
|
+
yK.push([t0 + per * 0.08, r.y], [t0 + per * 0.5, r.y - h], [t0 + per * 0.95, r.y]);
|
|
2951
3012
|
}
|
|
2952
3013
|
yK.push([p.duration, r.y]);
|
|
2953
3014
|
sxK.push([p.duration, r.scaleX]);
|
|
2954
3015
|
syK.push([p.duration, r.scaleY]);
|
|
2955
|
-
tracks.push(boneTrack(b, "y", K(...yK)), boneTrack(b, "scaleX", K(...sxK)), boneTrack(b, "scaleY", K(...syK)));
|
|
3016
|
+
tracks.push(boneTrack(b, "y", K(...yK), "pchip"), boneTrack(b, "scaleX", K(...sxK), smooth), boneTrack(b, "scaleY", K(...syK), smooth));
|
|
2956
3017
|
for (const h of byRole(doc, "head"))
|
|
2957
|
-
tracks.push(boneTrack(h, "rotation", K([0, h.transform.rotation], [p.duration * 0.25, h.transform.rotation - 6
|
|
3018
|
+
tracks.push(boneTrack(h, "rotation", K([0, h.transform.rotation], [p.duration * 0.25, h.transform.rotation - 6], [p.duration * 0.6, h.transform.rotation + 4], [p.duration, h.transform.rotation]), smooth));
|
|
2958
3019
|
const anim = finish(this.name, p.id, p.duration, false, tracks, p);
|
|
2959
3020
|
anim.events.push({ t: 0, name: "win_start" }, { t: per * 0.95, name: "land" });
|
|
2960
3021
|
return anim;
|
|
@@ -2967,8 +3028,8 @@ var anticipationShake = {
|
|
|
2967
3028
|
const b = root(doc), r = b.transform, tracks = [];
|
|
2968
3029
|
const n = Math.ceil(p.duration * p.frequency * 4);
|
|
2969
3030
|
const env = (t) => p.grow ? t / p.duration : 1;
|
|
2970
|
-
tracks.push(boneTrack(b, "x", sampled(p.duration, n, (t) => r.x + p.amplitude * env(t) * Math.sin(2 * Math.PI * p.frequency * t),
|
|
2971
|
-
tracks.push(boneTrack(b, "rotation", sampled(p.duration, n, (t) => r.rotation + 0.6 * p.amplitude * env(t) * Math.sin(2 * Math.PI * p.frequency * t + 1.2),
|
|
3031
|
+
tracks.push(boneTrack(b, "x", sampled(p.duration, n, (t) => r.x + p.amplitude * env(t) * Math.sin(2 * Math.PI * p.frequency * t)), smooth));
|
|
3032
|
+
tracks.push(boneTrack(b, "rotation", sampled(p.duration, n, (t) => r.rotation + 0.6 * p.amplitude * env(t) * Math.sin(2 * Math.PI * p.frequency * t + 1.2)), smooth));
|
|
2972
3033
|
tracks.push(boneTrack(b, "scaleX", K([0, r.scaleX, "ease_in"], [p.duration, r.scaleX * p.scaleUp])));
|
|
2973
3034
|
tracks.push(boneTrack(b, "scaleY", K([0, r.scaleY, "ease_in"], [p.duration, r.scaleY * p.scaleUp])));
|
|
2974
3035
|
return finish(this.name, p.id, p.duration, false, tracks, p);
|
|
@@ -2993,6 +3054,7 @@ var mouthTalk = {
|
|
|
2993
3054
|
if (!p.frames.length) throw new Error("mouth_talk: frames must not be empty");
|
|
2994
3055
|
const n = Math.max(1, Math.round(p.duration * p.rate));
|
|
2995
3056
|
const keys = S(...Array.from({ length: n }, (_, i) => [+(i / p.rate).toFixed(4), p.frames[i % p.frames.length]]));
|
|
3057
|
+
if (keys.at(-1).t < p.duration && keys.at(-1).v !== keys[0].v) keys.push(...S([p.duration, keys[0].v]));
|
|
2996
3058
|
return finish(this.name, p.id, p.duration, true, [slotTrack(slot, "attachment", keys)], p);
|
|
2997
3059
|
}
|
|
2998
3060
|
};
|
|
@@ -3010,10 +3072,10 @@ var symbolIdle = {
|
|
|
3010
3072
|
build(doc, p) {
|
|
3011
3073
|
const b = root(doc), r = b.transform, T2 = p.period, w = 2 * Math.PI / T2, tracks = [];
|
|
3012
3074
|
const rise = (t) => 0.5 - 0.5 * Math.cos(w * t);
|
|
3013
|
-
tracks.push(boneTrack(b, "y", sampled(T2, 8, (t) => r.y - p.float * rise(t),
|
|
3014
|
-
if (p.tilt) tracks.push(boneTrack(b, "rotation", sampled(T2, 8, (t) => r.rotation + p.tilt * Math.sin(w * t),
|
|
3075
|
+
tracks.push(boneTrack(b, "y", sampled(T2, 8, (t) => r.y - p.float * rise(t)), smooth));
|
|
3076
|
+
if (p.tilt) tracks.push(boneTrack(b, "rotation", sampled(T2, 8, (t) => r.rotation + p.tilt * Math.sin(w * t)), smooth));
|
|
3015
3077
|
if (p.pulse) for (const s of doc.slots.filter((s2) => s2.bone === b.id && s2.attachment))
|
|
3016
|
-
pushTrack(tracks, deformTrack(s, "bulge", sampled(T2, 8, (t) => p.pulse * rise(t),
|
|
3078
|
+
pushTrack(tracks, deformTrack(s, "bulge", sampled(T2, 8, (t) => p.pulse * rise(t)), smooth));
|
|
3017
3079
|
return finish(this.name, p.id, T2, true, tracks, p);
|
|
3018
3080
|
}
|
|
3019
3081
|
};
|
|
@@ -3023,12 +3085,12 @@ var symbolWin = {
|
|
|
3023
3085
|
build(doc, p) {
|
|
3024
3086
|
const b = root(doc), r = b.transform, d = p.duration, tracks = [];
|
|
3025
3087
|
for (const [prop, rest] of [["scaleX", r.scaleX], ["scaleY", r.scaleY]])
|
|
3026
|
-
tracks.push(boneTrack(b, prop, K([0, rest
|
|
3088
|
+
tracks.push(boneTrack(b, prop, K([0, rest], [d * 0.2, rest * (1 + p.pop)], [d * 0.5, rest * (1 - p.pop * 0.3)], [d, rest]), smooth));
|
|
3027
3089
|
if (p.wobble) {
|
|
3028
3090
|
const n = Math.max(8, p.wobbles * 4);
|
|
3029
|
-
const keys = sampled(d, n, (t) => p.wobble * Math.exp(-3 * t / d) * Math.sin(2 * Math.PI * p.wobbles * t / d)
|
|
3091
|
+
const keys = sampled(d, n, (t) => p.wobble * Math.exp(-3 * t / d) * Math.sin(2 * Math.PI * p.wobbles * t / d));
|
|
3030
3092
|
keys[keys.length - 1].v = 0;
|
|
3031
|
-
for (const s of doc.slots.filter((s2) => s2.bone === b.id && s2.attachment)) pushTrack(tracks, deformTrack(s, "sway", keys));
|
|
3093
|
+
for (const s of doc.slots.filter((s2) => s2.bone === b.id && s2.attachment)) pushTrack(tracks, deformTrack(s, "sway", keys, smooth));
|
|
3032
3094
|
}
|
|
3033
3095
|
const anim = finish(this.name, p.id, d, false, tracks, p);
|
|
3034
3096
|
anim.events.push({ t: 0, name: "win_start" });
|
|
@@ -3042,11 +3104,11 @@ var weightShift = {
|
|
|
3042
3104
|
const T2 = p.period, w = 2 * Math.PI / T2, N = 16, tracks = [];
|
|
3043
3105
|
const hips = byRole(doc, "hips")[0] ?? root(doc), hr = hips.transform;
|
|
3044
3106
|
const s = (t) => Math.sin(w * t);
|
|
3045
|
-
tracks.push(boneTrack(hips, "x", sampled(T2, N, (t) => hr.x + p.shift * s(t))));
|
|
3046
|
-
if (p.dip) tracks.push(boneTrack(hips, "y", sampled(T2, N, (t) => hr.y + p.dip * s(t) ** 2)));
|
|
3107
|
+
tracks.push(boneTrack(hips, "x", sampled(T2, N, (t) => hr.x + p.shift * s(t)), smooth));
|
|
3108
|
+
if (p.dip) tracks.push(boneTrack(hips, "y", sampled(T2, N, (t) => hr.y + p.dip * s(t) ** 2), smooth));
|
|
3047
3109
|
const torso = byRole(doc, "torso", "body")[0];
|
|
3048
|
-
if (torso && torso !== hips) tracks.push(boneTrack(torso, "rotation", sampled(T2, N, (t) => torso.transform.rotation - p.lean * s(t))));
|
|
3049
|
-
for (const h of byRole(doc, "head")) tracks.push(boneTrack(h, "rotation", sampled(T2, N, (t) => h.transform.rotation + p.lean / 2 * s(t))));
|
|
3110
|
+
if (torso && torso !== hips) tracks.push(boneTrack(torso, "rotation", sampled(T2, N, (t) => torso.transform.rotation - p.lean * s(t)), smooth));
|
|
3111
|
+
for (const h of byRole(doc, "head")) tracks.push(boneTrack(h, "rotation", sampled(T2, N, (t) => h.transform.rotation + p.lean / 2 * s(t)), smooth));
|
|
3050
3112
|
for (const leg of byRole(doc, "leg_l", "leg_r")) {
|
|
3051
3113
|
const slot = slotOfBone(doc, leg), att = slot && doc.attachments.find((a) => a.id === slot.attachment && a.type === "region");
|
|
3052
3114
|
const asset = att && att.type === "region" ? doc.assets.find((a) => a.id === att.asset) : void 0;
|
|
@@ -3056,8 +3118,8 @@ var weightShift = {
|
|
|
3056
3118
|
length = Math.max(...[[0, -h / 2], [w2 / 2, 0], [0, h / 2], [-w2 / 2, 0]].map(([x, y]) => Math.hypot(...apply(m, x, y))));
|
|
3057
3119
|
}
|
|
3058
3120
|
if (!(length > p.shift)) continue;
|
|
3059
|
-
tracks.push(boneTrack(leg, "rotation", sampled(T2, N, (t) => leg.transform.rotation + Math.asin(p.shift * s(t) / length) * 180 / Math.PI)));
|
|
3060
|
-
if (p.dip) tracks.push(boneTrack(leg, "y", sampled(T2, N, (t) => leg.transform.y - p.dip * s(t) ** 2)));
|
|
3121
|
+
tracks.push(boneTrack(leg, "rotation", sampled(T2, N, (t) => leg.transform.rotation + Math.asin(p.shift * s(t) / length) * 180 / Math.PI), smooth));
|
|
3122
|
+
if (p.dip) tracks.push(boneTrack(leg, "y", sampled(T2, N, (t) => leg.transform.y - p.dip * s(t) ** 2), smooth));
|
|
3061
3123
|
}
|
|
3062
3124
|
return finish(this.name, p.id, T2, true, tracks, p);
|
|
3063
3125
|
}
|
|
@@ -3300,13 +3362,13 @@ function motionQuality(doc, anim, opts = {}) {
|
|
|
3300
3362
|
const before = delta(values(k.v), values(p.v)), after = delta(values(n.v), values(k.v));
|
|
3301
3363
|
const pass = before.some((v, j2) => v * after[j2] > 1e-6);
|
|
3302
3364
|
const speed = Math.max(magnitude(before) / (k.t - p.t), magnitude(after) / (n.t - k.t));
|
|
3303
|
-
if (pass && Math.max(magnitude(left), magnitude(right)) < speed * 0.02) report("pass_key_stop", id, `motion stops at a pass-through key; use track interpolation pchip or matched tangents`, k.t);
|
|
3365
|
+
if (pass && Math.max(magnitude(left), magnitude(right)) < speed * 0.02) report("pass_key_stop", id, `motion stops at a pass-through key; use track interpolation pchip or spline, or matched tangents`, k.t);
|
|
3304
3366
|
const jump = magnitude(delta(left, right));
|
|
3305
3367
|
if (jump > Math.max(0.1, speed * 0.1)) report("velocity_jump", id, `velocity jumps ${jump.toFixed(3)} units/s across this key`, k.t);
|
|
3306
3368
|
const acceleration = (a, b, c) => values(at(b)).map((v, j2) => (values(at(c))[j2] - 2 * v + values(at(a))[j2]) / (h * h));
|
|
3307
3369
|
const al = acceleration(k.t - 2 * h, k.t - h, k.t), ar = acceleration(k.t, k.t + h, k.t + 2 * h);
|
|
3308
3370
|
const aj = magnitude(delta(al, ar));
|
|
3309
|
-
if (aj > Math.max(1, speed / Math.min(k.t - p.t, n.t - k.t) * 2)) report("acceleration_jump", id, `acceleration changes by ${aj.toFixed(2)} units/s\xB2 at this key; PCHIP guarantees velocity, not acceleration continuity`, k.t, "info");
|
|
3371
|
+
if (aj > Math.max(1, speed / Math.min(k.t - p.t, n.t - k.t) * 2)) report("acceleration_jump", id, `acceleration changes by ${aj.toFixed(2)} units/s\xB2 at this key; PCHIP guarantees velocity, not acceleration continuity \u2014 spline does both`, k.t, "info");
|
|
3310
3372
|
}
|
|
3311
3373
|
}
|
|
3312
3374
|
const steps = Math.max(2, Math.ceil(D * 60));
|
|
@@ -3788,6 +3850,17 @@ function checkRig(doc, opts = {}) {
|
|
|
3788
3850
|
out.push({ level: "warn", code: "never_visible", subject: s.id, message: `slot "${s.id}" has no attachment and no animation ever shows one` });
|
|
3789
3851
|
return out;
|
|
3790
3852
|
}
|
|
3853
|
+
function summarizeIgnoring(findings, rules, max) {
|
|
3854
|
+
const hits = (r, f) => r.code === f.code && (r.subject ?? f.subject) === f.subject && (r.animation ?? f.animation) === f.animation;
|
|
3855
|
+
const kept = findings.filter((f) => !rules.some((r) => hits(r, f)));
|
|
3856
|
+
const idle = rules.filter((r) => !findings.some((f) => hits(r, f)));
|
|
3857
|
+
const notes = [
|
|
3858
|
+
...kept.length < findings.length ? [` (${findings.length - kept.length} ignored)`] : [],
|
|
3859
|
+
...idle.map((r) => ` ignore matched nothing: ${JSON.stringify(r)}`)
|
|
3860
|
+
];
|
|
3861
|
+
return [summarize(kept, max), ...notes].join("\n");
|
|
3862
|
+
}
|
|
3863
|
+
var where = (f) => `${f.subject}${f.animation ? ` in ${f.animation}` : ""}${f.time !== void 0 ? ` @${+f.time.toFixed(4)}s` : ""}`;
|
|
3791
3864
|
function summarize(findings, max = 12) {
|
|
3792
3865
|
if (!findings.length) return "check: OK";
|
|
3793
3866
|
const rank = { error: 0, warn: 1, info: 2 };
|
|
@@ -3802,7 +3875,7 @@ function summarize(findings, max = 12) {
|
|
|
3802
3875
|
const lines = [];
|
|
3803
3876
|
for (const f of sorted) {
|
|
3804
3877
|
const shown = shownPerCode.get(f.code) ?? 0;
|
|
3805
|
-
if (shown < PER_CODE) lines.push(` [${f.level}] ${f.code}: ${f.message}`);
|
|
3878
|
+
if (shown < PER_CODE) lines.push(` [${f.level}] ${f.code} ${where(f)}: ${f.message}`);
|
|
3806
3879
|
else if (shown === PER_CODE) lines.push(` \u2026 ${codeTotal.get(f.code) - PER_CODE} more ${f.code}`);
|
|
3807
3880
|
shownPerCode.set(f.code, shown + 1);
|
|
3808
3881
|
}
|
|
@@ -3993,7 +4066,7 @@ function packRects(rects, opts = {}) {
|
|
|
3993
4066
|
shelf = Math.max(shelf, r.height);
|
|
3994
4067
|
}
|
|
3995
4068
|
const height = y + shelf + pad;
|
|
3996
|
-
if (height <= max) return { width, height, frames };
|
|
4069
|
+
if (height <= max) return { width: Math.max(pad, ...[...frames.values()].map(([fx, , fw]) => fx + fw)) + pad, height, frames };
|
|
3997
4070
|
if (width >= max) throw new Error(`atlas does not fit in ${max}\xD7${max} (needs ${width}\xD7${height})`);
|
|
3998
4071
|
width *= 2;
|
|
3999
4072
|
}
|
|
@@ -4052,7 +4125,7 @@ async function buildAtlas(doc, assetsDir, outDir, opts = {}) {
|
|
|
4052
4125
|
|
|
4053
4126
|
// src/spine-import.ts
|
|
4054
4127
|
import { readFile as readFile7, stat, writeFile as writeFile5 } from "node:fs/promises";
|
|
4055
|
-
import { basename as basename4, dirname as dirname6, extname, join as join8, relative } from "node:path";
|
|
4128
|
+
import { basename as basename4, dirname as dirname6, extname, join as join8, relative as relative2 } from "node:path";
|
|
4056
4129
|
|
|
4057
4130
|
// src/ktx2.ts
|
|
4058
4131
|
import { readFile as readFile6 } from "node:fs/promises";
|
|
@@ -4858,6 +4931,7 @@ async function importSpineProject(opts) {
|
|
|
4858
4931
|
const rigDir = dirname6(opts.rigPath);
|
|
4859
4932
|
const pagePaths = /* @__PURE__ */ new Map();
|
|
4860
4933
|
for (const page2 of pages) {
|
|
4934
|
+
if (!opts.image && outsideDir(dirname6(atlasPath), page2.name)) throw new Error(`atlas page "${page2.name}" is outside the atlas folder (${dirname6(atlasPath)})`);
|
|
4861
4935
|
const pageStem = join8(dirname6(atlasPath), page2.name.replace(/\.[a-z0-9]+$/i, ""));
|
|
4862
4936
|
const imagePath = opts.image ?? await firstExisting([join8(dirname6(atlasPath), page2.name), pageStem + ".png", pageStem + ".ktx2", ...pages.length === 1 ? [stem + ".png", stem + ".ktx2"] : []], `atlas page image ${page2.name}`);
|
|
4863
4937
|
let pngPath = imagePath;
|
|
@@ -4870,7 +4944,7 @@ async function importSpineProject(opts) {
|
|
|
4870
4944
|
}
|
|
4871
4945
|
pagePaths.set(page2.name, pngPath);
|
|
4872
4946
|
}
|
|
4873
|
-
const pageImage = (page2) =>
|
|
4947
|
+
const pageImage = (page2) => relative2(rigDir, pagePaths.get(page2)).split("\\").join("/");
|
|
4874
4948
|
const name = opts.name ?? basename4(stem);
|
|
4875
4949
|
const imagePaths = [...pagePaths.values()];
|
|
4876
4950
|
return { ...importSpine(json, atlasText, { name, skin: opts.skin, pageImage, margin: opts.margin, notes: opts.notes }), imagePath: imagePaths[0], imagePaths };
|
|
@@ -5563,8 +5637,8 @@ async function load(path) {
|
|
|
5563
5637
|
}
|
|
5564
5638
|
var save = (path, doc) => saveJson(path, doc);
|
|
5565
5639
|
var exists2 = (p) => stat2(p).then(() => true, () => false);
|
|
5566
|
-
var resolveFrom = (rigPath, p) =>
|
|
5567
|
-
var srcFor = (rigPath, file) =>
|
|
5640
|
+
var resolveFrom = (rigPath, p) => isAbsolute2(p) ? p : join9(dirname8(rigPath), p);
|
|
5641
|
+
var srcFor = (rigPath, file) => relative3(dirname8(rigPath), file).split("\\").join("/");
|
|
5568
5642
|
var libraryFor = (rigPath, lib) => lib ? resolveFrom(rigPath, lib) : join9(dirname8(rigPath), "presets.json");
|
|
5569
5643
|
async function pngInfo(rigPath, file) {
|
|
5570
5644
|
const abs = resolveFrom(rigPath, file);
|
|
@@ -5599,7 +5673,8 @@ function previewCheck(doc, animation) {
|
|
|
5599
5673
|
const a = animation ? doc.animations.find((x) => x.id === animation) : void 0;
|
|
5600
5674
|
return a ? `check: OK for "${a.id}" (${a.tracks.length} tracks, ${a.duration}s${a.loop ? " loop" : ""})` : "check: OK (rest pose)";
|
|
5601
5675
|
}
|
|
5602
|
-
var
|
|
5676
|
+
var TrackId = { target: z3.enum(["bone", "slot", "deform", "ik", "transform", "path", "drawOrder", "control"]), id: z3.string(), prop: z3.string() };
|
|
5677
|
+
var TrackRef = { interpolation: z3.enum(["segment", "pchip", "spline"]).optional().describe("segment: per-key easing; pchip: smooth through numeric keys, never past them (continuous velocity); spline: C2 cubic through them, continuous acceleration too, may overshoot between keys \u2014 for sampled curves"), ...TrackId };
|
|
5603
5678
|
tool(
|
|
5604
5679
|
"rig_set_control",
|
|
5605
5680
|
"Create or replace a semantic control with a finite min/max/default range. Animate target=control, prop=value. Changing a range requires matching binding grids.",
|
|
@@ -5792,11 +5867,21 @@ tool(
|
|
|
5792
5867
|
);
|
|
5793
5868
|
tool(
|
|
5794
5869
|
"rig_check",
|
|
5795
|
-
"Cheap self-critique without rendering: out_of_canvas (slot leaves the canvas, worst time), static_track, loop_seam, deform_flip (lattice folds over itself \u2014 an error), mesh_fold (a skinned/deformed mesh folds over itself: error when \u2265 5 % of the mesh folds, warning below \u2014 a dense mesh bent hard at a joint pinches the odd hairline triangle), weights_sum (skinned mesh vertex weights not summing to 1), patch_offset (a slot sits away from its asset's source bbox), rest_overlap, unused_asset, never_visible, and for constraints: constraint_dead (every mix is 0 at rest and no track lifts one \u2014 the solver skips it), constraint_cycle (the target is a bone the constraint drives, or hangs off one: it reads what it writes \u2014 an error), ik_unreachable (the target sits beyond the chain's reach for over 20 % of an animation, so the limb hangs straight), path_missing (a path constraint whose target slot never shows a path attachment \u2014 an error). Motion diagnostics also cover pass_key_stop, velocity_jump, acceleration_jump, loop_velocity and constraint_order; provide secondaryBones, frontOf slot pairs and named attachment UV landmarks for brief-specific frozen-motion, ordering and swap-registration checks. Findings are sorted by severity. Run it before spending vision tokens on a preview.",
|
|
5796
|
-
{
|
|
5797
|
-
|
|
5870
|
+
"Cheap self-critique without rendering: out_of_canvas (slot leaves the canvas, worst time), static_track, loop_seam, deform_flip (lattice folds over itself \u2014 an error), mesh_fold (a skinned/deformed mesh folds over itself: error when \u2265 5 % of the mesh folds, warning below \u2014 a dense mesh bent hard at a joint pinches the odd hairline triangle), weights_sum (skinned mesh vertex weights not summing to 1), patch_offset (a slot sits away from its asset's source bbox), rest_overlap, unused_asset, never_visible, and for constraints: constraint_dead (every mix is 0 at rest and no track lifts one \u2014 the solver skips it), constraint_cycle (the target is a bone the constraint drives, or hangs off one: it reads what it writes \u2014 an error), ik_unreachable (the target sits beyond the chain's reach for over 20 % of an animation, so the limb hangs straight), path_missing (a path constraint whose target slot never shows a path attachment \u2014 an error). Motion diagnostics also cover pass_key_stop, velocity_jump, acceleration_jump, loop_velocity and constraint_order; provide secondaryBones, frontOf slot pairs and named attachment UV landmarks for brief-specific frozen-motion, ordering and swap-registration checks. Findings are sorted by severity; each line names its subject (a track as target.id.prop), animation and time. `ignore` drops findings you have read and accept \u2014 by code, narrowed by subject and animation; the reply counts them and names a rule that matched nothing. Run it before spending vision tokens on a preview.",
|
|
5871
|
+
{
|
|
5872
|
+
path: Path,
|
|
5873
|
+
animation: z3.string().optional().describe("limit to one animation (rest pose is always checked)"),
|
|
5874
|
+
fps: z3.number().positive().optional(),
|
|
5875
|
+
deformFps: z3.number().positive().optional(),
|
|
5876
|
+
secondaryBones: z3.array(z3.string()).optional(),
|
|
5877
|
+
frontOf: z3.array(z3.tuple([z3.string(), z3.string()])).optional(),
|
|
5878
|
+
landmarks: z3.record(z3.record(z3.tuple([z3.number(), z3.number()]))).optional(),
|
|
5879
|
+
landmarkTolerance: z3.number().nonnegative().optional(),
|
|
5880
|
+
ignore: z3.array(z3.object({ code: z3.string(), subject: z3.string().optional(), animation: z3.string().optional() }).strict()).optional()
|
|
5881
|
+
},
|
|
5882
|
+
async ({ path, ignore = [], ...opts }) => {
|
|
5798
5883
|
try {
|
|
5799
|
-
return text(
|
|
5884
|
+
return text(summarizeIgnoring(checkRig(await load(path), opts), ignore, 100));
|
|
5800
5885
|
} catch (e) {
|
|
5801
5886
|
return fail(e);
|
|
5802
5887
|
}
|
|
@@ -6413,9 +6498,9 @@ tool(
|
|
|
6413
6498
|
);
|
|
6414
6499
|
tool(
|
|
6415
6500
|
"rig_adjust_track",
|
|
6416
|
-
"Re-tune an existing track without retyping keys: amplitude scales its deviation from the rest value (0.5 = half as strong, 2 = twice; scale props as ratios), offset adds a constant, timeScale stretches its key times (duration grows to fit). Drops the preset link.",
|
|
6501
|
+
"Re-tune an existing track without retyping keys: amplitude scales its deviation from the rest value (0.5 = half as strong, 2 = twice; scale props as ratios), offset adds a constant, timeScale stretches its key times (duration grows to fit), interpolation switches segment / pchip / spline. Drops the preset link.",
|
|
6417
6502
|
{ path: Path, animation: z3.string(), ...TrackRef, amplitude: z3.number().optional(), offset: z3.number().optional(), timeScale: z3.number().positive().optional() },
|
|
6418
|
-
async ({ path, animation, target, id, prop, ...adj }) => mutate(path, (d) => adjustTrack(d, animation, { target, id, prop }, adj))
|
|
6503
|
+
async ({ path, animation, target, id, prop, interpolation, ...adj }) => mutate(path, (d) => adjustTrack(d, animation, { target, id, prop, interpolation }, adj))
|
|
6419
6504
|
);
|
|
6420
6505
|
tool(
|
|
6421
6506
|
"rig_set_animation",
|
|
@@ -6433,7 +6518,7 @@ tool(
|
|
|
6433
6518
|
tool(
|
|
6434
6519
|
"rig_remove_keys",
|
|
6435
6520
|
"Remove the keys of one track at the given times; an emptied track is dropped. Drops the preset link.",
|
|
6436
|
-
{ path: Path, animation: z3.string(), ...
|
|
6521
|
+
{ path: Path, animation: z3.string(), ...TrackId, times: z3.array(z3.number()).min(1) },
|
|
6437
6522
|
async ({ path, animation, target, id, prop, times: times2 }) => mutate(path, (d) => removeKeys(d, animation, { target, id, prop }, times2))
|
|
6438
6523
|
);
|
|
6439
6524
|
tool(
|
|
@@ -6588,9 +6673,45 @@ tool(
|
|
|
6588
6673
|
}
|
|
6589
6674
|
}
|
|
6590
6675
|
);
|
|
6676
|
+
|
|
6677
|
+
// src/rig-version.ts
|
|
6678
|
+
import { stat as stat3 } from "node:fs/promises";
|
|
6679
|
+
async function rigVersion(abs) {
|
|
6680
|
+
try {
|
|
6681
|
+
const s = await stat3(abs);
|
|
6682
|
+
return `${s.mtimeMs}:${s.size}`;
|
|
6683
|
+
} catch {
|
|
6684
|
+
return "missing";
|
|
6685
|
+
}
|
|
6686
|
+
}
|
|
6687
|
+
async function callToolVersioned(name, args) {
|
|
6688
|
+
const path = typeof args.path === "string" ? args.path : void 0;
|
|
6689
|
+
if (!path) return { result: await callTool(name, args), before: "missing", after: "missing" };
|
|
6690
|
+
return withRigQueue(path, async () => {
|
|
6691
|
+
const before = await rigVersion(path);
|
|
6692
|
+
const result = await callTool(name, args);
|
|
6693
|
+
return { result, before, after: await rigVersion(path) };
|
|
6694
|
+
});
|
|
6695
|
+
}
|
|
6696
|
+
|
|
6697
|
+
// src/tool-schema.ts
|
|
6698
|
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
6699
|
+
function prefixItems(node) {
|
|
6700
|
+
if (Array.isArray(node)) return node.map(prefixItems);
|
|
6701
|
+
if (!node || typeof node !== "object") return node;
|
|
6702
|
+
const { items, ...rest } = Object.fromEntries(Object.entries(node).map(([k, v]) => [k, prefixItems(v)]));
|
|
6703
|
+
return items === void 0 ? rest : Array.isArray(items) ? { ...rest, prefixItems: items } : { ...rest, items };
|
|
6704
|
+
}
|
|
6705
|
+
function jsonSchemaOf(tool2) {
|
|
6706
|
+
const { $schema: _drop, ...schema } = zodToJsonSchema(tool2.input, { $refStrategy: "none" });
|
|
6707
|
+
return prefixItems(schema);
|
|
6708
|
+
}
|
|
6591
6709
|
export {
|
|
6592
6710
|
callTool,
|
|
6711
|
+
callToolVersioned,
|
|
6593
6712
|
closeTools,
|
|
6713
|
+
jsonSchemaOf,
|
|
6714
|
+
rigVersion,
|
|
6594
6715
|
tools
|
|
6595
6716
|
};
|
|
6596
6717
|
//# sourceMappingURL=tools.js.map
|