@energy8platform/golem 0.2.1 → 0.5.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 +28 -2
- package/dist/editor.css +50 -0
- package/dist/editor.js +1772 -1037
- package/dist/lib/cli.js +1575 -366
- package/dist/lib/cli.js.map +4 -4
- package/dist/lib/editor/controls-panel.d.ts +2 -0
- package/dist/lib/editor/stage.d.ts +1 -0
- package/dist/lib/editor/store.d.ts +212 -33
- package/dist/lib/editor-entry.js +1575 -366
- package/dist/lib/editor-entry.js.map +4 -4
- package/dist/lib/harness.js +328 -31
- package/dist/lib/interactive-bones.d.ts +37 -0
- package/dist/lib/interactive-editor.d.ts +80 -0
- package/dist/lib/interactive-editor.js +744 -0
- package/dist/lib/interactive-editor.js.map +7 -0
- package/dist/lib/preview/export-video.d.ts +12 -0
- package/dist/lib/preview/harness.d.ts +2 -0
- package/dist/lib/preview/render-preview.d.ts +6 -0
- package/dist/lib/rig-anim.d.ts +6 -3
- package/dist/lib/rig-check.d.ts +2 -1
- package/dist/lib/rig-constraints.d.ts +63 -0
- package/dist/lib/rig-control-qa.d.ts +319 -0
- package/dist/lib/rig-controls.d.ts +13 -0
- package/dist/lib/rig-format.d.ts +1469 -331
- package/dist/lib/rig-gates.d.ts +209 -0
- package/dist/lib/rig-mesh.d.ts +1 -0
- package/dist/lib/rig-motion.d.ts +22 -0
- package/dist/lib/rig-qa.d.ts +35 -0
- package/dist/lib/rig-quality.d.ts +12 -0
- package/dist/lib/rig-runtime.d.ts +43 -3
- package/dist/lib/rig-state.d.ts +3 -0
- package/dist/lib/rig-tools.d.ts +5 -1
- package/dist/lib/runtime.d.ts +3 -1
- package/dist/lib/runtime.js +306 -28
- package/dist/lib/runtime.js.map +4 -4
- package/dist/lib/tools.js +1557 -348
- package/dist/lib/tools.js.map +4 -4
- package/package.json +8 -2
package/dist/lib/harness.js
CHANGED
|
@@ -49413,7 +49413,7 @@ ${parts.join("\n")}
|
|
|
49413
49413
|
var ID_RE = /^[a-z][a-z0-9_]*$/;
|
|
49414
49414
|
var Id = external_exports.string().regex(ID_RE, "snake_case id");
|
|
49415
49415
|
var Ease = external_exports.union([
|
|
49416
|
-
external_exports.enum(["linear", "step", "ease_in", "ease_out", "ease_in_out", "back_out", "elastic_out"]),
|
|
49416
|
+
external_exports.enum(["linear", "step", "ease_in", "ease_out", "ease_in_out", "minimum_jerk", "back_out", "elastic_out"]),
|
|
49417
49417
|
// cubic-bezier control points, same semantics as CSS
|
|
49418
49418
|
external_exports.object({ bezier: external_exports.tuple([external_exports.number(), external_exports.number(), external_exports.number(), external_exports.number()]) })
|
|
49419
49419
|
]);
|
|
@@ -49445,6 +49445,7 @@ ${parts.join("\n")}
|
|
|
49445
49445
|
/** where this layer came from — provenance for agents */
|
|
49446
49446
|
origin: external_exports.object({
|
|
49447
49447
|
sourceImage: external_exports.string().optional(),
|
|
49448
|
+
bboxSpace: external_exports.enum(["source", "document"]).optional(),
|
|
49448
49449
|
/** bbox in source image: [x, y, w, h] */
|
|
49449
49450
|
bbox: external_exports.tuple([external_exports.number(), external_exports.number(), external_exports.number(), external_exports.number()]).optional(),
|
|
49450
49451
|
inpainted: external_exports.boolean().default(false),
|
|
@@ -49467,6 +49468,8 @@ ${parts.join("\n")}
|
|
|
49467
49468
|
var Slot = external_exports.object({
|
|
49468
49469
|
id: Id,
|
|
49469
49470
|
bone: Id,
|
|
49471
|
+
/** Closed path attachment used as a moving clipping mask. */
|
|
49472
|
+
clip: Id.optional(),
|
|
49470
49473
|
/** active attachment id; undefined = hidden */
|
|
49471
49474
|
attachment: Id.optional(),
|
|
49472
49475
|
alpha: external_exports.number().min(0).max(1).default(1),
|
|
@@ -49529,6 +49532,8 @@ ${parts.join("\n")}
|
|
|
49529
49532
|
order: external_exports.number().int().default(0),
|
|
49530
49533
|
bones: external_exports.array(Id).min(1),
|
|
49531
49534
|
target: Id,
|
|
49535
|
+
iterations: external_exports.number().int().min(1).max(1e3).optional(),
|
|
49536
|
+
tolerance: external_exports.number().positive().optional(),
|
|
49532
49537
|
mix: external_exports.number().default(1),
|
|
49533
49538
|
softness: external_exports.number().default(0),
|
|
49534
49539
|
bendPositive: external_exports.boolean().default(true),
|
|
@@ -49576,7 +49581,7 @@ ${parts.join("\n")}
|
|
|
49576
49581
|
var SlotProp = external_exports.enum(["alpha", "attachment", "z", "color"]);
|
|
49577
49582
|
var DeformProp = external_exports.string().regex(/^(bulge|bend|sway|squash|p[0-2][0-2][xy]|vertices)$/, "deform prop must be bulge|bend|sway|squash|p<row><col>x|y|vertices");
|
|
49578
49583
|
var IkProp = external_exports.enum(["mix", "softness", "bendPositive", "compress", "stretch"]);
|
|
49579
|
-
var TransformProp = external_exports.enum(["mixRotate", "mixX", "mixY", "mixScaleX", "mixScaleY", "mixShearY"]);
|
|
49584
|
+
var TransformProp = external_exports.enum(["mixRotate", "mixX", "mixY", "mixScaleX", "mixScaleY", "mixShearY", "x", "y", "rotation", "scaleX", "scaleY", "shearY"]);
|
|
49580
49585
|
var PathProp = external_exports.enum(["position", "spacing", "mixRotate", "mixX", "mixY"]);
|
|
49581
49586
|
var KeyValue = external_exports.union([external_exports.number(), external_exports.string(), external_exports.null(), external_exports.array(external_exports.number()), external_exports.array(external_exports.string())]);
|
|
49582
49587
|
var Key = external_exports.object({
|
|
@@ -49585,14 +49590,16 @@ ${parts.join("\n")}
|
|
|
49585
49590
|
/** easing INTO the next key */
|
|
49586
49591
|
ease: Ease.default("ease_in_out")
|
|
49587
49592
|
});
|
|
49593
|
+
var Interpolation = { interpolation: external_exports.enum(["segment", "pchip"]).optional() };
|
|
49588
49594
|
var Track = external_exports.discriminatedUnion("target", [
|
|
49589
|
-
external_exports.object({ target: external_exports.literal("
|
|
49590
|
-
external_exports.object({ target: external_exports.literal("
|
|
49591
|
-
external_exports.object({ target: external_exports.literal("
|
|
49592
|
-
external_exports.object({ target: external_exports.literal("
|
|
49593
|
-
external_exports.object({ target: external_exports.literal("
|
|
49594
|
-
external_exports.object({ target: external_exports.literal("
|
|
49595
|
-
external_exports.object({ target: external_exports.literal("
|
|
49595
|
+
external_exports.object({ target: external_exports.literal("control"), id: Id, prop: external_exports.literal("value"), ...Interpolation, keys: external_exports.array(Key).min(1) }),
|
|
49596
|
+
external_exports.object({ target: external_exports.literal("bone"), id: Id, prop: BoneProp, ...Interpolation, keys: external_exports.array(Key).min(1) }),
|
|
49597
|
+
external_exports.object({ target: external_exports.literal("slot"), id: Id, prop: SlotProp, ...Interpolation, keys: external_exports.array(Key).min(1) }),
|
|
49598
|
+
external_exports.object({ target: external_exports.literal("deform"), id: Id, prop: DeformProp, ...Interpolation, keys: external_exports.array(Key).min(1) }),
|
|
49599
|
+
external_exports.object({ target: external_exports.literal("ik"), id: Id, prop: IkProp, ...Interpolation, keys: external_exports.array(Key).min(1) }),
|
|
49600
|
+
external_exports.object({ target: external_exports.literal("transform"), id: Id, prop: TransformProp, ...Interpolation, keys: external_exports.array(Key).min(1) }),
|
|
49601
|
+
external_exports.object({ target: external_exports.literal("path"), id: Id, prop: PathProp, ...Interpolation, keys: external_exports.array(Key).min(1) }),
|
|
49602
|
+
external_exports.object({ target: external_exports.literal("drawOrder"), id: Id.default("order"), prop: external_exports.literal("order").default("order"), ...Interpolation, keys: external_exports.array(Key).min(1) })
|
|
49596
49603
|
]);
|
|
49597
49604
|
var Event2 = external_exports.object({
|
|
49598
49605
|
t: external_exports.number().nonnegative(),
|
|
@@ -49608,6 +49615,25 @@ ${parts.join("\n")}
|
|
|
49608
49615
|
/** if generated from a preset — keep params so the agent can re-tune instead of re-keying */
|
|
49609
49616
|
preset: external_exports.object({ name: external_exports.string(), params: external_exports.record(external_exports.unknown()) }).optional()
|
|
49610
49617
|
});
|
|
49618
|
+
var RigControl = external_exports.object({
|
|
49619
|
+
id: Id,
|
|
49620
|
+
label: external_exports.string().optional(),
|
|
49621
|
+
min: external_exports.number().finite(),
|
|
49622
|
+
max: external_exports.number().finite(),
|
|
49623
|
+
default: external_exports.number().finite()
|
|
49624
|
+
}).strict();
|
|
49625
|
+
var ControlValues = external_exports.array(external_exports.union([external_exports.number().finite(), external_exports.array(external_exports.number().finite()).min(1)])).min(2);
|
|
49626
|
+
var ControlChannel = external_exports.discriminatedUnion("target", [
|
|
49627
|
+
external_exports.object({ target: external_exports.literal("bone"), id: Id, prop: BoneProp, values: ControlValues }).strict(),
|
|
49628
|
+
external_exports.object({ target: external_exports.literal("slot"), id: Id, prop: external_exports.literal("alpha"), values: ControlValues }).strict(),
|
|
49629
|
+
external_exports.object({ target: external_exports.literal("deform"), id: Id, prop: external_exports.literal("vertices"), values: ControlValues }).strict()
|
|
49630
|
+
]);
|
|
49631
|
+
var ControlBinding = external_exports.object({
|
|
49632
|
+
id: Id,
|
|
49633
|
+
axes: external_exports.array(external_exports.object({ control: Id, keys: external_exports.array(external_exports.number().finite()).min(2).max(32) }).strict()).min(1).max(2),
|
|
49634
|
+
/** Flattened grid, first axis varies fastest. Linear / bilinear interpolation. */
|
|
49635
|
+
channels: external_exports.array(ControlChannel).min(1)
|
|
49636
|
+
}).strict();
|
|
49611
49637
|
var Reference = external_exports.object({
|
|
49612
49638
|
src: external_exports.string(),
|
|
49613
49639
|
opacity: external_exports.number().min(0).max(1).default(0.5),
|
|
@@ -49633,7 +49659,9 @@ ${parts.join("\n")}
|
|
|
49633
49659
|
ik: external_exports.array(IkConstraint).default([]),
|
|
49634
49660
|
transform: external_exports.array(TransformConstraint).default([]),
|
|
49635
49661
|
path: external_exports.array(PathConstraint).default([]),
|
|
49636
|
-
animations: external_exports.array(Animation)
|
|
49662
|
+
animations: external_exports.array(Animation),
|
|
49663
|
+
controls: external_exports.array(RigControl).optional(),
|
|
49664
|
+
controlBindings: external_exports.array(ControlBinding).optional()
|
|
49637
49665
|
});
|
|
49638
49666
|
var RigDocument = external_exports.preprocess((input) => {
|
|
49639
49667
|
const v2 = input?.version;
|
|
@@ -49708,6 +49736,8 @@ ${parts.join("\n")}
|
|
|
49708
49736
|
dup(doc.ik, "ik");
|
|
49709
49737
|
dup(doc.transform, "transform");
|
|
49710
49738
|
dup(doc.path, "path");
|
|
49739
|
+
dup(doc.controls ?? [], "control");
|
|
49740
|
+
dup(doc.controlBindings ?? [], "control binding");
|
|
49711
49741
|
const bones = new Set(doc.bones.map((b2) => b2.id));
|
|
49712
49742
|
const assets = new Map(doc.assets.map((a2) => [a2.id, a2]));
|
|
49713
49743
|
const slots = new Set(doc.slots.map((s2) => s2.id));
|
|
@@ -49734,6 +49764,10 @@ ${parts.join("\n")}
|
|
|
49734
49764
|
if (a2.frame && !a2.trim && !a2.rotate && (a2.frame[2] !== a2.width || a2.frame[3] !== a2.height)) errs.push(`asset "${a2.id}": frame size must equal width\xD7height (or declare trim/rotate)`);
|
|
49735
49765
|
}
|
|
49736
49766
|
for (const s2 of doc.slots) {
|
|
49767
|
+
if (s2.clip) {
|
|
49768
|
+
const mask = attachments.get(s2.clip);
|
|
49769
|
+
if (mask?.type !== "path" || !mask.closed) errs.push(`slot "${s2.id}": clip must name a closed path attachment`);
|
|
49770
|
+
}
|
|
49737
49771
|
if (!bones.has(s2.bone)) errs.push(`slot "${s2.id}": unknown bone "${s2.bone}"`);
|
|
49738
49772
|
if (s2.attachment) {
|
|
49739
49773
|
const a2 = attachments.get(s2.attachment);
|
|
@@ -49765,7 +49799,8 @@ ${parts.join("\n")}
|
|
|
49765
49799
|
}
|
|
49766
49800
|
}
|
|
49767
49801
|
for (const c2 of doc.ik) {
|
|
49768
|
-
|
|
49802
|
+
for (let i2 = 1; i2 < c2.bones.length; i2++) if (doc.bones.find((b2) => b2.id === c2.bones[i2])?.parent !== c2.bones[i2 - 1])
|
|
49803
|
+
errs.push(`ik "${c2.id}": bones must form a contiguous parent-to-child chain`);
|
|
49769
49804
|
for (const b2 of c2.bones) if (!bones.has(b2)) errs.push(`ik "${c2.id}": unknown bone "${b2}"`);
|
|
49770
49805
|
if (!bones.has(c2.target)) errs.push(`ik "${c2.id}": unknown target bone "${c2.target}"`);
|
|
49771
49806
|
}
|
|
@@ -49777,13 +49812,47 @@ ${parts.join("\n")}
|
|
|
49777
49812
|
for (const b2 of c2.bones) if (!bones.has(b2)) errs.push(`path "${c2.id}": unknown bone "${b2}"`);
|
|
49778
49813
|
if (!slots.has(c2.target)) errs.push(`path "${c2.id}": unknown target slot "${c2.target}"`);
|
|
49779
49814
|
}
|
|
49815
|
+
const controls = new Map((doc.controls ?? []).map((c2) => [c2.id, c2]));
|
|
49816
|
+
const driven = /* @__PURE__ */ new Set();
|
|
49817
|
+
for (const c2 of controls.values()) if (!(c2.min < c2.max && c2.default >= c2.min && c2.default <= c2.max))
|
|
49818
|
+
errs.push(`control "${c2.id}": require min < max and default within range`);
|
|
49819
|
+
for (const b2 of doc.controlBindings ?? []) {
|
|
49820
|
+
const prefix = `control binding "${b2.id}"`;
|
|
49821
|
+
if (new Set(b2.axes.map((a2) => a2.control)).size !== b2.axes.length) errs.push(`${prefix}: axes must use different controls`);
|
|
49822
|
+
for (const axis of b2.axes) {
|
|
49823
|
+
const c2 = controls.get(axis.control);
|
|
49824
|
+
if (!c2) errs.push(`${prefix}: unknown control "${axis.control}"`);
|
|
49825
|
+
else if (axis.keys[0] !== c2.min || axis.keys.at(-1) !== c2.max) errs.push(`${prefix}: keys must span the control's full range`);
|
|
49826
|
+
if (axis.keys.some((v2, i2) => i2 > 0 && v2 <= axis.keys[i2 - 1])) errs.push(`${prefix}: keys must be strictly increasing`);
|
|
49827
|
+
}
|
|
49828
|
+
const count2 = b2.axes.reduce((n2, a2) => n2 * a2.keys.length, 1);
|
|
49829
|
+
for (const ch of b2.channels) {
|
|
49830
|
+
const key = `${ch.target}.${ch.id}.${ch.prop}`;
|
|
49831
|
+
if (driven.has(key)) errs.push(`${prefix}: channel ${key} already owned by a binding`);
|
|
49832
|
+
driven.add(key);
|
|
49833
|
+
if (ch.values.length !== count2) errs.push(`${prefix}: ${key} needs ${count2} grid values`);
|
|
49834
|
+
if (ch.target === "deform") {
|
|
49835
|
+
const att = attachments.get(ch.id);
|
|
49836
|
+
if (!att || att.type === "region") errs.push(`${prefix}: vertices need a mesh or path attachment`);
|
|
49837
|
+
else {
|
|
49838
|
+
const n2 = att.weights ? att.weights.reduce((s2, a2) => s2 + a2.length * 2, 0) : att.vertices.length;
|
|
49839
|
+
if (ch.values.some((v2) => !Array.isArray(v2) || v2.length !== n2)) errs.push(`${prefix}: ${key} needs arrays of ${n2} offsets`);
|
|
49840
|
+
}
|
|
49841
|
+
} else {
|
|
49842
|
+
if (!(ch.target === "bone" ? bones : slots).has(ch.id)) errs.push(`${prefix}: unknown ${ch.target} "${ch.id}"`);
|
|
49843
|
+
if (ch.values.some((v2) => typeof v2 !== "number")) errs.push(`${prefix}: ${key} needs numeric values`);
|
|
49844
|
+
if (ch.target === "slot" && ch.values.some((v2) => typeof v2 === "number" && (v2 < 0 || v2 > 1))) errs.push(`${prefix}: alpha must be in 0..1`);
|
|
49845
|
+
}
|
|
49846
|
+
}
|
|
49847
|
+
}
|
|
49780
49848
|
for (const a2 of doc.animations) {
|
|
49781
49849
|
const tracks = /* @__PURE__ */ new Set();
|
|
49782
49850
|
for (const t2 of a2.tracks) {
|
|
49783
49851
|
const tid = trackId(t2);
|
|
49784
49852
|
if (tracks.has(tid)) errs.push(`animation "${a2.id}": duplicate track ${tid}`);
|
|
49785
49853
|
tracks.add(tid);
|
|
49786
|
-
|
|
49854
|
+
if (driven.has(tid)) errs.push(`animation "${a2.id}": ${tid} is controlled by a binding; animate its control instead`);
|
|
49855
|
+
const known = t2.target === "bone" ? bones.has(t2.id) : t2.target === "slot" ? slots.has(t2.id) : t2.target === "deform" ? attachments.has(t2.id) : t2.target === "ik" ? iks.has(t2.id) : t2.target === "transform" ? transforms.has(t2.id) : t2.target === "path" ? paths.has(t2.id) : t2.target === "control" ? controls.has(t2.id) : true;
|
|
49787
49856
|
if (!known) errs.push(`animation "${a2.id}": unknown ${t2.target} "${t2.id}"`);
|
|
49788
49857
|
const bound = t2.target === "deform" ? DEFORM_BOUNDS[t2.prop] : void 0;
|
|
49789
49858
|
const att = t2.target === "deform" ? attachments.get(t2.id) : void 0;
|
|
@@ -49791,6 +49860,10 @@ ${parts.join("\n")}
|
|
|
49791
49860
|
for (const k2 of t2.keys) {
|
|
49792
49861
|
if (k2.t <= prev && prev >= 0) errs.push(`animation "${a2.id}" ${tid}: keys not strictly increasing`);
|
|
49793
49862
|
if (k2.t > a2.duration) errs.push(`animation "${a2.id}" ${tid}: key at ${k2.t}s exceeds duration`);
|
|
49863
|
+
if (t2.target === "control") {
|
|
49864
|
+
const c2 = controls.get(t2.id);
|
|
49865
|
+
if (typeof k2.v !== "number" || !Number.isFinite(k2.v) || c2 && (k2.v < c2.min || k2.v > c2.max)) errs.push(`animation "${a2.id}" ${tid}: control key outside its finite range`);
|
|
49866
|
+
}
|
|
49794
49867
|
if (t2.target === "slot" && t2.prop === "attachment") {
|
|
49795
49868
|
if (k2.v !== null && typeof k2.v !== "string") errs.push(`animation "${a2.id}" ${tid}: attachment key must be an attachment id or null`);
|
|
49796
49869
|
else if (typeof k2.v === "string") {
|
|
@@ -49829,6 +49902,52 @@ ${parts.join("\n")}
|
|
|
49829
49902
|
return doc;
|
|
49830
49903
|
}
|
|
49831
49904
|
|
|
49905
|
+
// src/rig-controls.ts
|
|
49906
|
+
function controlPose(doc, values) {
|
|
49907
|
+
const out2 = /* @__PURE__ */ new Map();
|
|
49908
|
+
for (const [id, value] of Object.entries(values)) {
|
|
49909
|
+
const c2 = doc.controls?.find((c3) => c3.id === id);
|
|
49910
|
+
if (!c2) throw new Error(`unknown control "${id}"`);
|
|
49911
|
+
if (!Number.isFinite(value)) throw new Error(`control "${id}" must be finite`);
|
|
49912
|
+
out2.set(`control:${id}:value`, Math.max(c2.min, Math.min(c2.max, value)));
|
|
49913
|
+
}
|
|
49914
|
+
return out2;
|
|
49915
|
+
}
|
|
49916
|
+
function bracket(keys, value) {
|
|
49917
|
+
let i2 = 0;
|
|
49918
|
+
while (i2 < keys.length - 2 && value > keys[i2 + 1]) i2++;
|
|
49919
|
+
return [i2, Math.max(0, Math.min(1, (value - keys[i2]) / (keys[i2 + 1] - keys[i2])))];
|
|
49920
|
+
}
|
|
49921
|
+
function sampleBinding(binding, values) {
|
|
49922
|
+
const [x2, u2] = bracket(binding.axes[0].keys, values[0]);
|
|
49923
|
+
const [y2, v2] = binding.axes[1] ? bracket(binding.axes[1].keys, values[1]) : [0, 0];
|
|
49924
|
+
const width = binding.axes[0].keys.length, a2 = y2 * width + x2;
|
|
49925
|
+
const mix = (a3, b2, u3) => a3 + (b2 - a3) * u3;
|
|
49926
|
+
return binding.channels.map((ch) => {
|
|
49927
|
+
const read = (i2, j2) => j2 === void 0 ? ch.values[i2] : ch.values[i2][j2];
|
|
49928
|
+
const at = (j2) => {
|
|
49929
|
+
const top = mix(read(a2, j2), read(a2 + 1, j2), u2);
|
|
49930
|
+
return binding.axes[1] ? mix(top, mix(read(a2 + width, j2), read(a2 + width + 1, j2), u2), v2) : top;
|
|
49931
|
+
};
|
|
49932
|
+
return Array.isArray(ch.values[0]) ? ch.values[0].map((_, j2) => at(j2)) : at();
|
|
49933
|
+
});
|
|
49934
|
+
}
|
|
49935
|
+
function resolveControls(doc, input) {
|
|
49936
|
+
if (!doc.controlBindings?.length) return input;
|
|
49937
|
+
const out2 = new Map(input), controls = new Map(doc.controls?.map((c2) => [c2.id, c2]));
|
|
49938
|
+
for (const b2 of doc.controlBindings) {
|
|
49939
|
+
const values = b2.axes.map((axis) => {
|
|
49940
|
+
const c2 = controls.get(axis.control);
|
|
49941
|
+
const value = input.get(`control:${c2.id}:value`) ?? c2.default;
|
|
49942
|
+
if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`control "${c2.id}" must be finite`);
|
|
49943
|
+
return Math.max(c2.min, Math.min(c2.max, value));
|
|
49944
|
+
});
|
|
49945
|
+
const sampled = sampleBinding(b2, values);
|
|
49946
|
+
b2.channels.forEach((ch, i2) => out2.set(`${ch.target}:${ch.id}:${ch.prop}`, sampled[i2]));
|
|
49947
|
+
}
|
|
49948
|
+
return out2;
|
|
49949
|
+
}
|
|
49950
|
+
|
|
49832
49951
|
// src/rig-anim.ts
|
|
49833
49952
|
var DEG2 = Math.PI / 180;
|
|
49834
49953
|
var named = {
|
|
@@ -49837,6 +49956,7 @@ ${parts.join("\n")}
|
|
|
49837
49956
|
ease_in: (t2) => t2 * t2,
|
|
49838
49957
|
ease_out: (t2) => 1 - (1 - t2) * (1 - t2),
|
|
49839
49958
|
ease_in_out: (t2) => t2 < 0.5 ? 2 * t2 * t2 : 1 - (-2 * t2 + 2) ** 2 / 2,
|
|
49959
|
+
minimum_jerk: (t2) => t2 * t2 * t2 * (10 + t2 * (-15 + 6 * t2)),
|
|
49840
49960
|
back_out: (t2) => 1 + 2.70158 * (t2 - 1) ** 3 + 1.70158 * (t2 - 1) ** 2,
|
|
49841
49961
|
elastic_out: (t2) => t2 === 0 ? 0 : t2 === 1 ? 1 : 2 ** (-10 * t2) * Math.sin((t2 * 10 - 0.75) * (2 * Math.PI / 3)) + 1
|
|
49842
49962
|
};
|
|
@@ -49868,7 +49988,25 @@ ${parts.join("\n")}
|
|
|
49868
49988
|
return f2;
|
|
49869
49989
|
}
|
|
49870
49990
|
var pk = (target, id, prop) => `${target}:${id}:${prop}`;
|
|
49871
|
-
function
|
|
49991
|
+
function smoothValue(track, i2, t2, component, loop) {
|
|
49992
|
+
const k2 = track.keys, n2 = k2.length;
|
|
49993
|
+
const v2 = (j2) => component === void 0 ? k2[j2].v : k2[j2].v[component];
|
|
49994
|
+
const h2 = (j2) => k2[j2 + 1].t - k2[j2].t;
|
|
49995
|
+
const d2 = (j2) => (v2(j2 + 1) - v2(j2)) / h2(j2);
|
|
49996
|
+
const harmonic = (a2, b2, h0, h1) => a2 * b2 <= 0 ? 0 : 3 * (h0 + h1) / ((2 * h1 + h0) / a2 + (h1 + 2 * h0) / b2);
|
|
49997
|
+
const tangent = (j2) => {
|
|
49998
|
+
if (j2 === 0 || j2 === n2 - 1) {
|
|
49999
|
+
if (loop && n2 > 2 && v2(0) === v2(n2 - 1) && k2[0].ease !== "step" && k2[n2 - 2].ease !== "step")
|
|
50000
|
+
return harmonic(d2(n2 - 2), d2(0), h2(n2 - 2), h2(0));
|
|
50001
|
+
return 0;
|
|
50002
|
+
}
|
|
50003
|
+
if (k2[j2 - 1].ease === "step" || k2[j2].ease === "step") return 0;
|
|
50004
|
+
return harmonic(d2(j2 - 1), d2(j2), h2(j2 - 1), h2(j2));
|
|
50005
|
+
};
|
|
50006
|
+
const u2 = (t2 - k2[i2].t) / h2(i2), u22 = u2 * u2, u3 = u22 * u2;
|
|
50007
|
+
return (2 * u3 - 3 * u22 + 1) * v2(i2) + (u3 - 2 * u22 + u2) * h2(i2) * tangent(i2) + (-2 * u3 + 3 * u22) * v2(i2 + 1) + (u3 - u22) * h2(i2) * tangent(i2 + 1);
|
|
50008
|
+
}
|
|
50009
|
+
function sample(track, t2, loop = false) {
|
|
49872
50010
|
const keys = track.keys;
|
|
49873
50011
|
if (t2 <= keys[0].t) return keys[0].v;
|
|
49874
50012
|
const last = keys[keys.length - 1];
|
|
@@ -49876,36 +50014,44 @@ ${parts.join("\n")}
|
|
|
49876
50014
|
let i2 = 0;
|
|
49877
50015
|
while (keys[i2 + 1].t <= t2) i2++;
|
|
49878
50016
|
const a2 = keys[i2], b2 = keys[i2 + 1];
|
|
50017
|
+
if (a2.ease === "step") return a2.v;
|
|
49879
50018
|
if (typeof a2.v === "number" && typeof b2.v === "number") {
|
|
50019
|
+
if (track.interpolation === "pchip") return smoothValue(track, i2, t2, void 0, loop);
|
|
49880
50020
|
const u2 = ease(a2.ease)((t2 - a2.t) / (b2.t - a2.t));
|
|
49881
50021
|
return a2.v + (b2.v - a2.v) * u2;
|
|
49882
50022
|
}
|
|
49883
50023
|
if (Array.isArray(a2.v) && Array.isArray(b2.v) && typeof a2.v[0] === "number") {
|
|
50024
|
+
if (track.interpolation === "pchip") return a2.v.map((_, j2) => smoothValue(track, i2, t2, j2, loop));
|
|
49884
50025
|
const u2 = ease(a2.ease)((t2 - a2.t) / (b2.t - a2.t)), av = a2.v, bv = b2.v;
|
|
49885
50026
|
return av.map((v2, k2) => v2 + ((bv[k2] ?? v2) - v2) * u2);
|
|
49886
50027
|
}
|
|
49887
50028
|
return a2.v;
|
|
49888
50029
|
}
|
|
49889
50030
|
function poseOf(anim, t2, out2 = /* @__PURE__ */ new Map()) {
|
|
49890
|
-
for (const tr of anim.tracks) out2.set(pk(tr.target, tr.id, tr.prop), sample(tr, t2));
|
|
50031
|
+
for (const tr of anim.tracks) out2.set(pk(tr.target, tr.id, tr.prop), sample(tr, t2, anim.loop && tr.keys[0].t === 0 && tr.keys.at(-1).t === anim.duration));
|
|
49891
50032
|
return out2;
|
|
49892
50033
|
}
|
|
49893
50034
|
function blendPoses(from, to, w2, restOf) {
|
|
49894
|
-
|
|
49895
|
-
|
|
49896
|
-
|
|
49897
|
-
|
|
50035
|
+
if (w2 >= 1) return new Map(to);
|
|
50036
|
+
const out2 = /* @__PURE__ */ new Map();
|
|
50037
|
+
for (const k2 of /* @__PURE__ */ new Set([...from.keys(), ...to.keys()])) {
|
|
50038
|
+
const f2 = from.has(k2) ? from.get(k2) : restOf(k2);
|
|
50039
|
+
const cur = to.has(k2) ? to.get(k2) : restOf(k2);
|
|
50040
|
+
if (typeof f2 === "number" && !Array.isArray(cur)) {
|
|
49898
50041
|
const target = typeof cur === "number" ? cur : restOf(k2);
|
|
49899
50042
|
out2.set(k2, f2 + (target - f2) * w2);
|
|
49900
50043
|
} else if (Array.isArray(f2) && typeof f2[0] === "number") {
|
|
49901
50044
|
const fv = f2, tv = Array.isArray(cur) && typeof cur[0] === "number" ? cur : fv.map(() => 0);
|
|
49902
50045
|
out2.set(k2, fv.map((v2, i2) => v2 + ((tv[i2] ?? 0) - v2) * w2));
|
|
49903
|
-
} else if (cur
|
|
50046
|
+
} else if (Array.isArray(cur) && typeof cur[0] === "number" && typeof f2 !== "string") {
|
|
50047
|
+
out2.set(k2, cur.map((v2) => v2 * w2));
|
|
50048
|
+
} else out2.set(k2, f2 ?? null);
|
|
49904
50049
|
}
|
|
49905
50050
|
return out2;
|
|
49906
50051
|
}
|
|
49907
50052
|
function restValue(doc, key) {
|
|
49908
50053
|
const [target, id, prop] = key.split(":");
|
|
50054
|
+
if (target === "control") return doc.controls?.find((c2) => c2.id === id)?.default ?? 0;
|
|
49909
50055
|
if (target === "bone") return doc.bones.find((b2) => b2.id === id).transform[prop];
|
|
49910
50056
|
if (target === "slot") {
|
|
49911
50057
|
const s2 = doc.slots.find((s3) => s3.id === id);
|
|
@@ -50008,7 +50154,9 @@ ${parts.join("\n")}
|
|
|
50008
50154
|
for (const k2 of kids.get(id) ?? []) stack.push(k2.id);
|
|
50009
50155
|
}
|
|
50010
50156
|
}
|
|
50011
|
-
function evaluate(doc, pose) {
|
|
50157
|
+
function evaluate(doc, pose, modifiers) {
|
|
50158
|
+
pose = resolveControls(doc, pose);
|
|
50159
|
+
if (modifiers) for (const modify of modifiers) pose = modify(new Map(pose));
|
|
50012
50160
|
const skel = { doc, pose, bones: /* @__PURE__ */ new Map(), attachment: /* @__PURE__ */ new Map() };
|
|
50013
50161
|
for (const b2 of boneOrder(doc)) {
|
|
50014
50162
|
const s2 = localOf(doc, pose, b2);
|
|
@@ -50069,10 +50217,43 @@ ${parts.join("\n")}
|
|
|
50069
50217
|
updateSubtree(skel, boneId);
|
|
50070
50218
|
}
|
|
50071
50219
|
var shortest = (deg) => ((deg + 180) % 360 + 360) % 360 - 180;
|
|
50220
|
+
function applyLongIk(skel, c2, tx, ty, mix) {
|
|
50221
|
+
const initial = c2.bones.map((id) => ({ ...skel.bones.get(id) }));
|
|
50222
|
+
const last = c2.bones.at(-1), len = boneOf(skel.doc, last).length;
|
|
50223
|
+
const end = () => apply(skel.bones.get(last).world, len, 0);
|
|
50224
|
+
const tolerance = c2.tolerance ?? 0.05;
|
|
50225
|
+
const root = skel.bones.get(c2.bones[0]).world, tip = end();
|
|
50226
|
+
if (Math.abs((tip[0] - root.tx) * (ty - root.ty) - (tip[1] - root.ty) * (tx - root.tx)) < 1e-7 && Math.hypot(tx - root.tx, ty - root.ty) < Math.hypot(tip[0] - root.tx, tip[1] - root.ty) - tolerance) {
|
|
50227
|
+
skel.bones.get(last).rotation += cnum(skel, "ik", c2.id, "bendPositive", c2.bendPositive) > 0.5 ? 5 : -5;
|
|
50228
|
+
updateSubtree(skel, last);
|
|
50229
|
+
}
|
|
50230
|
+
for (let iter = 0; iter < (c2.iterations ?? 100); iter++) {
|
|
50231
|
+
const e2 = end();
|
|
50232
|
+
if (Math.hypot(e2[0] - tx, e2[1] - ty) <= tolerance) break;
|
|
50233
|
+
for (let i2 = c2.bones.length - 1; i2 >= 0; i2--) {
|
|
50234
|
+
const id = c2.bones[i2], b2 = boneOf(skel.doc, id), st = skel.bones.get(id), w2 = st.world, e3 = end();
|
|
50235
|
+
const angle = wrapRad(Math.atan2(ty - w2.ty, tx - w2.tx) - Math.atan2(e3[1] - w2.ty, e3[0] - w2.tx));
|
|
50236
|
+
const cos = Math.cos(angle), sin = Math.sin(angle);
|
|
50237
|
+
setEffectiveWorld(skel, b2, st, { ...w2, a: cos * w2.a - sin * w2.b, b: sin * w2.a + cos * w2.b, c: cos * w2.c - sin * w2.d, d: sin * w2.c + cos * w2.d });
|
|
50238
|
+
}
|
|
50239
|
+
}
|
|
50240
|
+
if (mix < 1) {
|
|
50241
|
+
c2.bones.forEach((id, i2) => {
|
|
50242
|
+
const st = skel.bones.get(id), from = initial[i2];
|
|
50243
|
+
for (const p2 of ["rotation", "shearX", "shearY"]) st[p2] = from[p2] + shortest(st[p2] - from[p2]) * mix;
|
|
50244
|
+
for (const p2 of ["x", "y", "scaleX", "scaleY"]) st[p2] = from[p2] + (st[p2] - from[p2]) * mix;
|
|
50245
|
+
});
|
|
50246
|
+
updateSubtree(skel, c2.bones[0]);
|
|
50247
|
+
}
|
|
50248
|
+
}
|
|
50072
50249
|
function applyIk(skel, c2) {
|
|
50073
50250
|
const mix = cnum(skel, "ik", c2.id, "mix", c2.mix);
|
|
50074
50251
|
if (mix <= 0) return;
|
|
50075
50252
|
const target = skel.bones.get(c2.target).world;
|
|
50253
|
+
if (c2.bones.length > 2) {
|
|
50254
|
+
applyLongIk(skel, c2, target.tx, target.ty, mix);
|
|
50255
|
+
return;
|
|
50256
|
+
}
|
|
50076
50257
|
const bendDir = cnum(skel, "ik", c2.id, "bendPositive", c2.bendPositive) > 0.5 ? 1 : -1;
|
|
50077
50258
|
const compress = cnum(skel, "ik", c2.id, "compress", c2.compress) > 0.5, stretch = cnum(skel, "ik", c2.id, "stretch", c2.stretch) > 0.5;
|
|
50078
50259
|
let softness = cnum(skel, "ik", c2.id, "softness", c2.softness);
|
|
@@ -50207,6 +50388,7 @@ ${parts.join("\n")}
|
|
|
50207
50388
|
const mixRotate = cnum(skel, "transform", c2.id, "mixRotate", c2.mixRotate), mixX = cnum(skel, "transform", c2.id, "mixX", c2.mixX), mixY = cnum(skel, "transform", c2.id, "mixY", c2.mixY);
|
|
50208
50389
|
const mixScaleX = cnum(skel, "transform", c2.id, "mixScaleX", c2.mixScaleX), mixScaleY = cnum(skel, "transform", c2.id, "mixScaleY", c2.mixScaleY), mixShearY = cnum(skel, "transform", c2.id, "mixShearY", c2.mixShearY);
|
|
50209
50390
|
if (!mixRotate && !mixX && !mixY && !mixScaleX && !mixScaleY && !mixShearY) return;
|
|
50391
|
+
c2 = { ...c2, ...Object.fromEntries(["x", "y", "rotation", "scaleX", "scaleY", "shearY"].map((p2) => [p2, cnum(skel, "transform", c2.id, p2, c2[p2])])) };
|
|
50210
50392
|
const target = skel.bones.get(c2.target), tw = target.world;
|
|
50211
50393
|
const offsetRotation = c2.rotation * DEG2, offsetShearY = c2.shearY * DEG2;
|
|
50212
50394
|
for (const id of c2.bones) {
|
|
@@ -50534,6 +50716,7 @@ ${parts.join("\n")}
|
|
|
50534
50716
|
var AnimationState = class {
|
|
50535
50717
|
constructor(sink, opts = {}) {
|
|
50536
50718
|
this.sink = sink;
|
|
50719
|
+
this.opts = opts;
|
|
50537
50720
|
this.defaultMix = opts.mix ?? 0;
|
|
50538
50721
|
}
|
|
50539
50722
|
onEvent;
|
|
@@ -50558,11 +50741,18 @@ ${parts.join("\n")}
|
|
|
50558
50741
|
}
|
|
50559
50742
|
channel(id, loop, priority = 0) {
|
|
50560
50743
|
const anim = this.sink.doc.animations.find((a2) => a2.id === id);
|
|
50561
|
-
if (!anim)
|
|
50744
|
+
if (!anim) {
|
|
50745
|
+
const message = `unknown animation "${id}"; available: ${this.sink.doc.animations.map((a2) => a2.id).join(", ")}`;
|
|
50746
|
+
if (this.opts.missingAnimation === "throw") throw new Error(message);
|
|
50747
|
+
(this.opts.onWarning ?? console.warn)(message);
|
|
50748
|
+
return void 0;
|
|
50749
|
+
}
|
|
50562
50750
|
return { anim, time: 0, loop: loop ?? anim.loop, done: false, priority, fresh: true };
|
|
50563
50751
|
}
|
|
50564
50752
|
setBase(id, opts = {}) {
|
|
50565
|
-
|
|
50753
|
+
const next = id === void 0 ? void 0 : this.channel(id);
|
|
50754
|
+
if (id !== void 0 && !next) return;
|
|
50755
|
+
this.base = next;
|
|
50566
50756
|
if (!this.main || this.main.done) {
|
|
50567
50757
|
this.main = void 0;
|
|
50568
50758
|
this.beginMix(opts.mix);
|
|
@@ -50571,6 +50761,16 @@ ${parts.join("\n")}
|
|
|
50571
50761
|
}
|
|
50572
50762
|
play(id, opts = {}) {
|
|
50573
50763
|
const ch = this.channel(id, opts.loop, opts.priority ?? 0);
|
|
50764
|
+
if (!ch) {
|
|
50765
|
+
this.main?.settle?.("interrupted");
|
|
50766
|
+
for (const queued of this.queue) queued.settle?.("dropped");
|
|
50767
|
+
this.main = void 0;
|
|
50768
|
+
this.queue = [];
|
|
50769
|
+
this.beginMix(opts.mix);
|
|
50770
|
+
this.update(0);
|
|
50771
|
+
opts.onComplete?.("dropped");
|
|
50772
|
+
return Promise.resolve("dropped");
|
|
50773
|
+
}
|
|
50574
50774
|
const promise2 = new Promise((resolve) => {
|
|
50575
50775
|
ch.settle = (r2) => {
|
|
50576
50776
|
ch.settle = void 0;
|
|
@@ -50591,7 +50791,10 @@ ${parts.join("\n")}
|
|
|
50591
50791
|
/** Independent loop on top of the shown pose; `undefined` removes it. */
|
|
50592
50792
|
setOverlay(name, id) {
|
|
50593
50793
|
if (id === void 0) this.overlays.delete(name);
|
|
50594
|
-
else
|
|
50794
|
+
else {
|
|
50795
|
+
const ch = this.channel(id);
|
|
50796
|
+
if (ch) this.overlays.set(name, ch);
|
|
50797
|
+
}
|
|
50595
50798
|
}
|
|
50596
50799
|
/** Clear everything and show the setup pose. Pending plays resolve as "stopped". */
|
|
50597
50800
|
stop() {
|
|
@@ -50676,6 +50879,7 @@ ${parts.join("\n")}
|
|
|
50676
50879
|
// src/rig-runtime.ts
|
|
50677
50880
|
var DEG3 = Math.PI / 180;
|
|
50678
50881
|
var MESH_GRID = 9;
|
|
50882
|
+
var GHOST_ALPHA = 0.5;
|
|
50679
50883
|
async function createTextures(doc, loadSource) {
|
|
50680
50884
|
const bySrc = /* @__PURE__ */ new Map(), out2 = /* @__PURE__ */ new Map();
|
|
50681
50885
|
for (const a2 of doc.assets) {
|
|
@@ -50715,7 +50919,7 @@ ${parts.join("\n")}
|
|
|
50715
50919
|
var rgbOf = (c2) => Math.round(c2[0] * 255) << 16 | Math.round(c2[1] * 255) << 8 | Math.round(c2[2] * 255);
|
|
50716
50920
|
var sameNumbers = (a2, b2) => a2 === b2 || a2.length === b2.length && a2.every((v2, i2) => v2 === b2[i2]);
|
|
50717
50921
|
var RigPlayer = class {
|
|
50718
|
-
/**
|
|
50922
|
+
/** Default crossfade is 0.18 seconds; explicit mix: 0 requests a hard cut. */
|
|
50719
50923
|
constructor(doc, textures, opts = {}) {
|
|
50720
50924
|
this.doc = doc;
|
|
50721
50925
|
parse2(doc);
|
|
@@ -50754,17 +50958,63 @@ ${parts.join("\n")}
|
|
|
50754
50958
|
this.items.push(item);
|
|
50755
50959
|
this.view.addChild(item.node);
|
|
50756
50960
|
}
|
|
50757
|
-
this.state = new AnimationState(this, { mix: opts.mix ?? 0 });
|
|
50961
|
+
this.state = new AnimationState(this, { ...opts, mix: opts.mix ?? 0.18 });
|
|
50758
50962
|
this.setPose(/* @__PURE__ */ new Map());
|
|
50759
50963
|
}
|
|
50964
|
+
inputPose = /* @__PURE__ */ new Map();
|
|
50965
|
+
controlOverrides = /* @__PURE__ */ new Map();
|
|
50966
|
+
/** Manual inputs override animated controls until resetControls; values are clamped to declared ranges. */
|
|
50967
|
+
setControls(values) {
|
|
50968
|
+
this.controlOverrides = controlPose(this.doc, values);
|
|
50969
|
+
this.setPose(this.inputPose);
|
|
50970
|
+
}
|
|
50971
|
+
resetControls() {
|
|
50972
|
+
this.controlOverrides.clear();
|
|
50973
|
+
this.setPose(this.inputPose);
|
|
50974
|
+
}
|
|
50760
50975
|
view = new Container();
|
|
50761
50976
|
state;
|
|
50762
50977
|
items = [];
|
|
50978
|
+
beforePose = /* @__PURE__ */ new Set();
|
|
50979
|
+
afterPose = /* @__PURE__ */ new Set();
|
|
50980
|
+
clipPoints = /* @__PURE__ */ new Map();
|
|
50763
50981
|
skel;
|
|
50764
50982
|
textures;
|
|
50765
50983
|
pages = /* @__PURE__ */ new Map();
|
|
50766
50984
|
/** slots the editor hides; honoured by setPose */
|
|
50767
50985
|
hidden = /* @__PURE__ */ new Set();
|
|
50986
|
+
/** slots the editor has selected; setPose draws them at GHOST_ALPHA at least */
|
|
50987
|
+
ghosts = /* @__PURE__ */ new Set();
|
|
50988
|
+
clipGraphics = /* @__PURE__ */ new Map();
|
|
50989
|
+
/** Read-only render handles for in-page tools. Nodes remain owned by the player. */
|
|
50990
|
+
get renderItems() {
|
|
50991
|
+
return this.items;
|
|
50992
|
+
}
|
|
50993
|
+
/** Current document-space clipping polygons, keyed by path attachment id. */
|
|
50994
|
+
get clipPolygons() {
|
|
50995
|
+
return this.clipPoints;
|
|
50996
|
+
}
|
|
50997
|
+
/**
|
|
50998
|
+
* Modify resolved control outputs before skeleton evaluation, constraints and skinning.
|
|
50999
|
+
* Callbacks run in registration order, each with its own map. Change control inputs via setControls.
|
|
51000
|
+
*/
|
|
51001
|
+
onBeforePose(callback) {
|
|
51002
|
+
this.beforePose.add(callback);
|
|
51003
|
+
return () => {
|
|
51004
|
+
this.beforePose.delete(callback);
|
|
51005
|
+
};
|
|
51006
|
+
}
|
|
51007
|
+
/** Subscribe after the base pose has been rebuilt. Return value removes the callback. */
|
|
51008
|
+
onAfterPose(callback) {
|
|
51009
|
+
this.afterPose.add(callback);
|
|
51010
|
+
return () => {
|
|
51011
|
+
this.afterPose.delete(callback);
|
|
51012
|
+
};
|
|
51013
|
+
}
|
|
51014
|
+
/** Rebuild the current pose without advancing playback; useful for reversible overlays. */
|
|
51015
|
+
refreshPose() {
|
|
51016
|
+
this.setPose(this.inputPose);
|
|
51017
|
+
}
|
|
50768
51018
|
/** whole atlas page as a plain texture (identity uv mapping) for skinned meshes */
|
|
50769
51019
|
pageTexture(tex) {
|
|
50770
51020
|
let page = this.pages.get(tex.source);
|
|
@@ -50776,7 +51026,7 @@ ${parts.join("\n")}
|
|
|
50776
51026
|
this.state.onEvent = opts.onEvent;
|
|
50777
51027
|
return this.state.play(animId, {
|
|
50778
51028
|
loop: opts.loop,
|
|
50779
|
-
mix: opts.mix
|
|
51029
|
+
mix: opts.mix,
|
|
50780
51030
|
ifBusy: "interrupt",
|
|
50781
51031
|
onComplete: (r2) => {
|
|
50782
51032
|
if (r2 === "completed") opts.onComplete?.();
|
|
@@ -50805,6 +51055,10 @@ ${parts.join("\n")}
|
|
|
50805
51055
|
if (visible) this.hidden.delete(slotId);
|
|
50806
51056
|
else this.hidden.add(slotId);
|
|
50807
51057
|
}
|
|
51058
|
+
/** Editor-only: draw these slots at GHOST_ALPHA at least, whatever the pose says (an empty list clears it). */
|
|
51059
|
+
setGhostSlots(slotIds) {
|
|
51060
|
+
this.ghosts = new Set(slotIds);
|
|
51061
|
+
}
|
|
50808
51062
|
/** Stop playback and immediately restore the complete setup pose. */
|
|
50809
51063
|
stop() {
|
|
50810
51064
|
this.state.stop();
|
|
@@ -50815,13 +51069,39 @@ ${parts.join("\n")}
|
|
|
50815
51069
|
}
|
|
50816
51070
|
/** Apply a pose (rest where silent) to the display objects. */
|
|
50817
51071
|
setPose(pose) {
|
|
50818
|
-
|
|
51072
|
+
this.inputPose = new Map(pose);
|
|
51073
|
+
if (this.controlOverrides.size) pose = new Map([...pose, ...this.controlOverrides]);
|
|
51074
|
+
this.clipPoints.clear();
|
|
51075
|
+
const skel = this.skel = evaluate(this.doc, pose, this.beforePose);
|
|
51076
|
+
pose = skel.pose;
|
|
51077
|
+
const clips = new Set(this.doc.slots.flatMap((s2) => s2.clip ? [s2.clip] : []));
|
|
51078
|
+
for (const [id, g2] of this.clipGraphics) if (!clips.has(id)) {
|
|
51079
|
+
g2.destroy();
|
|
51080
|
+
this.clipGraphics.delete(id);
|
|
51081
|
+
}
|
|
51082
|
+
for (const id of clips) {
|
|
51083
|
+
const att = this.doc.attachments.find((a2) => a2.id === id);
|
|
51084
|
+
if (att?.type !== "path" || !att.closed) continue;
|
|
51085
|
+
let g2 = this.clipGraphics.get(id);
|
|
51086
|
+
if (!g2) {
|
|
51087
|
+
g2 = new Graphics();
|
|
51088
|
+
this.clipGraphics.set(id, g2);
|
|
51089
|
+
this.view.addChild(g2);
|
|
51090
|
+
}
|
|
51091
|
+
const vertices = attachmentWorldVertices(skel, att.slot, att);
|
|
51092
|
+
const n2 = Math.max(32, vertices.length * 4);
|
|
51093
|
+
const points = samplePath(vertices, true, att.lengths, true, Array.from({ length: n2 }, (_, i2) => i2 / n2), true);
|
|
51094
|
+
const polygon = points.flatMap((p2) => [p2.x, p2.y]);
|
|
51095
|
+
this.clipPoints.set(id, polygon);
|
|
51096
|
+
g2.clear().poly(polygon, true).fill(16777215);
|
|
51097
|
+
}
|
|
50819
51098
|
const m2 = new Matrix();
|
|
50820
51099
|
const orderV = pose.get(pk("drawOrder", "order", "order"));
|
|
50821
51100
|
const order = /* @__PURE__ */ new Map();
|
|
50822
51101
|
if (Array.isArray(orderV)) orderV.forEach((id, i2) => order.set(id, i2));
|
|
50823
51102
|
for (const it of this.items) {
|
|
50824
51103
|
const s2 = it.slot, shown = skel.attachment.get(s2.id);
|
|
51104
|
+
it.node.mask = s2.clip ? this.clipGraphics.get(s2.clip) ?? null : null;
|
|
50825
51105
|
if (shown !== it.att || this.hidden.has(s2.id)) {
|
|
50826
51106
|
it.node.visible = false;
|
|
50827
51107
|
continue;
|
|
@@ -50829,10 +51109,12 @@ ${parts.join("\n")}
|
|
|
50829
51109
|
it.node.visible = true;
|
|
50830
51110
|
const colorV = pose.get(pk("slot", s2.id, "color"));
|
|
50831
51111
|
const color = Array.isArray(colorV) && typeof colorV[0] === "number" ? colorV : colorToArray(s2.color);
|
|
50832
|
-
|
|
51112
|
+
const alpha = numOf(pose, pk("slot", s2.id, "alpha"), s2.alpha) * color[3];
|
|
51113
|
+
it.node.alpha = this.ghosts.has(s2.id) ? Math.max(alpha, GHOST_ALPHA) : alpha;
|
|
50833
51114
|
it.node.tint = rgbOf(color);
|
|
50834
51115
|
it.node.zIndex = order.size ? order.get(s2.id) ?? 0 : numOf(pose, pk("slot", s2.id, "z"), s2.z);
|
|
50835
51116
|
if (it.skinned) {
|
|
51117
|
+
it.node.setFromMatrix(m2.identity());
|
|
50836
51118
|
const v2 = attachmentWorldVertices(skel, s2.id, it.att);
|
|
50837
51119
|
const buf = it.skinned.mesh.geometry.getBuffer("aPosition");
|
|
50838
51120
|
buf.data.set(v2);
|
|
@@ -50865,6 +51147,7 @@ ${parts.join("\n")}
|
|
|
50865
51147
|
it.node.scale.y *= h2 / (this.textures.get(att.asset)?.height ?? h2);
|
|
50866
51148
|
}
|
|
50867
51149
|
}
|
|
51150
|
+
for (const callback of this.afterPose) callback(this);
|
|
50868
51151
|
}
|
|
50869
51152
|
/** World-space bone positions — used by editor gizmos and renderPreview overlays */
|
|
50870
51153
|
bonePositions() {
|
|
@@ -50912,7 +51195,7 @@ ${parts.join("\n")}
|
|
|
50912
51195
|
if (!assets[src]) throw new Error(`missing asset data for "${src}"`);
|
|
50913
51196
|
return textureFromDataUrl(assets[src]);
|
|
50914
51197
|
});
|
|
50915
|
-
player = new RigPlayer(doc, textures);
|
|
51198
|
+
player = new RigPlayer(doc, textures, { mix: 0 });
|
|
50916
51199
|
player.view.scale.set(scale);
|
|
50917
51200
|
overlay = new Container();
|
|
50918
51201
|
overlay.scale.set(scale);
|
|
@@ -50957,7 +51240,7 @@ ${parts.join("\n")}
|
|
|
50957
51240
|
};
|
|
50958
51241
|
for (const t2 of opts.times) {
|
|
50959
51242
|
if (opts.animation) {
|
|
50960
|
-
player.play(opts.animation);
|
|
51243
|
+
player.play(opts.animation, { mix: 0 });
|
|
50961
51244
|
player.tick(t2);
|
|
50962
51245
|
} else {
|
|
50963
51246
|
player.stop();
|
|
@@ -50965,7 +51248,21 @@ ${parts.join("\n")}
|
|
|
50965
51248
|
}
|
|
50966
51249
|
if (opts.overlayBones) drawBones();
|
|
50967
51250
|
else clearOverlay();
|
|
50968
|
-
|
|
51251
|
+
if (opts.weightBone) {
|
|
51252
|
+
if (!player.doc.bones.some((b2) => b2.id === opts.weightBone)) throw new Error(`unknown weight bone "${opts.weightBone}"`);
|
|
51253
|
+
const anim = player.doc.animations.find((a2) => a2.id === opts.animation), pose = anim ? poseOf(anim, anim.loop ? t2 % anim.duration : t2) : /* @__PURE__ */ new Map();
|
|
51254
|
+
const skel = evaluate(player.doc, pose), g2 = new Graphics();
|
|
51255
|
+
for (const att of skel.attachment.values()) if (att?.type === "mesh" && att.weights) {
|
|
51256
|
+
const v2 = attachmentWorldVertices(skel, att.slot, att);
|
|
51257
|
+
for (let j2 = 0; j2 < att.triangles.length; j2 += 3) {
|
|
51258
|
+
const ids = att.triangles.slice(j2, j2 + 3);
|
|
51259
|
+
const weight = ids.reduce((sum, i2) => sum + att.weights[i2].filter((w3) => w3.bone === opts.weightBone).reduce((s2, w3) => s2 + w3.w, 0), 0) / 3;
|
|
51260
|
+
g2.poly(ids.flatMap((i2) => [v2[i2 * 2], v2[i2 * 2 + 1]]), true).fill({ color: Math.round(255 * weight) << 16 | Math.round(255 * (1 - weight)), alpha: 0.75 });
|
|
51261
|
+
}
|
|
51262
|
+
}
|
|
51263
|
+
overlay.addChild(g2);
|
|
51264
|
+
}
|
|
51265
|
+
const frame = grab(opts.transparent ? 0 : 1);
|
|
50969
51266
|
const ctx = frame.getContext("2d");
|
|
50970
51267
|
if (opts.onionSkin && prev) {
|
|
50971
51268
|
ctx.globalAlpha = 0.35;
|