@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/runtime.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/rig-runtime.ts
|
|
2
|
-
import { Container, Sprite, Mesh, MeshGeometry, MeshPlane, Texture, Matrix, Rectangle } from "pixi.js";
|
|
2
|
+
import { Container, Sprite, Mesh, MeshGeometry, MeshPlane, Texture, Matrix, Rectangle, Graphics } from "pixi.js";
|
|
3
3
|
|
|
4
4
|
// src/rig-format.ts
|
|
5
5
|
import { z } from "zod";
|
|
@@ -48,7 +48,7 @@ function gridPositions(offsets, w, h, pivot, n, out = new Float32Array(2 * n * n
|
|
|
48
48
|
var ID_RE = /^[a-z][a-z0-9_]*$/;
|
|
49
49
|
var Id = z.string().regex(ID_RE, "snake_case id");
|
|
50
50
|
var Ease = z.union([
|
|
51
|
-
z.enum(["linear", "step", "ease_in", "ease_out", "ease_in_out", "back_out", "elastic_out"]),
|
|
51
|
+
z.enum(["linear", "step", "ease_in", "ease_out", "ease_in_out", "minimum_jerk", "back_out", "elastic_out"]),
|
|
52
52
|
// cubic-bezier control points, same semantics as CSS
|
|
53
53
|
z.object({ bezier: z.tuple([z.number(), z.number(), z.number(), z.number()]) })
|
|
54
54
|
]);
|
|
@@ -80,6 +80,7 @@ var Asset = z.object({
|
|
|
80
80
|
/** where this layer came from — provenance for agents */
|
|
81
81
|
origin: z.object({
|
|
82
82
|
sourceImage: z.string().optional(),
|
|
83
|
+
bboxSpace: z.enum(["source", "document"]).optional(),
|
|
83
84
|
/** bbox in source image: [x, y, w, h] */
|
|
84
85
|
bbox: z.tuple([z.number(), z.number(), z.number(), z.number()]).optional(),
|
|
85
86
|
inpainted: z.boolean().default(false),
|
|
@@ -102,6 +103,8 @@ var Bone = z.object({
|
|
|
102
103
|
var Slot = z.object({
|
|
103
104
|
id: Id,
|
|
104
105
|
bone: Id,
|
|
106
|
+
/** Closed path attachment used as a moving clipping mask. */
|
|
107
|
+
clip: Id.optional(),
|
|
105
108
|
/** active attachment id; undefined = hidden */
|
|
106
109
|
attachment: Id.optional(),
|
|
107
110
|
alpha: z.number().min(0).max(1).default(1),
|
|
@@ -164,6 +167,8 @@ var IkConstraint = z.object({
|
|
|
164
167
|
order: z.number().int().default(0),
|
|
165
168
|
bones: z.array(Id).min(1),
|
|
166
169
|
target: Id,
|
|
170
|
+
iterations: z.number().int().min(1).max(1e3).optional(),
|
|
171
|
+
tolerance: z.number().positive().optional(),
|
|
167
172
|
mix: z.number().default(1),
|
|
168
173
|
softness: z.number().default(0),
|
|
169
174
|
bendPositive: z.boolean().default(true),
|
|
@@ -211,7 +216,7 @@ var BoneProp = z.enum(["x", "y", "rotation", "scaleX", "scaleY", "shearX", "shea
|
|
|
211
216
|
var SlotProp = z.enum(["alpha", "attachment", "z", "color"]);
|
|
212
217
|
var DeformProp = z.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");
|
|
213
218
|
var IkProp = z.enum(["mix", "softness", "bendPositive", "compress", "stretch"]);
|
|
214
|
-
var TransformProp = z.enum(["mixRotate", "mixX", "mixY", "mixScaleX", "mixScaleY", "mixShearY"]);
|
|
219
|
+
var TransformProp = z.enum(["mixRotate", "mixX", "mixY", "mixScaleX", "mixScaleY", "mixShearY", "x", "y", "rotation", "scaleX", "scaleY", "shearY"]);
|
|
215
220
|
var PathProp = z.enum(["position", "spacing", "mixRotate", "mixX", "mixY"]);
|
|
216
221
|
var KeyValue = z.union([z.number(), z.string(), z.null(), z.array(z.number()), z.array(z.string())]);
|
|
217
222
|
var Key = z.object({
|
|
@@ -220,14 +225,16 @@ var Key = z.object({
|
|
|
220
225
|
/** easing INTO the next key */
|
|
221
226
|
ease: Ease.default("ease_in_out")
|
|
222
227
|
});
|
|
228
|
+
var Interpolation = { interpolation: z.enum(["segment", "pchip"]).optional() };
|
|
223
229
|
var Track = z.discriminatedUnion("target", [
|
|
224
|
-
z.object({ target: z.literal("
|
|
225
|
-
z.object({ target: z.literal("
|
|
226
|
-
z.object({ target: z.literal("
|
|
227
|
-
z.object({ target: z.literal("
|
|
228
|
-
z.object({ target: z.literal("
|
|
229
|
-
z.object({ target: z.literal("
|
|
230
|
-
z.object({ target: z.literal("
|
|
230
|
+
z.object({ target: z.literal("control"), id: Id, prop: z.literal("value"), ...Interpolation, keys: z.array(Key).min(1) }),
|
|
231
|
+
z.object({ target: z.literal("bone"), id: Id, prop: BoneProp, ...Interpolation, keys: z.array(Key).min(1) }),
|
|
232
|
+
z.object({ target: z.literal("slot"), id: Id, prop: SlotProp, ...Interpolation, keys: z.array(Key).min(1) }),
|
|
233
|
+
z.object({ target: z.literal("deform"), id: Id, prop: DeformProp, ...Interpolation, keys: z.array(Key).min(1) }),
|
|
234
|
+
z.object({ target: z.literal("ik"), id: Id, prop: IkProp, ...Interpolation, keys: z.array(Key).min(1) }),
|
|
235
|
+
z.object({ target: z.literal("transform"), id: Id, prop: TransformProp, ...Interpolation, keys: z.array(Key).min(1) }),
|
|
236
|
+
z.object({ target: z.literal("path"), id: Id, prop: PathProp, ...Interpolation, keys: z.array(Key).min(1) }),
|
|
237
|
+
z.object({ target: z.literal("drawOrder"), id: Id.default("order"), prop: z.literal("order").default("order"), ...Interpolation, keys: z.array(Key).min(1) })
|
|
231
238
|
]);
|
|
232
239
|
var Event = z.object({
|
|
233
240
|
t: z.number().nonnegative(),
|
|
@@ -243,6 +250,25 @@ var Animation = z.object({
|
|
|
243
250
|
/** if generated from a preset — keep params so the agent can re-tune instead of re-keying */
|
|
244
251
|
preset: z.object({ name: z.string(), params: z.record(z.unknown()) }).optional()
|
|
245
252
|
});
|
|
253
|
+
var RigControl = z.object({
|
|
254
|
+
id: Id,
|
|
255
|
+
label: z.string().optional(),
|
|
256
|
+
min: z.number().finite(),
|
|
257
|
+
max: z.number().finite(),
|
|
258
|
+
default: z.number().finite()
|
|
259
|
+
}).strict();
|
|
260
|
+
var ControlValues = z.array(z.union([z.number().finite(), z.array(z.number().finite()).min(1)])).min(2);
|
|
261
|
+
var ControlChannel = z.discriminatedUnion("target", [
|
|
262
|
+
z.object({ target: z.literal("bone"), id: Id, prop: BoneProp, values: ControlValues }).strict(),
|
|
263
|
+
z.object({ target: z.literal("slot"), id: Id, prop: z.literal("alpha"), values: ControlValues }).strict(),
|
|
264
|
+
z.object({ target: z.literal("deform"), id: Id, prop: z.literal("vertices"), values: ControlValues }).strict()
|
|
265
|
+
]);
|
|
266
|
+
var ControlBinding = z.object({
|
|
267
|
+
id: Id,
|
|
268
|
+
axes: z.array(z.object({ control: Id, keys: z.array(z.number().finite()).min(2).max(32) }).strict()).min(1).max(2),
|
|
269
|
+
/** Flattened grid, first axis varies fastest. Linear / bilinear interpolation. */
|
|
270
|
+
channels: z.array(ControlChannel).min(1)
|
|
271
|
+
}).strict();
|
|
246
272
|
var Reference = z.object({
|
|
247
273
|
src: z.string(),
|
|
248
274
|
opacity: z.number().min(0).max(1).default(0.5),
|
|
@@ -268,7 +294,9 @@ var RigSchema = z.object({
|
|
|
268
294
|
ik: z.array(IkConstraint).default([]),
|
|
269
295
|
transform: z.array(TransformConstraint).default([]),
|
|
270
296
|
path: z.array(PathConstraint).default([]),
|
|
271
|
-
animations: z.array(Animation)
|
|
297
|
+
animations: z.array(Animation),
|
|
298
|
+
controls: z.array(RigControl).optional(),
|
|
299
|
+
controlBindings: z.array(ControlBinding).optional()
|
|
272
300
|
});
|
|
273
301
|
var RigDocument = z.preprocess((input) => {
|
|
274
302
|
const v = input?.version;
|
|
@@ -343,6 +371,8 @@ function validate(doc) {
|
|
|
343
371
|
dup(doc.ik, "ik");
|
|
344
372
|
dup(doc.transform, "transform");
|
|
345
373
|
dup(doc.path, "path");
|
|
374
|
+
dup(doc.controls ?? [], "control");
|
|
375
|
+
dup(doc.controlBindings ?? [], "control binding");
|
|
346
376
|
const bones = new Set(doc.bones.map((b) => b.id));
|
|
347
377
|
const assets = new Map(doc.assets.map((a) => [a.id, a]));
|
|
348
378
|
const slots = new Set(doc.slots.map((s) => s.id));
|
|
@@ -369,6 +399,10 @@ function validate(doc) {
|
|
|
369
399
|
if (a.frame && !a.trim && !a.rotate && (a.frame[2] !== a.width || a.frame[3] !== a.height)) errs.push(`asset "${a.id}": frame size must equal width\xD7height (or declare trim/rotate)`);
|
|
370
400
|
}
|
|
371
401
|
for (const s of doc.slots) {
|
|
402
|
+
if (s.clip) {
|
|
403
|
+
const mask = attachments.get(s.clip);
|
|
404
|
+
if (mask?.type !== "path" || !mask.closed) errs.push(`slot "${s.id}": clip must name a closed path attachment`);
|
|
405
|
+
}
|
|
372
406
|
if (!bones.has(s.bone)) errs.push(`slot "${s.id}": unknown bone "${s.bone}"`);
|
|
373
407
|
if (s.attachment) {
|
|
374
408
|
const a = attachments.get(s.attachment);
|
|
@@ -400,7 +434,8 @@ function validate(doc) {
|
|
|
400
434
|
}
|
|
401
435
|
}
|
|
402
436
|
for (const c of doc.ik) {
|
|
403
|
-
|
|
437
|
+
for (let i = 1; i < c.bones.length; i++) if (doc.bones.find((b) => b.id === c.bones[i])?.parent !== c.bones[i - 1])
|
|
438
|
+
errs.push(`ik "${c.id}": bones must form a contiguous parent-to-child chain`);
|
|
404
439
|
for (const b of c.bones) if (!bones.has(b)) errs.push(`ik "${c.id}": unknown bone "${b}"`);
|
|
405
440
|
if (!bones.has(c.target)) errs.push(`ik "${c.id}": unknown target bone "${c.target}"`);
|
|
406
441
|
}
|
|
@@ -412,13 +447,47 @@ function validate(doc) {
|
|
|
412
447
|
for (const b of c.bones) if (!bones.has(b)) errs.push(`path "${c.id}": unknown bone "${b}"`);
|
|
413
448
|
if (!slots.has(c.target)) errs.push(`path "${c.id}": unknown target slot "${c.target}"`);
|
|
414
449
|
}
|
|
450
|
+
const controls = new Map((doc.controls ?? []).map((c) => [c.id, c]));
|
|
451
|
+
const driven = /* @__PURE__ */ new Set();
|
|
452
|
+
for (const c of controls.values()) if (!(c.min < c.max && c.default >= c.min && c.default <= c.max))
|
|
453
|
+
errs.push(`control "${c.id}": require min < max and default within range`);
|
|
454
|
+
for (const b of doc.controlBindings ?? []) {
|
|
455
|
+
const prefix = `control binding "${b.id}"`;
|
|
456
|
+
if (new Set(b.axes.map((a) => a.control)).size !== b.axes.length) errs.push(`${prefix}: axes must use different controls`);
|
|
457
|
+
for (const axis of b.axes) {
|
|
458
|
+
const c = controls.get(axis.control);
|
|
459
|
+
if (!c) errs.push(`${prefix}: unknown control "${axis.control}"`);
|
|
460
|
+
else if (axis.keys[0] !== c.min || axis.keys.at(-1) !== c.max) errs.push(`${prefix}: keys must span the control's full range`);
|
|
461
|
+
if (axis.keys.some((v, i) => i > 0 && v <= axis.keys[i - 1])) errs.push(`${prefix}: keys must be strictly increasing`);
|
|
462
|
+
}
|
|
463
|
+
const count = b.axes.reduce((n, a) => n * a.keys.length, 1);
|
|
464
|
+
for (const ch of b.channels) {
|
|
465
|
+
const key = `${ch.target}.${ch.id}.${ch.prop}`;
|
|
466
|
+
if (driven.has(key)) errs.push(`${prefix}: channel ${key} already owned by a binding`);
|
|
467
|
+
driven.add(key);
|
|
468
|
+
if (ch.values.length !== count) errs.push(`${prefix}: ${key} needs ${count} grid values`);
|
|
469
|
+
if (ch.target === "deform") {
|
|
470
|
+
const att = attachments.get(ch.id);
|
|
471
|
+
if (!att || att.type === "region") errs.push(`${prefix}: vertices need a mesh or path attachment`);
|
|
472
|
+
else {
|
|
473
|
+
const n = att.weights ? att.weights.reduce((s, a) => s + a.length * 2, 0) : att.vertices.length;
|
|
474
|
+
if (ch.values.some((v) => !Array.isArray(v) || v.length !== n)) errs.push(`${prefix}: ${key} needs arrays of ${n} offsets`);
|
|
475
|
+
}
|
|
476
|
+
} else {
|
|
477
|
+
if (!(ch.target === "bone" ? bones : slots).has(ch.id)) errs.push(`${prefix}: unknown ${ch.target} "${ch.id}"`);
|
|
478
|
+
if (ch.values.some((v) => typeof v !== "number")) errs.push(`${prefix}: ${key} needs numeric values`);
|
|
479
|
+
if (ch.target === "slot" && ch.values.some((v) => typeof v === "number" && (v < 0 || v > 1))) errs.push(`${prefix}: alpha must be in 0..1`);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
415
483
|
for (const a of doc.animations) {
|
|
416
484
|
const tracks = /* @__PURE__ */ new Set();
|
|
417
485
|
for (const t of a.tracks) {
|
|
418
486
|
const tid = trackId(t);
|
|
419
487
|
if (tracks.has(tid)) errs.push(`animation "${a.id}": duplicate track ${tid}`);
|
|
420
488
|
tracks.add(tid);
|
|
421
|
-
|
|
489
|
+
if (driven.has(tid)) errs.push(`animation "${a.id}": ${tid} is controlled by a binding; animate its control instead`);
|
|
490
|
+
const known = t.target === "bone" ? bones.has(t.id) : t.target === "slot" ? slots.has(t.id) : t.target === "deform" ? attachments.has(t.id) : t.target === "ik" ? iks.has(t.id) : t.target === "transform" ? transforms.has(t.id) : t.target === "path" ? paths.has(t.id) : t.target === "control" ? controls.has(t.id) : true;
|
|
422
491
|
if (!known) errs.push(`animation "${a.id}": unknown ${t.target} "${t.id}"`);
|
|
423
492
|
const bound = t.target === "deform" ? DEFORM_BOUNDS[t.prop] : void 0;
|
|
424
493
|
const att = t.target === "deform" ? attachments.get(t.id) : void 0;
|
|
@@ -426,6 +495,10 @@ function validate(doc) {
|
|
|
426
495
|
for (const k of t.keys) {
|
|
427
496
|
if (k.t <= prev && prev >= 0) errs.push(`animation "${a.id}" ${tid}: keys not strictly increasing`);
|
|
428
497
|
if (k.t > a.duration) errs.push(`animation "${a.id}" ${tid}: key at ${k.t}s exceeds duration`);
|
|
498
|
+
if (t.target === "control") {
|
|
499
|
+
const c = controls.get(t.id);
|
|
500
|
+
if (typeof k.v !== "number" || !Number.isFinite(k.v) || c && (k.v < c.min || k.v > c.max)) errs.push(`animation "${a.id}" ${tid}: control key outside its finite range`);
|
|
501
|
+
}
|
|
429
502
|
if (t.target === "slot" && t.prop === "attachment") {
|
|
430
503
|
if (k.v !== null && typeof k.v !== "string") errs.push(`animation "${a.id}" ${tid}: attachment key must be an attachment id or null`);
|
|
431
504
|
else if (typeof k.v === "string") {
|
|
@@ -464,6 +537,52 @@ function parse(input) {
|
|
|
464
537
|
return doc;
|
|
465
538
|
}
|
|
466
539
|
|
|
540
|
+
// src/rig-controls.ts
|
|
541
|
+
function controlPose(doc, values) {
|
|
542
|
+
const out = /* @__PURE__ */ new Map();
|
|
543
|
+
for (const [id, value] of Object.entries(values)) {
|
|
544
|
+
const c = doc.controls?.find((c2) => c2.id === id);
|
|
545
|
+
if (!c) throw new Error(`unknown control "${id}"`);
|
|
546
|
+
if (!Number.isFinite(value)) throw new Error(`control "${id}" must be finite`);
|
|
547
|
+
out.set(`control:${id}:value`, Math.max(c.min, Math.min(c.max, value)));
|
|
548
|
+
}
|
|
549
|
+
return out;
|
|
550
|
+
}
|
|
551
|
+
function bracket(keys, value) {
|
|
552
|
+
let i = 0;
|
|
553
|
+
while (i < keys.length - 2 && value > keys[i + 1]) i++;
|
|
554
|
+
return [i, Math.max(0, Math.min(1, (value - keys[i]) / (keys[i + 1] - keys[i])))];
|
|
555
|
+
}
|
|
556
|
+
function sampleBinding(binding, values) {
|
|
557
|
+
const [x, u] = bracket(binding.axes[0].keys, values[0]);
|
|
558
|
+
const [y, v] = binding.axes[1] ? bracket(binding.axes[1].keys, values[1]) : [0, 0];
|
|
559
|
+
const width = binding.axes[0].keys.length, a = y * width + x;
|
|
560
|
+
const mix = (a2, b, u2) => a2 + (b - a2) * u2;
|
|
561
|
+
return binding.channels.map((ch) => {
|
|
562
|
+
const read = (i, j) => j === void 0 ? ch.values[i] : ch.values[i][j];
|
|
563
|
+
const at = (j) => {
|
|
564
|
+
const top = mix(read(a, j), read(a + 1, j), u);
|
|
565
|
+
return binding.axes[1] ? mix(top, mix(read(a + width, j), read(a + width + 1, j), u), v) : top;
|
|
566
|
+
};
|
|
567
|
+
return Array.isArray(ch.values[0]) ? ch.values[0].map((_, j) => at(j)) : at();
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
function resolveControls(doc, input) {
|
|
571
|
+
if (!doc.controlBindings?.length) return input;
|
|
572
|
+
const out = new Map(input), controls = new Map(doc.controls?.map((c) => [c.id, c]));
|
|
573
|
+
for (const b of doc.controlBindings) {
|
|
574
|
+
const values = b.axes.map((axis) => {
|
|
575
|
+
const c = controls.get(axis.control);
|
|
576
|
+
const value = input.get(`control:${c.id}:value`) ?? c.default;
|
|
577
|
+
if (typeof value !== "number" || !Number.isFinite(value)) throw new Error(`control "${c.id}" must be finite`);
|
|
578
|
+
return Math.max(c.min, Math.min(c.max, value));
|
|
579
|
+
});
|
|
580
|
+
const sampled = sampleBinding(b, values);
|
|
581
|
+
b.channels.forEach((ch, i) => out.set(`${ch.target}:${ch.id}:${ch.prop}`, sampled[i]));
|
|
582
|
+
}
|
|
583
|
+
return out;
|
|
584
|
+
}
|
|
585
|
+
|
|
467
586
|
// src/rig-anim.ts
|
|
468
587
|
var DEG2 = Math.PI / 180;
|
|
469
588
|
var named = {
|
|
@@ -472,6 +591,7 @@ var named = {
|
|
|
472
591
|
ease_in: (t) => t * t,
|
|
473
592
|
ease_out: (t) => 1 - (1 - t) * (1 - t),
|
|
474
593
|
ease_in_out: (t) => t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2,
|
|
594
|
+
minimum_jerk: (t) => t * t * t * (10 + t * (-15 + 6 * t)),
|
|
475
595
|
back_out: (t) => 1 + 2.70158 * (t - 1) ** 3 + 1.70158 * (t - 1) ** 2,
|
|
476
596
|
elastic_out: (t) => t === 0 ? 0 : t === 1 ? 1 : 2 ** (-10 * t) * Math.sin((t * 10 - 0.75) * (2 * Math.PI / 3)) + 1
|
|
477
597
|
};
|
|
@@ -503,7 +623,25 @@ function ease(spec) {
|
|
|
503
623
|
return f;
|
|
504
624
|
}
|
|
505
625
|
var pk = (target, id, prop) => `${target}:${id}:${prop}`;
|
|
506
|
-
function
|
|
626
|
+
function smoothValue(track, i, t, component, loop) {
|
|
627
|
+
const k = track.keys, n = k.length;
|
|
628
|
+
const v = (j) => component === void 0 ? k[j].v : k[j].v[component];
|
|
629
|
+
const h = (j) => k[j + 1].t - k[j].t;
|
|
630
|
+
const d = (j) => (v(j + 1) - v(j)) / h(j);
|
|
631
|
+
const harmonic = (a, b, h0, h1) => a * b <= 0 ? 0 : 3 * (h0 + h1) / ((2 * h1 + h0) / a + (h1 + 2 * h0) / b);
|
|
632
|
+
const tangent = (j) => {
|
|
633
|
+
if (j === 0 || j === n - 1) {
|
|
634
|
+
if (loop && n > 2 && v(0) === v(n - 1) && k[0].ease !== "step" && k[n - 2].ease !== "step")
|
|
635
|
+
return harmonic(d(n - 2), d(0), h(n - 2), h(0));
|
|
636
|
+
return 0;
|
|
637
|
+
}
|
|
638
|
+
if (k[j - 1].ease === "step" || k[j].ease === "step") return 0;
|
|
639
|
+
return harmonic(d(j - 1), d(j), h(j - 1), h(j));
|
|
640
|
+
};
|
|
641
|
+
const u = (t - k[i].t) / h(i), u2 = u * u, u3 = u2 * u;
|
|
642
|
+
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);
|
|
643
|
+
}
|
|
644
|
+
function sample(track, t, loop = false) {
|
|
507
645
|
const keys = track.keys;
|
|
508
646
|
if (t <= keys[0].t) return keys[0].v;
|
|
509
647
|
const last = keys[keys.length - 1];
|
|
@@ -511,36 +649,44 @@ function sample(track, t) {
|
|
|
511
649
|
let i = 0;
|
|
512
650
|
while (keys[i + 1].t <= t) i++;
|
|
513
651
|
const a = keys[i], b = keys[i + 1];
|
|
652
|
+
if (a.ease === "step") return a.v;
|
|
514
653
|
if (typeof a.v === "number" && typeof b.v === "number") {
|
|
654
|
+
if (track.interpolation === "pchip") return smoothValue(track, i, t, void 0, loop);
|
|
515
655
|
const u = ease(a.ease)((t - a.t) / (b.t - a.t));
|
|
516
656
|
return a.v + (b.v - a.v) * u;
|
|
517
657
|
}
|
|
518
658
|
if (Array.isArray(a.v) && Array.isArray(b.v) && typeof a.v[0] === "number") {
|
|
659
|
+
if (track.interpolation === "pchip") return a.v.map((_, j) => smoothValue(track, i, t, j, loop));
|
|
519
660
|
const u = ease(a.ease)((t - a.t) / (b.t - a.t)), av = a.v, bv = b.v;
|
|
520
661
|
return av.map((v, k) => v + ((bv[k] ?? v) - v) * u);
|
|
521
662
|
}
|
|
522
663
|
return a.v;
|
|
523
664
|
}
|
|
524
665
|
function poseOf(anim, t, out = /* @__PURE__ */ new Map()) {
|
|
525
|
-
for (const tr of anim.tracks) out.set(pk(tr.target, tr.id, tr.prop), sample(tr, t));
|
|
666
|
+
for (const tr of anim.tracks) out.set(pk(tr.target, tr.id, tr.prop), sample(tr, t, anim.loop && tr.keys[0].t === 0 && tr.keys.at(-1).t === anim.duration));
|
|
526
667
|
return out;
|
|
527
668
|
}
|
|
528
669
|
function blendPoses(from, to, w, restOf) {
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
670
|
+
if (w >= 1) return new Map(to);
|
|
671
|
+
const out = /* @__PURE__ */ new Map();
|
|
672
|
+
for (const k of /* @__PURE__ */ new Set([...from.keys(), ...to.keys()])) {
|
|
673
|
+
const f = from.has(k) ? from.get(k) : restOf(k);
|
|
674
|
+
const cur = to.has(k) ? to.get(k) : restOf(k);
|
|
675
|
+
if (typeof f === "number" && !Array.isArray(cur)) {
|
|
533
676
|
const target = typeof cur === "number" ? cur : restOf(k);
|
|
534
677
|
out.set(k, f + (target - f) * w);
|
|
535
678
|
} else if (Array.isArray(f) && typeof f[0] === "number") {
|
|
536
679
|
const fv = f, tv = Array.isArray(cur) && typeof cur[0] === "number" ? cur : fv.map(() => 0);
|
|
537
680
|
out.set(k, fv.map((v, i) => v + ((tv[i] ?? 0) - v) * w));
|
|
538
|
-
} else if (cur
|
|
681
|
+
} else if (Array.isArray(cur) && typeof cur[0] === "number" && typeof f !== "string") {
|
|
682
|
+
out.set(k, cur.map((v) => v * w));
|
|
683
|
+
} else out.set(k, f ?? null);
|
|
539
684
|
}
|
|
540
685
|
return out;
|
|
541
686
|
}
|
|
542
687
|
function restValue(doc, key) {
|
|
543
688
|
const [target, id, prop] = key.split(":");
|
|
689
|
+
if (target === "control") return doc.controls?.find((c) => c.id === id)?.default ?? 0;
|
|
544
690
|
if (target === "bone") return doc.bones.find((b) => b.id === id).transform[prop];
|
|
545
691
|
if (target === "slot") {
|
|
546
692
|
const s = doc.slots.find((s2) => s2.id === id);
|
|
@@ -643,7 +789,9 @@ function updateSubtree(skel, root) {
|
|
|
643
789
|
for (const k of kids.get(id) ?? []) stack.push(k.id);
|
|
644
790
|
}
|
|
645
791
|
}
|
|
646
|
-
function evaluate(doc, pose) {
|
|
792
|
+
function evaluate(doc, pose, modifiers) {
|
|
793
|
+
pose = resolveControls(doc, pose);
|
|
794
|
+
if (modifiers) for (const modify of modifiers) pose = modify(new Map(pose));
|
|
647
795
|
const skel = { doc, pose, bones: /* @__PURE__ */ new Map(), attachment: /* @__PURE__ */ new Map() };
|
|
648
796
|
for (const b of boneOrder(doc)) {
|
|
649
797
|
const s = localOf(doc, pose, b);
|
|
@@ -704,10 +852,43 @@ function aimAt(skel, boneId, tx, ty, mix, compress = false, stretch = false, uni
|
|
|
704
852
|
updateSubtree(skel, boneId);
|
|
705
853
|
}
|
|
706
854
|
var shortest = (deg) => ((deg + 180) % 360 + 360) % 360 - 180;
|
|
855
|
+
function applyLongIk(skel, c, tx, ty, mix) {
|
|
856
|
+
const initial = c.bones.map((id) => ({ ...skel.bones.get(id) }));
|
|
857
|
+
const last = c.bones.at(-1), len = boneOf(skel.doc, last).length;
|
|
858
|
+
const end = () => apply(skel.bones.get(last).world, len, 0);
|
|
859
|
+
const tolerance = c.tolerance ?? 0.05;
|
|
860
|
+
const root = skel.bones.get(c.bones[0]).world, tip = end();
|
|
861
|
+
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) {
|
|
862
|
+
skel.bones.get(last).rotation += cnum(skel, "ik", c.id, "bendPositive", c.bendPositive) > 0.5 ? 5 : -5;
|
|
863
|
+
updateSubtree(skel, last);
|
|
864
|
+
}
|
|
865
|
+
for (let iter = 0; iter < (c.iterations ?? 100); iter++) {
|
|
866
|
+
const e = end();
|
|
867
|
+
if (Math.hypot(e[0] - tx, e[1] - ty) <= tolerance) break;
|
|
868
|
+
for (let i = c.bones.length - 1; i >= 0; i--) {
|
|
869
|
+
const id = c.bones[i], b = boneOf(skel.doc, id), st = skel.bones.get(id), w = st.world, e2 = end();
|
|
870
|
+
const angle = wrapRad(Math.atan2(ty - w.ty, tx - w.tx) - Math.atan2(e2[1] - w.ty, e2[0] - w.tx));
|
|
871
|
+
const cos = Math.cos(angle), sin = Math.sin(angle);
|
|
872
|
+
setEffectiveWorld(skel, b, st, { ...w, a: cos * w.a - sin * w.b, b: sin * w.a + cos * w.b, c: cos * w.c - sin * w.d, d: sin * w.c + cos * w.d });
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
if (mix < 1) {
|
|
876
|
+
c.bones.forEach((id, i) => {
|
|
877
|
+
const st = skel.bones.get(id), from = initial[i];
|
|
878
|
+
for (const p of ["rotation", "shearX", "shearY"]) st[p] = from[p] + shortest(st[p] - from[p]) * mix;
|
|
879
|
+
for (const p of ["x", "y", "scaleX", "scaleY"]) st[p] = from[p] + (st[p] - from[p]) * mix;
|
|
880
|
+
});
|
|
881
|
+
updateSubtree(skel, c.bones[0]);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
707
884
|
function applyIk(skel, c) {
|
|
708
885
|
const mix = cnum(skel, "ik", c.id, "mix", c.mix);
|
|
709
886
|
if (mix <= 0) return;
|
|
710
887
|
const target = skel.bones.get(c.target).world;
|
|
888
|
+
if (c.bones.length > 2) {
|
|
889
|
+
applyLongIk(skel, c, target.tx, target.ty, mix);
|
|
890
|
+
return;
|
|
891
|
+
}
|
|
711
892
|
const bendDir = cnum(skel, "ik", c.id, "bendPositive", c.bendPositive) > 0.5 ? 1 : -1;
|
|
712
893
|
const compress = cnum(skel, "ik", c.id, "compress", c.compress) > 0.5, stretch = cnum(skel, "ik", c.id, "stretch", c.stretch) > 0.5;
|
|
713
894
|
let softness = cnum(skel, "ik", c.id, "softness", c.softness);
|
|
@@ -842,6 +1023,7 @@ function applyTransformConstraint(skel, c) {
|
|
|
842
1023
|
const mixRotate = cnum(skel, "transform", c.id, "mixRotate", c.mixRotate), mixX = cnum(skel, "transform", c.id, "mixX", c.mixX), mixY = cnum(skel, "transform", c.id, "mixY", c.mixY);
|
|
843
1024
|
const mixScaleX = cnum(skel, "transform", c.id, "mixScaleX", c.mixScaleX), mixScaleY = cnum(skel, "transform", c.id, "mixScaleY", c.mixScaleY), mixShearY = cnum(skel, "transform", c.id, "mixShearY", c.mixShearY);
|
|
844
1025
|
if (!mixRotate && !mixX && !mixY && !mixScaleX && !mixScaleY && !mixShearY) return;
|
|
1026
|
+
c = { ...c, ...Object.fromEntries(["x", "y", "rotation", "scaleX", "scaleY", "shearY"].map((p) => [p, cnum(skel, "transform", c.id, p, c[p])])) };
|
|
845
1027
|
const target = skel.bones.get(c.target), tw = target.world;
|
|
846
1028
|
const offsetRotation = c.rotation * DEG2, offsetShearY = c.shearY * DEG2;
|
|
847
1029
|
for (const id of c.bones) {
|
|
@@ -1169,6 +1351,7 @@ function regionSize(doc, att) {
|
|
|
1169
1351
|
var AnimationState = class {
|
|
1170
1352
|
constructor(sink, opts = {}) {
|
|
1171
1353
|
this.sink = sink;
|
|
1354
|
+
this.opts = opts;
|
|
1172
1355
|
this.defaultMix = opts.mix ?? 0;
|
|
1173
1356
|
}
|
|
1174
1357
|
onEvent;
|
|
@@ -1193,11 +1376,18 @@ var AnimationState = class {
|
|
|
1193
1376
|
}
|
|
1194
1377
|
channel(id, loop, priority = 0) {
|
|
1195
1378
|
const anim = this.sink.doc.animations.find((a) => a.id === id);
|
|
1196
|
-
if (!anim)
|
|
1379
|
+
if (!anim) {
|
|
1380
|
+
const message = `unknown animation "${id}"; available: ${this.sink.doc.animations.map((a) => a.id).join(", ")}`;
|
|
1381
|
+
if (this.opts.missingAnimation === "throw") throw new Error(message);
|
|
1382
|
+
(this.opts.onWarning ?? console.warn)(message);
|
|
1383
|
+
return void 0;
|
|
1384
|
+
}
|
|
1197
1385
|
return { anim, time: 0, loop: loop ?? anim.loop, done: false, priority, fresh: true };
|
|
1198
1386
|
}
|
|
1199
1387
|
setBase(id, opts = {}) {
|
|
1200
|
-
|
|
1388
|
+
const next = id === void 0 ? void 0 : this.channel(id);
|
|
1389
|
+
if (id !== void 0 && !next) return;
|
|
1390
|
+
this.base = next;
|
|
1201
1391
|
if (!this.main || this.main.done) {
|
|
1202
1392
|
this.main = void 0;
|
|
1203
1393
|
this.beginMix(opts.mix);
|
|
@@ -1206,6 +1396,16 @@ var AnimationState = class {
|
|
|
1206
1396
|
}
|
|
1207
1397
|
play(id, opts = {}) {
|
|
1208
1398
|
const ch = this.channel(id, opts.loop, opts.priority ?? 0);
|
|
1399
|
+
if (!ch) {
|
|
1400
|
+
this.main?.settle?.("interrupted");
|
|
1401
|
+
for (const queued of this.queue) queued.settle?.("dropped");
|
|
1402
|
+
this.main = void 0;
|
|
1403
|
+
this.queue = [];
|
|
1404
|
+
this.beginMix(opts.mix);
|
|
1405
|
+
this.update(0);
|
|
1406
|
+
opts.onComplete?.("dropped");
|
|
1407
|
+
return Promise.resolve("dropped");
|
|
1408
|
+
}
|
|
1209
1409
|
const promise = new Promise((resolve) => {
|
|
1210
1410
|
ch.settle = (r) => {
|
|
1211
1411
|
ch.settle = void 0;
|
|
@@ -1226,7 +1426,10 @@ var AnimationState = class {
|
|
|
1226
1426
|
/** Independent loop on top of the shown pose; `undefined` removes it. */
|
|
1227
1427
|
setOverlay(name, id) {
|
|
1228
1428
|
if (id === void 0) this.overlays.delete(name);
|
|
1229
|
-
else
|
|
1429
|
+
else {
|
|
1430
|
+
const ch = this.channel(id);
|
|
1431
|
+
if (ch) this.overlays.set(name, ch);
|
|
1432
|
+
}
|
|
1230
1433
|
}
|
|
1231
1434
|
/** Clear everything and show the setup pose. Pending plays resolve as "stopped". */
|
|
1232
1435
|
stop() {
|
|
@@ -1351,7 +1554,7 @@ function atlasUV(asset, u, v, sourceW, sourceH) {
|
|
|
1351
1554
|
var rgbOf = (c) => Math.round(c[0] * 255) << 16 | Math.round(c[1] * 255) << 8 | Math.round(c[2] * 255);
|
|
1352
1555
|
var sameNumbers = (a, b) => a === b || a.length === b.length && a.every((v, i) => v === b[i]);
|
|
1353
1556
|
var RigPlayer = class {
|
|
1354
|
-
/**
|
|
1557
|
+
/** Default crossfade is 0.18 seconds; explicit mix: 0 requests a hard cut. */
|
|
1355
1558
|
constructor(doc, textures, opts = {}) {
|
|
1356
1559
|
this.doc = doc;
|
|
1357
1560
|
parse(doc);
|
|
@@ -1390,12 +1593,26 @@ var RigPlayer = class {
|
|
|
1390
1593
|
this.items.push(item);
|
|
1391
1594
|
this.view.addChild(item.node);
|
|
1392
1595
|
}
|
|
1393
|
-
this.state = new AnimationState(this, { mix: opts.mix ?? 0 });
|
|
1596
|
+
this.state = new AnimationState(this, { ...opts, mix: opts.mix ?? 0.18 });
|
|
1394
1597
|
this.setPose(/* @__PURE__ */ new Map());
|
|
1395
1598
|
}
|
|
1599
|
+
inputPose = /* @__PURE__ */ new Map();
|
|
1600
|
+
controlOverrides = /* @__PURE__ */ new Map();
|
|
1601
|
+
/** Manual inputs override animated controls until resetControls; values are clamped to declared ranges. */
|
|
1602
|
+
setControls(values) {
|
|
1603
|
+
this.controlOverrides = controlPose(this.doc, values);
|
|
1604
|
+
this.setPose(this.inputPose);
|
|
1605
|
+
}
|
|
1606
|
+
resetControls() {
|
|
1607
|
+
this.controlOverrides.clear();
|
|
1608
|
+
this.setPose(this.inputPose);
|
|
1609
|
+
}
|
|
1396
1610
|
view = new Container();
|
|
1397
1611
|
state;
|
|
1398
1612
|
items = [];
|
|
1613
|
+
beforePose = /* @__PURE__ */ new Set();
|
|
1614
|
+
afterPose = /* @__PURE__ */ new Set();
|
|
1615
|
+
clipPoints = /* @__PURE__ */ new Map();
|
|
1399
1616
|
skel;
|
|
1400
1617
|
textures;
|
|
1401
1618
|
pages = /* @__PURE__ */ new Map();
|
|
@@ -1403,6 +1620,36 @@ var RigPlayer = class {
|
|
|
1403
1620
|
hidden = /* @__PURE__ */ new Set();
|
|
1404
1621
|
/** slots the editor has selected; setPose draws them at GHOST_ALPHA at least */
|
|
1405
1622
|
ghosts = /* @__PURE__ */ new Set();
|
|
1623
|
+
clipGraphics = /* @__PURE__ */ new Map();
|
|
1624
|
+
/** Read-only render handles for in-page tools. Nodes remain owned by the player. */
|
|
1625
|
+
get renderItems() {
|
|
1626
|
+
return this.items;
|
|
1627
|
+
}
|
|
1628
|
+
/** Current document-space clipping polygons, keyed by path attachment id. */
|
|
1629
|
+
get clipPolygons() {
|
|
1630
|
+
return this.clipPoints;
|
|
1631
|
+
}
|
|
1632
|
+
/**
|
|
1633
|
+
* Modify resolved control outputs before skeleton evaluation, constraints and skinning.
|
|
1634
|
+
* Callbacks run in registration order, each with its own map. Change control inputs via setControls.
|
|
1635
|
+
*/
|
|
1636
|
+
onBeforePose(callback) {
|
|
1637
|
+
this.beforePose.add(callback);
|
|
1638
|
+
return () => {
|
|
1639
|
+
this.beforePose.delete(callback);
|
|
1640
|
+
};
|
|
1641
|
+
}
|
|
1642
|
+
/** Subscribe after the base pose has been rebuilt. Return value removes the callback. */
|
|
1643
|
+
onAfterPose(callback) {
|
|
1644
|
+
this.afterPose.add(callback);
|
|
1645
|
+
return () => {
|
|
1646
|
+
this.afterPose.delete(callback);
|
|
1647
|
+
};
|
|
1648
|
+
}
|
|
1649
|
+
/** Rebuild the current pose without advancing playback; useful for reversible overlays. */
|
|
1650
|
+
refreshPose() {
|
|
1651
|
+
this.setPose(this.inputPose);
|
|
1652
|
+
}
|
|
1406
1653
|
/** whole atlas page as a plain texture (identity uv mapping) for skinned meshes */
|
|
1407
1654
|
pageTexture(tex) {
|
|
1408
1655
|
let page = this.pages.get(tex.source);
|
|
@@ -1414,7 +1661,7 @@ var RigPlayer = class {
|
|
|
1414
1661
|
this.state.onEvent = opts.onEvent;
|
|
1415
1662
|
return this.state.play(animId, {
|
|
1416
1663
|
loop: opts.loop,
|
|
1417
|
-
mix: opts.mix
|
|
1664
|
+
mix: opts.mix,
|
|
1418
1665
|
ifBusy: "interrupt",
|
|
1419
1666
|
onComplete: (r) => {
|
|
1420
1667
|
if (r === "completed") opts.onComplete?.();
|
|
@@ -1457,13 +1704,39 @@ var RigPlayer = class {
|
|
|
1457
1704
|
}
|
|
1458
1705
|
/** Apply a pose (rest where silent) to the display objects. */
|
|
1459
1706
|
setPose(pose) {
|
|
1460
|
-
|
|
1707
|
+
this.inputPose = new Map(pose);
|
|
1708
|
+
if (this.controlOverrides.size) pose = new Map([...pose, ...this.controlOverrides]);
|
|
1709
|
+
this.clipPoints.clear();
|
|
1710
|
+
const skel = this.skel = evaluate(this.doc, pose, this.beforePose);
|
|
1711
|
+
pose = skel.pose;
|
|
1712
|
+
const clips = new Set(this.doc.slots.flatMap((s) => s.clip ? [s.clip] : []));
|
|
1713
|
+
for (const [id, g] of this.clipGraphics) if (!clips.has(id)) {
|
|
1714
|
+
g.destroy();
|
|
1715
|
+
this.clipGraphics.delete(id);
|
|
1716
|
+
}
|
|
1717
|
+
for (const id of clips) {
|
|
1718
|
+
const att = this.doc.attachments.find((a) => a.id === id);
|
|
1719
|
+
if (att?.type !== "path" || !att.closed) continue;
|
|
1720
|
+
let g = this.clipGraphics.get(id);
|
|
1721
|
+
if (!g) {
|
|
1722
|
+
g = new Graphics();
|
|
1723
|
+
this.clipGraphics.set(id, g);
|
|
1724
|
+
this.view.addChild(g);
|
|
1725
|
+
}
|
|
1726
|
+
const vertices = attachmentWorldVertices(skel, att.slot, att);
|
|
1727
|
+
const n = Math.max(32, vertices.length * 4);
|
|
1728
|
+
const points = samplePath(vertices, true, att.lengths, true, Array.from({ length: n }, (_, i) => i / n), true);
|
|
1729
|
+
const polygon = points.flatMap((p) => [p.x, p.y]);
|
|
1730
|
+
this.clipPoints.set(id, polygon);
|
|
1731
|
+
g.clear().poly(polygon, true).fill(16777215);
|
|
1732
|
+
}
|
|
1461
1733
|
const m = new Matrix();
|
|
1462
1734
|
const orderV = pose.get(pk("drawOrder", "order", "order"));
|
|
1463
1735
|
const order = /* @__PURE__ */ new Map();
|
|
1464
1736
|
if (Array.isArray(orderV)) orderV.forEach((id, i) => order.set(id, i));
|
|
1465
1737
|
for (const it of this.items) {
|
|
1466
1738
|
const s = it.slot, shown = skel.attachment.get(s.id);
|
|
1739
|
+
it.node.mask = s.clip ? this.clipGraphics.get(s.clip) ?? null : null;
|
|
1467
1740
|
if (shown !== it.att || this.hidden.has(s.id)) {
|
|
1468
1741
|
it.node.visible = false;
|
|
1469
1742
|
continue;
|
|
@@ -1476,6 +1749,7 @@ var RigPlayer = class {
|
|
|
1476
1749
|
it.node.tint = rgbOf(color);
|
|
1477
1750
|
it.node.zIndex = order.size ? order.get(s.id) ?? 0 : numOf(pose, pk("slot", s.id, "z"), s.z);
|
|
1478
1751
|
if (it.skinned) {
|
|
1752
|
+
it.node.setFromMatrix(m.identity());
|
|
1479
1753
|
const v = attachmentWorldVertices(skel, s.id, it.att);
|
|
1480
1754
|
const buf = it.skinned.mesh.geometry.getBuffer("aPosition");
|
|
1481
1755
|
buf.data.set(v);
|
|
@@ -1508,6 +1782,7 @@ var RigPlayer = class {
|
|
|
1508
1782
|
it.node.scale.y *= h / (this.textures.get(att.asset)?.height ?? h);
|
|
1509
1783
|
}
|
|
1510
1784
|
}
|
|
1785
|
+
for (const callback of this.afterPose) callback(this);
|
|
1511
1786
|
}
|
|
1512
1787
|
/** World-space bone positions — used by editor gizmos and renderPreview overlays */
|
|
1513
1788
|
bonePositions() {
|
|
@@ -1584,9 +1859,12 @@ export {
|
|
|
1584
1859
|
RigPlayer,
|
|
1585
1860
|
RigSymbol,
|
|
1586
1861
|
atlasUV,
|
|
1862
|
+
controlPose,
|
|
1587
1863
|
createTextures,
|
|
1588
1864
|
migrateV1,
|
|
1589
1865
|
parse,
|
|
1866
|
+
resolveControls,
|
|
1867
|
+
sampleBinding,
|
|
1590
1868
|
validate
|
|
1591
1869
|
};
|
|
1592
1870
|
//# sourceMappingURL=runtime.js.map
|