rig-play 1.10.0 → 1.11.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/NOTICE.md +14 -10
- package/README.md +211 -35
- package/dist/DomRenderer.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +396 -99
- package/dist/index.js.map +1 -1
- package/dist/loadModel.d.ts +25 -0
- package/dist/loadModel.d.ts.map +1 -1
- package/dist/player.d.ts +32 -1
- package/dist/player.d.ts.map +1 -1
- package/package.json +22 -2
package/dist/index.js
CHANGED
|
@@ -151,7 +151,7 @@ function listedByAppliedSkin(doc, kind, name) {
|
|
|
151
151
|
const DEFORM_CURVE_END = 0.99999999;
|
|
152
152
|
const SEQUENCE_MODES = ["hold", "once", "loop", "pingpong", "onceReverse", "loopReverse", "pingpongReverse"];
|
|
153
153
|
const SEQUENCE_EPSILON = 1e-5;
|
|
154
|
-
const isRecord$
|
|
154
|
+
const isRecord$a = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
155
155
|
const finite$2 = (v) => typeof v === "number" && Number.isFinite(v);
|
|
156
156
|
function deformLength(vertices) {
|
|
157
157
|
return vertices.weighted ? 2 * vertices.bindings.reduce((n, b) => n + b.length, 0) : vertices.xy.length;
|
|
@@ -159,7 +159,7 @@ function deformLength(vertices) {
|
|
|
159
159
|
function keyTimes(list, at, problems) {
|
|
160
160
|
let last = -Infinity;
|
|
161
161
|
list.forEach((k, i) => {
|
|
162
|
-
if (!isRecord$
|
|
162
|
+
if (!isRecord$a(k)) return;
|
|
163
163
|
const t = k.time;
|
|
164
164
|
if (!finite$2(t) || t < 0) problems.push(`${at}[${i}]: time is ${JSON.stringify(t)}, not a finite time at or after 0`);
|
|
165
165
|
else if (t <= last) problems.push(`${at}[${i}]: time ${t} is not after the key before it — the writer refuses key times that do not strictly increase`);
|
|
@@ -176,7 +176,7 @@ function readDeformKeys(value, at, vertices, problems) {
|
|
|
176
176
|
const out = [];
|
|
177
177
|
value.forEach((k, i) => {
|
|
178
178
|
const kat = `${at}[${i}]`;
|
|
179
|
-
if (!isRecord$
|
|
179
|
+
if (!isRecord$a(k)) {
|
|
180
180
|
problems.push(`${kat} is not an object`);
|
|
181
181
|
return;
|
|
182
182
|
}
|
|
@@ -215,7 +215,7 @@ function readSequenceKeys(value, at, count, problems) {
|
|
|
215
215
|
const out = [];
|
|
216
216
|
value.forEach((k, i) => {
|
|
217
217
|
const kat = `${at}[${i}]`;
|
|
218
|
-
if (!isRecord$
|
|
218
|
+
if (!isRecord$a(k)) {
|
|
219
219
|
problems.push(`${kat} is not an object`);
|
|
220
220
|
return;
|
|
221
221
|
}
|
|
@@ -249,7 +249,7 @@ function readAttachmentTimelines(value, label, skins, problems) {
|
|
|
249
249
|
}
|
|
250
250
|
value.forEach((skinEntry, i) => {
|
|
251
251
|
const sat = `${where}[${i}]`;
|
|
252
|
-
if (!isRecord$
|
|
252
|
+
if (!isRecord$a(skinEntry) || typeof skinEntry.name !== "string") {
|
|
253
253
|
problems.push(`${sat} names no skin`);
|
|
254
254
|
return;
|
|
255
255
|
}
|
|
@@ -261,7 +261,7 @@ function readAttachmentTimelines(value, label, skins, problems) {
|
|
|
261
261
|
}
|
|
262
262
|
skinEntry.slots.forEach((slotEntry, j) => {
|
|
263
263
|
const lat = `${sat}.slots[${j}]`;
|
|
264
|
-
if (!isRecord$
|
|
264
|
+
if (!isRecord$a(slotEntry) || typeof slotEntry.name !== "string") {
|
|
265
265
|
problems.push(`${lat} names no slot`);
|
|
266
266
|
return;
|
|
267
267
|
}
|
|
@@ -272,7 +272,7 @@ function readAttachmentTimelines(value, label, skins, problems) {
|
|
|
272
272
|
const slot = slotEntry.name;
|
|
273
273
|
slotEntry.attachments.forEach((attEntry, m) => {
|
|
274
274
|
const aat = `${lat}.attachments[${m}]`;
|
|
275
|
-
if (!isRecord$
|
|
275
|
+
if (!isRecord$a(attEntry) || typeof attEntry.name !== "string") {
|
|
276
276
|
problems.push(`${aat} names no attachment`);
|
|
277
277
|
return;
|
|
278
278
|
}
|
|
@@ -450,7 +450,7 @@ function attachmentStates(doc, resolve, placeholders, sample, sliders, plant = {
|
|
|
450
450
|
}
|
|
451
451
|
return { shown, why };
|
|
452
452
|
}
|
|
453
|
-
const isRecord$
|
|
453
|
+
const isRecord$9 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
454
454
|
function readDrawOrderKeys(value, label, slots, problems) {
|
|
455
455
|
const where = `${label}.drawOrder`;
|
|
456
456
|
if (!Array.isArray(value)) {
|
|
@@ -462,7 +462,7 @@ function readDrawOrderKeys(value, label, slots, problems) {
|
|
|
462
462
|
let last = -Infinity;
|
|
463
463
|
value.forEach((k, i) => {
|
|
464
464
|
const at = `${where}[${i}]`;
|
|
465
|
-
if (!isRecord$
|
|
465
|
+
if (!isRecord$9(k)) {
|
|
466
466
|
problems.push(`${at} is not an object`);
|
|
467
467
|
return;
|
|
468
468
|
}
|
|
@@ -478,7 +478,7 @@ function readDrawOrderKeys(value, label, slots, problems) {
|
|
|
478
478
|
const landed = /* @__PURE__ */ new Map();
|
|
479
479
|
k.offsets.forEach((o, j) => {
|
|
480
480
|
const oat = `${at}.offsets[${j}]`;
|
|
481
|
-
if (!isRecord$
|
|
481
|
+
if (!isRecord$9(o) || typeof o.slot !== "string") {
|
|
482
482
|
problems.push(`${oat} names no slot`);
|
|
483
483
|
return;
|
|
484
484
|
}
|
|
@@ -517,7 +517,7 @@ function drawOrderAt(count, keys, t) {
|
|
|
517
517
|
const i = keyIndexAt(keys, t);
|
|
518
518
|
return i < 0 ? null : orderOf(count, keys[i].moves);
|
|
519
519
|
}
|
|
520
|
-
const isRecord$
|
|
520
|
+
const isRecord$8 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
521
521
|
const EVENT_DEF_FIELDS = ["name", "int", "float", "string", "audio", "volume", "balance"];
|
|
522
522
|
const EVENT_KEY_FIELDS = ["time", "name", "int", "float", "string", "volume", "balance"];
|
|
523
523
|
function payload(raw, at, problems) {
|
|
@@ -545,7 +545,7 @@ function readEventDefs(value, problems) {
|
|
|
545
545
|
}
|
|
546
546
|
value.forEach((raw, i) => {
|
|
547
547
|
const at = `events[${i}]`;
|
|
548
|
-
if (!isRecord$
|
|
548
|
+
if (!isRecord$8(raw) || typeof raw.name !== "string" || raw.name === "") {
|
|
549
549
|
problems.push(`${at} names no event`);
|
|
550
550
|
return;
|
|
551
551
|
}
|
|
@@ -567,7 +567,7 @@ function readEventKeys(value, label, defs, problems) {
|
|
|
567
567
|
let last = -Infinity;
|
|
568
568
|
value.forEach((raw, i) => {
|
|
569
569
|
const at = `${where}[${i}]`;
|
|
570
|
-
if (!isRecord$
|
|
570
|
+
if (!isRecord$8(raw)) {
|
|
571
571
|
problems.push(`${at} is not an object`);
|
|
572
572
|
return;
|
|
573
573
|
}
|
|
@@ -1019,11 +1019,11 @@ function worldVertices(vertices, bone2, world, coords = Math.fround) {
|
|
|
1019
1019
|
}
|
|
1020
1020
|
return out;
|
|
1021
1021
|
}
|
|
1022
|
-
const isRecord$
|
|
1022
|
+
const isRecord$7 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1023
1023
|
const finite$1 = (v) => typeof v === "number" && Number.isFinite(v);
|
|
1024
1024
|
const RECT_FIELDS = ["width", "height", "offsetX", "offsetY", "originalWidth", "originalHeight"];
|
|
1025
1025
|
function readRect(value, where, problems) {
|
|
1026
|
-
if (!isRecord$
|
|
1026
|
+
if (!isRecord$7(value)) {
|
|
1027
1027
|
problems.push(`${where} is ${JSON.stringify(value)}, not an atlas rectangle`);
|
|
1028
1028
|
return void 0;
|
|
1029
1029
|
}
|
|
@@ -1033,7 +1033,7 @@ function readRect(value, where, problems) {
|
|
|
1033
1033
|
return problems.length === before ? value : void 0;
|
|
1034
1034
|
}
|
|
1035
1035
|
function readVertices(value, where, bones, problems) {
|
|
1036
|
-
if (!isRecord$
|
|
1036
|
+
if (!isRecord$7(value) || typeof value.weighted !== "boolean") {
|
|
1037
1037
|
problems.push(`${where} is not { weighted: false, xy } or { weighted: true, bindings }`);
|
|
1038
1038
|
return void 0;
|
|
1039
1039
|
}
|
|
@@ -1055,7 +1055,7 @@ function readVertices(value, where, bones, problems) {
|
|
|
1055
1055
|
}
|
|
1056
1056
|
influences.forEach((b, j) => {
|
|
1057
1057
|
const at = `${where}.bindings[${i}][${j}]`;
|
|
1058
|
-
if (!isRecord$
|
|
1058
|
+
if (!isRecord$7(b)) {
|
|
1059
1059
|
problems.push(`${at} is not an object`);
|
|
1060
1060
|
return;
|
|
1061
1061
|
}
|
|
@@ -1078,10 +1078,10 @@ function readGeometry(raw, kind, where, bones, slots, problems) {
|
|
|
1078
1078
|
if (hasRect === hasSequence) {
|
|
1079
1079
|
problems.push(`${where}: the region carries ${hasRect ? "both an atlas rectangle and a sequence" : "neither an atlas rectangle nor a sequence"}; the writer states exactly one of the two, and a sequence holds a rectangle per frame (issue #935)`);
|
|
1080
1080
|
} else if (hasRect) {
|
|
1081
|
-
atlas = raw.atlas === null ? null : isRecord$
|
|
1081
|
+
atlas = raw.atlas === null ? null : isRecord$7(raw.atlas) ? raw.atlas : void 0;
|
|
1082
1082
|
} else {
|
|
1083
1083
|
const seq = raw.sequence;
|
|
1084
|
-
if (!isRecord$
|
|
1084
|
+
if (!isRecord$7(seq)) problems.push(`${where}.sequence is not an object`);
|
|
1085
1085
|
else {
|
|
1086
1086
|
const count = seq.count;
|
|
1087
1087
|
const setup = seq.setup ?? 0;
|
|
@@ -1247,7 +1247,7 @@ const PATH_POSITION_MODES = ["fixed", "percent"];
|
|
|
1247
1247
|
const PATH_SPACING_MODES = ["length", "fixed", "percent", "proportional"];
|
|
1248
1248
|
const PATH_ROTATE_MODES = ["tangent", "chain", "chainScale"];
|
|
1249
1249
|
const PATH_FIELDS = ["bones", "slot", "positionMode", "spacingMode", "rotateMode", "rotation", "position", "spacing", "mixRotate", "mixX", "mixY", "skin"];
|
|
1250
|
-
const isRecord$
|
|
1250
|
+
const isRecord$6 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
1251
1251
|
function fold(raw, key, modes, dflt, where, problems) {
|
|
1252
1252
|
const v = raw[key];
|
|
1253
1253
|
if (v === void 0) return dflt;
|
|
@@ -1325,7 +1325,7 @@ function readPathTimelines(value, label, declared, problems) {
|
|
|
1325
1325
|
if (!Array.isArray(value)) return out;
|
|
1326
1326
|
value.forEach((entry, i) => {
|
|
1327
1327
|
const at = `${label}.constraints.path[${i}]`;
|
|
1328
|
-
if (!isRecord$
|
|
1328
|
+
if (!isRecord$6(entry) || typeof entry.name !== "string") {
|
|
1329
1329
|
problems.push(`${at} names no constraint`);
|
|
1330
1330
|
return;
|
|
1331
1331
|
}
|
|
@@ -1337,8 +1337,8 @@ function readPathTimelines(value, label, declared, problems) {
|
|
|
1337
1337
|
}
|
|
1338
1338
|
entry.timelines.forEach((tl, j) => {
|
|
1339
1339
|
const tat = `${at}.timelines[${j}]`;
|
|
1340
|
-
if (!isRecord$
|
|
1341
|
-
problems.push(`${tat}: ${isRecord$
|
|
1340
|
+
if (!isRecord$6(tl) || typeof tl.name !== "string" || !(tl.name in PATH_TIMELINES)) {
|
|
1341
|
+
problems.push(`${tat}: ${isRecord$6(tl) ? JSON.stringify(tl.name) : "it"} is not a path timeline; they are ${Object.keys(PATH_TIMELINES).join(", ")}`);
|
|
1342
1342
|
return;
|
|
1343
1343
|
}
|
|
1344
1344
|
const kind = tl.name;
|
|
@@ -1353,7 +1353,7 @@ function readPathTimelines(value, label, declared, problems) {
|
|
|
1353
1353
|
const keys = [];
|
|
1354
1354
|
rawKeys.forEach((k, n) => {
|
|
1355
1355
|
const kat = `${tat}.keys[${n}]`;
|
|
1356
|
-
if (!isRecord$
|
|
1356
|
+
if (!isRecord$6(k)) {
|
|
1357
1357
|
problems.push(`${kat} is not an object`);
|
|
1358
1358
|
return;
|
|
1359
1359
|
}
|
|
@@ -2179,7 +2179,7 @@ function steppedPreviousPassWhy(doc) {
|
|
|
2179
2179
|
return reads.length === 0 ? null : `${reads.map((r) => `path constraint "${r.constraint}" reads slot bone "${r.bone}" from the previous pose`).join("; ")} — under the step the previous pose is the previous step's, which the stepped walk does not carry`;
|
|
2180
2180
|
}
|
|
2181
2181
|
const SLIDER_FIELDS = ["animation", "additive", "loop", "mix", "bone", "property", "from", "to", "scale", "max", "local", "time", "skin"];
|
|
2182
|
-
const isRecord$
|
|
2182
|
+
const isRecord$5 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2183
2183
|
function readSliderRecord(raw, name, where, bones, animations, problems) {
|
|
2184
2184
|
const before = problems.length;
|
|
2185
2185
|
for (const key of Object.keys(raw)) {
|
|
@@ -2252,7 +2252,7 @@ function readSliderTimelines(value, label, declared, problems) {
|
|
|
2252
2252
|
if (!Array.isArray(value)) return out;
|
|
2253
2253
|
value.forEach((entry, i) => {
|
|
2254
2254
|
const at = `${label}.constraints.slider[${i}]`;
|
|
2255
|
-
if (!isRecord$
|
|
2255
|
+
if (!isRecord$5(entry) || typeof entry.name !== "string") {
|
|
2256
2256
|
problems.push(`${at} names no slider`);
|
|
2257
2257
|
return;
|
|
2258
2258
|
}
|
|
@@ -2264,8 +2264,8 @@ function readSliderTimelines(value, label, declared, problems) {
|
|
|
2264
2264
|
}
|
|
2265
2265
|
entry.timelines.forEach((raw, j) => {
|
|
2266
2266
|
const tat = `${at}.timelines[${j}]`;
|
|
2267
|
-
if (!isRecord$
|
|
2268
|
-
problems.push(`${tat}: ${JSON.stringify(isRecord$
|
|
2267
|
+
if (!isRecord$5(raw) || raw.name !== "time" && raw.name !== "mix") {
|
|
2268
|
+
problems.push(`${tat}: ${JSON.stringify(isRecord$5(raw) ? raw.name : raw)} is not a slider timeline; a slider keys time and mix`);
|
|
2269
2269
|
return;
|
|
2270
2270
|
}
|
|
2271
2271
|
const which = raw.name;
|
|
@@ -2285,7 +2285,7 @@ function readKeys(value, at, problems) {
|
|
|
2285
2285
|
let last = -Infinity;
|
|
2286
2286
|
value.forEach((k, j) => {
|
|
2287
2287
|
const kat = `${at}.keys[${j}]`;
|
|
2288
|
-
if (!isRecord$
|
|
2288
|
+
if (!isRecord$5(k)) {
|
|
2289
2289
|
problems.push(`${kat} is not an object`);
|
|
2290
2290
|
return;
|
|
2291
2291
|
}
|
|
@@ -2529,7 +2529,7 @@ const CONSTRAINT_FIELDS = {
|
|
|
2529
2529
|
ik: ["bones", "target", "scaleY", "mix", "softness", "bendPositive", "compress", "stretch", "skin"],
|
|
2530
2530
|
transform: ["bones", "source", "properties", "localSource", "localTarget", "additive", "clamp", "rotation", "x", "y", "scaleX", "scaleY", "shearY", "mixRotate", "mixX", "mixY", "mixScaleX", "mixScaleY", "mixShearY", "skin"]
|
|
2531
2531
|
};
|
|
2532
|
-
const isRecord$
|
|
2532
|
+
const isRecord$4 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2533
2533
|
function unknownFields$1(record, known, where, problems) {
|
|
2534
2534
|
for (const key of Object.keys(record)) if (!known.includes(key)) problems.push(`${where}: field "${key}" is not one this reader knows; it reads [${known.join(", ")}]`);
|
|
2535
2535
|
}
|
|
@@ -2618,8 +2618,8 @@ function readConstraintRecord(raw, kind, name, where, bones, parents, problems)
|
|
|
2618
2618
|
const source = boneRef(raw, "source", bones, where, problems);
|
|
2619
2619
|
const properties = [];
|
|
2620
2620
|
const driven = /* @__PURE__ */ new Set();
|
|
2621
|
-
if (raw.properties !== void 0 && !isRecord$
|
|
2622
|
-
else if (isRecord$
|
|
2621
|
+
if (raw.properties !== void 0 && !isRecord$4(raw.properties)) problems.push(`${where}: properties is not an object`);
|
|
2622
|
+
else if (isRecord$4(raw.properties)) {
|
|
2623
2623
|
for (const [fromName, fromRaw] of Object.entries(raw.properties)) {
|
|
2624
2624
|
const at = `${where}.properties.${fromName}`;
|
|
2625
2625
|
const from = TRANSFORM_PROPERTIES.find((p) => p === fromName);
|
|
@@ -2627,13 +2627,13 @@ function readConstraintRecord(raw, kind, name, where, bones, parents, problems)
|
|
|
2627
2627
|
problems.push(`${at}: "${fromName}" is none of ${TRANSFORM_PROPERTIES.join(", ")}`);
|
|
2628
2628
|
continue;
|
|
2629
2629
|
}
|
|
2630
|
-
if (!isRecord$
|
|
2630
|
+
if (!isRecord$4(fromRaw)) {
|
|
2631
2631
|
problems.push(`${at} is not an object`);
|
|
2632
2632
|
continue;
|
|
2633
2633
|
}
|
|
2634
2634
|
unknownFields$1(fromRaw, ["offset", "to"], at, problems);
|
|
2635
2635
|
const to = [];
|
|
2636
|
-
if (!isRecord$
|
|
2636
|
+
if (!isRecord$4(fromRaw.to)) problems.push(`${at}: to is not an object`);
|
|
2637
2637
|
else {
|
|
2638
2638
|
for (const [toName, toRaw] of Object.entries(fromRaw.to)) {
|
|
2639
2639
|
const at2 = `${at}.to.${toName}`;
|
|
@@ -2642,7 +2642,7 @@ function readConstraintRecord(raw, kind, name, where, bones, parents, problems)
|
|
|
2642
2642
|
problems.push(`${at2}: "${toName}" is none of ${TRANSFORM_PROPERTIES.join(", ")}`);
|
|
2643
2643
|
continue;
|
|
2644
2644
|
}
|
|
2645
|
-
if (!isRecord$
|
|
2645
|
+
if (!isRecord$4(toRaw)) {
|
|
2646
2646
|
problems.push(`${at2} is not an object`);
|
|
2647
2647
|
continue;
|
|
2648
2648
|
}
|
|
@@ -2695,7 +2695,7 @@ function keyCurve(raw, channels, last, at, problems) {
|
|
|
2695
2695
|
}
|
|
2696
2696
|
function readConstraintTimelines(value, label, declared, problems) {
|
|
2697
2697
|
const out = { ik: [], transform: [], path: [], physics: 0, slider: [] };
|
|
2698
|
-
if (!isRecord$
|
|
2698
|
+
if (!isRecord$4(value)) return out;
|
|
2699
2699
|
out.path = readPathTimelines(value.path, label, new Set(declared.filter((c) => c.kind === "path").map((c) => c.name)), problems);
|
|
2700
2700
|
out.physics = physicsTimelineCount(value.physics);
|
|
2701
2701
|
out.physicsKeyed = readPhysicsTimelines(value.physics, label, new Set(declared.filter((c) => c.kind === "physics").map((c) => c.name)), problems);
|
|
@@ -2705,7 +2705,7 @@ function readConstraintTimelines(value, label, declared, problems) {
|
|
|
2705
2705
|
if (!Array.isArray(list)) continue;
|
|
2706
2706
|
list.forEach((entry, i) => {
|
|
2707
2707
|
const at = `${label}.constraints.${kind}[${i}]`;
|
|
2708
|
-
if (!isRecord$
|
|
2708
|
+
if (!isRecord$4(entry) || typeof entry.name !== "string") {
|
|
2709
2709
|
problems.push(`${at} names no constraint`);
|
|
2710
2710
|
return;
|
|
2711
2711
|
}
|
|
@@ -2721,7 +2721,7 @@ function readConstraintTimelines(value, label, declared, problems) {
|
|
|
2721
2721
|
const keys = [];
|
|
2722
2722
|
rawKeys.forEach((k, j) => {
|
|
2723
2723
|
const kat = `${at}.keys[${j}]`;
|
|
2724
|
-
if (!isRecord$
|
|
2724
|
+
if (!isRecord$4(k)) {
|
|
2725
2725
|
problems.push(`${kat} is not an object`);
|
|
2726
2726
|
return;
|
|
2727
2727
|
}
|
|
@@ -3539,7 +3539,7 @@ const SLOT_COLOUR_TIMELINES = {
|
|
|
3539
3539
|
rgb2: { fields: [["light", 6], ["dark", 6]], channels: ["r", "g", "b", "r2", "g2", "b2"] }
|
|
3540
3540
|
};
|
|
3541
3541
|
const SLOT_TIMELINE_KINDS = ["attachment", ...Object.keys(SLOT_COLOUR_TIMELINES)];
|
|
3542
|
-
const isRecord$
|
|
3542
|
+
const isRecord$3 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
3543
3543
|
const isHex = (v, digits) => typeof v === "string" && v.length === digits && /^[0-9a-fA-F]+$/.test(v);
|
|
3544
3544
|
function keyTime(raw, where, problems) {
|
|
3545
3545
|
const time = raw.time;
|
|
@@ -3558,7 +3558,7 @@ function keyList(value, where, problems) {
|
|
|
3558
3558
|
let last = -Infinity;
|
|
3559
3559
|
value.forEach((raw, i) => {
|
|
3560
3560
|
const at = `${where}.keys[${i}]`;
|
|
3561
|
-
if (!isRecord$
|
|
3561
|
+
if (!isRecord$3(raw)) {
|
|
3562
3562
|
problems.push(`${at} is not an object`);
|
|
3563
3563
|
return;
|
|
3564
3564
|
}
|
|
@@ -3651,7 +3651,7 @@ function constraintKeyTimes(value, where, problems) {
|
|
|
3651
3651
|
return;
|
|
3652
3652
|
}
|
|
3653
3653
|
list.forEach((k, i) => {
|
|
3654
|
-
if (!isRecord$
|
|
3654
|
+
if (!isRecord$3(k)) problems.push(`${at}[${i}] is not an object`);
|
|
3655
3655
|
else {
|
|
3656
3656
|
const t = keyTime(k, `${at}[${i}]`, problems);
|
|
3657
3657
|
if (t !== null) times2.push(Math.fround(t));
|
|
@@ -3663,9 +3663,9 @@ function constraintKeyTimes(value, where, problems) {
|
|
|
3663
3663
|
problems.push(`${at} is not a list`);
|
|
3664
3664
|
return;
|
|
3665
3665
|
}
|
|
3666
|
-
list.forEach((entry, i) => isRecord$
|
|
3666
|
+
list.forEach((entry, i) => isRecord$3(entry) ? each(entry, `${at}[${i}]`) : problems.push(`${at}[${i}] is not an object`));
|
|
3667
3667
|
};
|
|
3668
|
-
if (!isRecord$
|
|
3668
|
+
if (!isRecord$3(value)) problems.push(`${where} is not an object`);
|
|
3669
3669
|
else {
|
|
3670
3670
|
for (const kind of ["ik", "transform"]) named(value[kind], `${where}.${kind}`, (e, at) => keys(e.keys, `${at}.keys`));
|
|
3671
3671
|
for (const kind of ["path", "physics", "slider"]) named(value[kind], `${where}.${kind}`, (e, at) => named(e.timelines, `${at}.timelines`, (tl, at2) => keys(tl.keys, `${at2}.keys`)));
|
|
@@ -3686,7 +3686,7 @@ function readAnimationTimelines(raw, label, bones, slots, problems, context) {
|
|
|
3686
3686
|
}
|
|
3687
3687
|
value.forEach((entry, i) => {
|
|
3688
3688
|
const at = `${label}.${group}[${i}]`;
|
|
3689
|
-
if (!isRecord$
|
|
3689
|
+
if (!isRecord$3(entry) || typeof entry.name !== "string") {
|
|
3690
3690
|
problems.push(`${at} names no target`);
|
|
3691
3691
|
return;
|
|
3692
3692
|
}
|
|
@@ -3701,7 +3701,7 @@ function readAnimationTimelines(raw, label, bones, slots, problems, context) {
|
|
|
3701
3701
|
const target = { name, timelines: [] };
|
|
3702
3702
|
entry.timelines.forEach((tl, j) => {
|
|
3703
3703
|
const tat = `${where}.timelines[${j}]`;
|
|
3704
|
-
if (!isRecord$
|
|
3704
|
+
if (!isRecord$3(tl) || typeof tl.name !== "string") {
|
|
3705
3705
|
problems.push(`${tat} names no timeline`);
|
|
3706
3706
|
return;
|
|
3707
3707
|
}
|
|
@@ -4144,7 +4144,7 @@ function readPages(value, problems, flags) {
|
|
|
4144
4144
|
const out = [];
|
|
4145
4145
|
value.forEach((raw, i) => {
|
|
4146
4146
|
const where = `pages[${i}]`;
|
|
4147
|
-
if (!isRecord$
|
|
4147
|
+
if (!isRecord$2(raw)) {
|
|
4148
4148
|
problems.push(`${where} is not an object`);
|
|
4149
4149
|
return;
|
|
4150
4150
|
}
|
|
@@ -4166,7 +4166,7 @@ function readPages(value, problems, flags) {
|
|
|
4166
4166
|
else {
|
|
4167
4167
|
raw.regions.forEach((region, j) => {
|
|
4168
4168
|
const at = `${label}.regions[${j}]`;
|
|
4169
|
-
if (!isRecord$
|
|
4169
|
+
if (!isRecord$2(region)) {
|
|
4170
4170
|
problems.push(`${at} is not an object`);
|
|
4171
4171
|
return;
|
|
4172
4172
|
}
|
|
@@ -4191,7 +4191,7 @@ function readPages(value, problems, flags) {
|
|
|
4191
4191
|
}
|
|
4192
4192
|
function readSpineDigest(value, problems) {
|
|
4193
4193
|
if (value === void 0) return "";
|
|
4194
|
-
if (!isRecord$
|
|
4194
|
+
if (!isRecord$2(value)) {
|
|
4195
4195
|
problems.push(`spine is ${JSON.stringify(value)}, not { "sha256": "<64 lowercase hex digits>" }`);
|
|
4196
4196
|
return "";
|
|
4197
4197
|
}
|
|
@@ -4205,7 +4205,7 @@ function readSpineDigest(value, problems) {
|
|
|
4205
4205
|
}
|
|
4206
4206
|
function readStage(value, problems) {
|
|
4207
4207
|
if (value === null) return null;
|
|
4208
|
-
if (!isRecord$
|
|
4208
|
+
if (!isRecord$2(value)) {
|
|
4209
4209
|
problems.push(`stage is ${JSON.stringify(value) ?? "absent"}, not null or { x, y, width, height } — the setup-pose box the Spine header declares`);
|
|
4210
4210
|
return null;
|
|
4211
4211
|
}
|
|
@@ -4217,7 +4217,7 @@ function readStage(value, problems) {
|
|
|
4217
4217
|
}
|
|
4218
4218
|
const box = value.box;
|
|
4219
4219
|
if (box !== void 0) {
|
|
4220
|
-
if (!isRecord$
|
|
4220
|
+
if (!isRecord$2(box)) problems.push(`stage.box is ${JSON.stringify(box)}, not { slot, attachment }`);
|
|
4221
4221
|
else {
|
|
4222
4222
|
unknownFields(box, CORE_STAGE_BOX_FIELDS, "stage.box", problems);
|
|
4223
4223
|
for (const key of CORE_STAGE_BOX_FIELDS) if (typeof box[key] !== "string" || box[key] === "") problems.push(`stage.box: ${key} is ${JSON.stringify(box[key]) ?? "absent"}, not a non-empty string`);
|
|
@@ -4225,12 +4225,12 @@ function readStage(value, problems) {
|
|
|
4225
4225
|
}
|
|
4226
4226
|
if (problems.length !== before) return null;
|
|
4227
4227
|
const stage = { x: value.x, y: value.y, width: value.width, height: value.height };
|
|
4228
|
-
if (isRecord$
|
|
4228
|
+
if (isRecord$2(box)) stage.box = { slot: box.slot, attachment: box.attachment };
|
|
4229
4229
|
return stage;
|
|
4230
4230
|
}
|
|
4231
4231
|
function readEditorOrder(value, skins, animations, problems) {
|
|
4232
4232
|
const out = { skins: [], animations: [] };
|
|
4233
|
-
if (!isRecord$
|
|
4233
|
+
if (!isRecord$2(value)) {
|
|
4234
4234
|
problems.push(`editorOrder is ${JSON.stringify(value) ?? "absent"}, not { skins, animations }`);
|
|
4235
4235
|
return out;
|
|
4236
4236
|
}
|
|
@@ -4256,7 +4256,7 @@ function readEditorOrder(value, skins, animations, problems) {
|
|
|
4256
4256
|
else {
|
|
4257
4257
|
value.skins.forEach((entry, i) => {
|
|
4258
4258
|
const at = `editorOrder.skins[${i}]`;
|
|
4259
|
-
if (!isRecord$
|
|
4259
|
+
if (!isRecord$2(entry) || typeof entry.name !== "string") return void problems.push(`${at} is not { name, slots }`);
|
|
4260
4260
|
unknownFields(entry, ["name", "slots"], at, problems);
|
|
4261
4261
|
const slots = names(entry.slots, `${at}.slots`);
|
|
4262
4262
|
const skin = skins.find((k) => k.name === entry.name);
|
|
@@ -4272,7 +4272,7 @@ function readEditorOrder(value, skins, animations, problems) {
|
|
|
4272
4272
|
}
|
|
4273
4273
|
return out;
|
|
4274
4274
|
}
|
|
4275
|
-
const isRecord$
|
|
4275
|
+
const isRecord$2 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
4276
4276
|
function foldInheritMode(value) {
|
|
4277
4277
|
const folded = value.length === 0 ? value : value[0].toLowerCase() + value.slice(1);
|
|
4278
4278
|
return CORE_INHERIT_MODES.find((m) => m === folded) ?? null;
|
|
@@ -4291,7 +4291,7 @@ function readBones(value, problems) {
|
|
|
4291
4291
|
const seen = /* @__PURE__ */ new Set();
|
|
4292
4292
|
value.forEach((raw, i) => {
|
|
4293
4293
|
const where = `bones[${i}]`;
|
|
4294
|
-
if (!isRecord$
|
|
4294
|
+
if (!isRecord$2(raw)) {
|
|
4295
4295
|
problems.push(`${where} is not an object`);
|
|
4296
4296
|
return;
|
|
4297
4297
|
}
|
|
@@ -4314,7 +4314,7 @@ function readBones(value, problems) {
|
|
|
4314
4314
|
}
|
|
4315
4315
|
if (raw.skinRequired !== void 0 && typeof raw.skinRequired !== "boolean") problems.push(`${label}: skinRequired is ${JSON.stringify(raw.skinRequired)}, not a boolean`);
|
|
4316
4316
|
if (raw.editor !== void 0) {
|
|
4317
|
-
if (!isRecord$
|
|
4317
|
+
if (!isRecord$2(raw.editor)) problems.push(`${label}: editor is not an object`);
|
|
4318
4318
|
else {
|
|
4319
4319
|
unknownFields(raw.editor, ["color", "icon"], `${label}.editor`, problems);
|
|
4320
4320
|
for (const key of ["color", "icon"]) {
|
|
@@ -4335,7 +4335,7 @@ function readSlots(value, bones, problems) {
|
|
|
4335
4335
|
const out = [];
|
|
4336
4336
|
value.forEach((raw, i) => {
|
|
4337
4337
|
const where = `slots[${i}]`;
|
|
4338
|
-
if (!isRecord$
|
|
4338
|
+
if (!isRecord$2(raw)) {
|
|
4339
4339
|
problems.push(`${where} is not an object`);
|
|
4340
4340
|
return;
|
|
4341
4341
|
}
|
|
@@ -4364,14 +4364,14 @@ function readAttachments(value, bones, slots, label, problems) {
|
|
|
4364
4364
|
for (const [slot, table] of Object.entries(value)) {
|
|
4365
4365
|
const at = `${label}.attachments["${slot}"]`;
|
|
4366
4366
|
if (!slots.has(slot)) problems.push(`${at}: "${slot}" is not a slot of this document`);
|
|
4367
|
-
if (!isRecord$
|
|
4367
|
+
if (!isRecord$2(table)) {
|
|
4368
4368
|
problems.push(`${at} is not an object`);
|
|
4369
4369
|
continue;
|
|
4370
4370
|
}
|
|
4371
4371
|
const entries = {};
|
|
4372
4372
|
for (const [placeholder, raw] of Object.entries(table)) {
|
|
4373
4373
|
const where = `${at}["${placeholder}"]`;
|
|
4374
|
-
if (!isRecord$
|
|
4374
|
+
if (!isRecord$2(raw)) {
|
|
4375
4375
|
problems.push(`${where} is not an object`);
|
|
4376
4376
|
continue;
|
|
4377
4377
|
}
|
|
@@ -4395,7 +4395,7 @@ function readAttachments(value, bones, slots, label, problems) {
|
|
|
4395
4395
|
}
|
|
4396
4396
|
const geometry = readGeometry(raw, kind, where, bones, slots, problems);
|
|
4397
4397
|
if (geometry !== void 0) record.geometry = geometry;
|
|
4398
|
-
if (isRecord$
|
|
4398
|
+
if (isRecord$2(raw.sequence)) {
|
|
4399
4399
|
const count = raw.sequence.count;
|
|
4400
4400
|
if (typeof count === "number" && Number.isInteger(count) && count >= 1) record.sequenceCount = count;
|
|
4401
4401
|
else if (kind !== "region") problems.push(`${where}.sequence: count is ${JSON.stringify(count)}, not a whole number of at least 1`);
|
|
@@ -4419,7 +4419,7 @@ function readAttachments(value, bones, slots, label, problems) {
|
|
|
4419
4419
|
}
|
|
4420
4420
|
function readAtlasRect(value, where, problems) {
|
|
4421
4421
|
if (value === null) return null;
|
|
4422
|
-
if (!isRecord$
|
|
4422
|
+
if (!isRecord$2(value)) {
|
|
4423
4423
|
problems.push(`${where} is ${JSON.stringify(value)}, neither null nor an object`);
|
|
4424
4424
|
return void 0;
|
|
4425
4425
|
}
|
|
@@ -4439,7 +4439,7 @@ function readSkins(value, bones, slots, problems) {
|
|
|
4439
4439
|
const out = [];
|
|
4440
4440
|
value.forEach((raw, i) => {
|
|
4441
4441
|
const where = `skins[${i}]`;
|
|
4442
|
-
if (!isRecord$
|
|
4442
|
+
if (!isRecord$2(raw)) {
|
|
4443
4443
|
problems.push(`${where} is not an object`);
|
|
4444
4444
|
return;
|
|
4445
4445
|
}
|
|
@@ -4456,7 +4456,7 @@ function readSkins(value, bones, slots, problems) {
|
|
|
4456
4456
|
});
|
|
4457
4457
|
}
|
|
4458
4458
|
const lists = Object.fromEntries(CORE_CONSTRAINT_KINDS.map((k) => [k, []]));
|
|
4459
|
-
if (!isRecord$
|
|
4459
|
+
if (!isRecord$2(raw.constraints)) problems.push(`${label}: constraints is not an object`);
|
|
4460
4460
|
else {
|
|
4461
4461
|
for (const [kind, list] of Object.entries(raw.constraints)) {
|
|
4462
4462
|
const known = CORE_CONSTRAINT_KINDS.find((k) => k === kind);
|
|
@@ -4466,7 +4466,7 @@ function readSkins(value, bones, slots, problems) {
|
|
|
4466
4466
|
}
|
|
4467
4467
|
}
|
|
4468
4468
|
let attachments = {};
|
|
4469
|
-
if (!isRecord$
|
|
4469
|
+
if (!isRecord$2(raw.attachments)) problems.push(`${label}: attachments is not an object`);
|
|
4470
4470
|
else attachments = readAttachments(raw.attachments, bones, slots, label, problems);
|
|
4471
4471
|
out.push({ name: typeof raw.name === "string" ? raw.name : "", bones: members, constraints: lists, attachments });
|
|
4472
4472
|
});
|
|
@@ -4481,7 +4481,7 @@ function readAnimations(value, bones, slotRecords, skins, events, problems) {
|
|
|
4481
4481
|
const out = [];
|
|
4482
4482
|
value.forEach((raw, i) => {
|
|
4483
4483
|
const where = `animations[${i}]`;
|
|
4484
|
-
if (!isRecord$
|
|
4484
|
+
if (!isRecord$2(raw)) {
|
|
4485
4485
|
problems.push(`${where} is not an object`);
|
|
4486
4486
|
return;
|
|
4487
4487
|
}
|
|
@@ -4491,13 +4491,13 @@ function readAnimations(value, bones, slotRecords, skins, events, problems) {
|
|
|
4491
4491
|
if (!Array.isArray(raw.slots)) problems.push(`${label}: slots is not a list`);
|
|
4492
4492
|
else {
|
|
4493
4493
|
raw.slots.forEach((entry, j) => {
|
|
4494
|
-
if (!isRecord$
|
|
4494
|
+
if (!isRecord$2(entry) || typeof entry.name !== "string") problems.push(`${label}: slots[${j}] names no slot`);
|
|
4495
4495
|
else if (!slots.has(entry.name)) problems.push(`${label}: slots[${j}] "${entry.name}" is not a slot of this document`);
|
|
4496
4496
|
else keyed.push(entry.name);
|
|
4497
4497
|
});
|
|
4498
4498
|
}
|
|
4499
4499
|
const deforms = [];
|
|
4500
|
-
const list = (v) => Array.isArray(v) ? v.filter(isRecord$
|
|
4500
|
+
const list = (v) => Array.isArray(v) ? v.filter(isRecord$2) : [];
|
|
4501
4501
|
for (const skin of list(raw.attachments)) for (const slot of list(skin.slots)) for (const att of list(slot.attachments)) if (att.deform !== void 0) deforms.push(`${String(skin.name)}/${String(slot.name)}/${String(att.name)}`);
|
|
4502
4502
|
out.push({ name: typeof raw.name === "string" ? raw.name : "", slots: keyed, timelines: readAnimationTimelines(raw, label, bones, slotRecords, problems, { skins, events }), constraints: { ik: [], transform: [], path: [], physics: 0, slider: [] }, deforms });
|
|
4503
4503
|
});
|
|
@@ -4514,7 +4514,7 @@ function readConstraints(value, animations, bones, slots, referenceScale, proble
|
|
|
4514
4514
|
const out = [];
|
|
4515
4515
|
value.forEach((raw, i) => {
|
|
4516
4516
|
const where = `constraints[${i}]`;
|
|
4517
|
-
if (!isRecord$
|
|
4517
|
+
if (!isRecord$2(raw)) {
|
|
4518
4518
|
problems.push(`${where} is not an object`);
|
|
4519
4519
|
return;
|
|
4520
4520
|
}
|
|
@@ -4541,7 +4541,7 @@ function readModel(text, where = "the model document") {
|
|
|
4541
4541
|
} catch (err) {
|
|
4542
4542
|
throw new CoreInputError(`${where}: not JSON — ${err.message}`);
|
|
4543
4543
|
}
|
|
4544
|
-
if (!isRecord$
|
|
4544
|
+
if (!isRecord$2(value)) throw new CoreInputError(`${where}: not a JSON object`);
|
|
4545
4545
|
if (typeof value.spec !== "string" || !CORE_DOCUMENT_SPECS.includes(value.spec)) {
|
|
4546
4546
|
throw new CoreInputError(
|
|
4547
4547
|
`${where}: spec is ${JSON.stringify(value.spec)}, not "${CORE_DOCUMENT_SPEC}" (or "${CORE_DOCUMENT_SPEC_2}", read without its stage, editor order and page flags, or "${CORE_DOCUMENT_SPEC_1}", read without its pages too)`
|
|
@@ -4577,7 +4577,7 @@ function readModel(text, where = "the model document") {
|
|
|
4577
4577
|
}
|
|
4578
4578
|
if (Array.isArray(value.animations)) {
|
|
4579
4579
|
value.animations.forEach((raw, i) => {
|
|
4580
|
-
if (isRecord$
|
|
4580
|
+
if (isRecord$2(raw) && animations[i] !== void 0) animations[i].constraints = readConstraintTimelines(raw.constraints, `animations[${i}] "${animations[i].name}"`, constraints, problems);
|
|
4581
4581
|
});
|
|
4582
4582
|
}
|
|
4583
4583
|
for (const c of constraints) {
|
|
@@ -6266,21 +6266,21 @@ function meshPageUvs(region, page, art, reading = {}) {
|
|
|
6266
6266
|
function frameRegionName(path, sequence, frame2) {
|
|
6267
6267
|
return path + String(sequence.start + frame2).padStart(sequence.digits, "0");
|
|
6268
6268
|
}
|
|
6269
|
-
const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
6269
|
+
const isRecord$1 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
6270
6270
|
const whole = (v, min) => typeof v === "number" && Number.isInteger(v) && v >= min;
|
|
6271
6271
|
function readUvSequences(document2) {
|
|
6272
6272
|
const out = /* @__PURE__ */ new Map();
|
|
6273
6273
|
const problems = [];
|
|
6274
|
-
const skins = isRecord(document2) && Array.isArray(document2.skins) ? document2.skins : [];
|
|
6274
|
+
const skins = isRecord$1(document2) && Array.isArray(document2.skins) ? document2.skins : [];
|
|
6275
6275
|
skins.forEach((skin, k) => {
|
|
6276
|
-
if (!isRecord(skin) || typeof skin.name !== "string" || !isRecord(skin.attachments)) return;
|
|
6276
|
+
if (!isRecord$1(skin) || typeof skin.name !== "string" || !isRecord$1(skin.attachments)) return;
|
|
6277
6277
|
for (const [slot, table] of Object.entries(skin.attachments)) {
|
|
6278
|
-
if (!isRecord(table)) continue;
|
|
6278
|
+
if (!isRecord$1(table)) continue;
|
|
6279
6279
|
for (const [placeholder, record] of Object.entries(table)) {
|
|
6280
|
-
if (!isRecord(record) || record.sequence === void 0) continue;
|
|
6280
|
+
if (!isRecord$1(record) || record.sequence === void 0) continue;
|
|
6281
6281
|
const where = `skins[${k}] "${skin.name}".attachments["${slot}"]["${placeholder}"].sequence`;
|
|
6282
6282
|
const seq = record.sequence;
|
|
6283
|
-
if (!isRecord(seq)) {
|
|
6283
|
+
if (!isRecord$1(seq)) {
|
|
6284
6284
|
problems.push(`${where} is not an object`);
|
|
6285
6285
|
continue;
|
|
6286
6286
|
}
|
|
@@ -7003,6 +7003,17 @@ function clipNum(v) {
|
|
|
7003
7003
|
return Math.round(v * 1e3) / 1e3;
|
|
7004
7004
|
}
|
|
7005
7005
|
const CLIP_COORD_LIMIT = 1e9;
|
|
7006
|
+
function float32HalfUlp(value) {
|
|
7007
|
+
if (!Number.isFinite(value)) return 0;
|
|
7008
|
+
return 2 ** (Math.max(-149, Math.floor(Math.log2(Math.abs(value))) - 23) - 1);
|
|
7009
|
+
}
|
|
7010
|
+
function sameMeshCoordinate(relative, cached, world, offset) {
|
|
7011
|
+
if (relative === cached) return true;
|
|
7012
|
+
if (offset === 0) return false;
|
|
7013
|
+
const tolerance = float32HalfUlp(world);
|
|
7014
|
+
const residual = Math.abs(relative - cached);
|
|
7015
|
+
return residual < 0.5 && residual <= tolerance;
|
|
7016
|
+
}
|
|
7006
7017
|
const BLEND_CSS = {
|
|
7007
7018
|
Normal: "",
|
|
7008
7019
|
Additive: "plus-lighter",
|
|
@@ -7382,18 +7393,24 @@ class DomRenderer {
|
|
|
7382
7393
|
dirty = true;
|
|
7383
7394
|
}
|
|
7384
7395
|
const rel = view.meshVertices;
|
|
7385
|
-
|
|
7386
|
-
const
|
|
7387
|
-
const
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7396
|
+
if (!dirty) {
|
|
7397
|
+
const offsetX = minX - view.meshOriginX;
|
|
7398
|
+
const offsetY = minY - view.meshOriginY;
|
|
7399
|
+
for (let v = 0; v < count && !dirty; v += 2) {
|
|
7400
|
+
dirty = !sameMeshCoordinate(vertices[v] - minX, rel[v], vertices[v], offsetX) || !sameMeshCoordinate(vertices[v + 1] - minY, rel[v + 1], vertices[v + 1], offsetY);
|
|
7401
|
+
}
|
|
7391
7402
|
}
|
|
7392
7403
|
this.setTransform(view, `translate(${minX}px,${minY}px)`);
|
|
7393
7404
|
this.applyClip(view, 1, 0, 0, 1, minX, minY, view.canvasW / ratio, view.canvasH / ratio);
|
|
7394
7405
|
if (!dirty) {
|
|
7395
7406
|
this.meshReuseCount++;
|
|
7396
7407
|
} else {
|
|
7408
|
+
for (let v = 0; v < count; v += 2) {
|
|
7409
|
+
rel[v] = vertices[v] - minX;
|
|
7410
|
+
rel[v + 1] = vertices[v + 1] - minY;
|
|
7411
|
+
}
|
|
7412
|
+
view.meshOriginX = minX;
|
|
7413
|
+
view.meshOriginY = minY;
|
|
7397
7414
|
view.meshUvs = uvs;
|
|
7398
7415
|
view.meshTriangles = triangles;
|
|
7399
7416
|
view.meshPage = page;
|
|
@@ -7762,6 +7779,8 @@ class DomRenderer {
|
|
|
7762
7779
|
meshVertexCount: -1,
|
|
7763
7780
|
meshBackendDrawn: "",
|
|
7764
7781
|
meshVertices: new Float64Array(0),
|
|
7782
|
+
meshOriginX: 0,
|
|
7783
|
+
meshOriginY: 0,
|
|
7765
7784
|
drawnIn: 0
|
|
7766
7785
|
};
|
|
7767
7786
|
this.views.set(slot, view);
|
|
@@ -8323,6 +8342,136 @@ function affine(u0, v0, u1, v1, u2, v2, x0, y0, x1, y1, x2, y2) {
|
|
|
8323
8342
|
const d = (eu1 * ey2 - eu2 * ey1) * inv;
|
|
8324
8343
|
return [a, b, c, d, x0 - a * u0 - c * v0, y0 - b * u0 - d * v0];
|
|
8325
8344
|
}
|
|
8345
|
+
const SETS_SPECS = ["spine-parts-sets/1", "rig-parts-sets/1"];
|
|
8346
|
+
function isRecord(value) {
|
|
8347
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8348
|
+
}
|
|
8349
|
+
function readSetsText(text, where, doc) {
|
|
8350
|
+
let raw;
|
|
8351
|
+
try {
|
|
8352
|
+
raw = JSON.parse(text);
|
|
8353
|
+
} catch (error) {
|
|
8354
|
+
throw new Error(`${where}: not JSON — ${error.message}`);
|
|
8355
|
+
}
|
|
8356
|
+
if (!isRecord(raw)) {
|
|
8357
|
+
throw new Error(`${where}: sets document must be a JSON object`);
|
|
8358
|
+
}
|
|
8359
|
+
if (raw.spec !== SETS_SPECS[0] && raw.spec !== SETS_SPECS[1]) {
|
|
8360
|
+
throw new Error(
|
|
8361
|
+
`${where}: spec is ${JSON.stringify(raw.spec)}, not "${SETS_SPECS[0]}" or "${SETS_SPECS[1]}"`
|
|
8362
|
+
);
|
|
8363
|
+
}
|
|
8364
|
+
if (!isRecord(raw.sets) && !Array.isArray(raw.sets)) {
|
|
8365
|
+
throw new Error(`${where}: "sets" must be an object or an array`);
|
|
8366
|
+
}
|
|
8367
|
+
const knownSlots = new Set(doc.slots.map((slot) => slot.name));
|
|
8368
|
+
const attachmentsBySlot = /* @__PURE__ */ new Map();
|
|
8369
|
+
for (const skin of doc.skins) {
|
|
8370
|
+
for (const [slotName, table] of Object.entries(skin.attachments)) {
|
|
8371
|
+
let set = attachmentsBySlot.get(slotName);
|
|
8372
|
+
if (!set) {
|
|
8373
|
+
set = /* @__PURE__ */ new Set();
|
|
8374
|
+
attachmentsBySlot.set(slotName, set);
|
|
8375
|
+
}
|
|
8376
|
+
for (const attName of Object.keys(table)) set.add(attName);
|
|
8377
|
+
}
|
|
8378
|
+
}
|
|
8379
|
+
const entries = [];
|
|
8380
|
+
if (Array.isArray(raw.sets)) {
|
|
8381
|
+
for (let i = 0; i < raw.sets.length; i++) {
|
|
8382
|
+
const item = raw.sets[i];
|
|
8383
|
+
if (!isRecord(item) || typeof item.name !== "string" || item.name.length === 0) {
|
|
8384
|
+
throw new Error(`${where}: sets[${i}] must be an object with a non-empty "name"`);
|
|
8385
|
+
}
|
|
8386
|
+
entries.push([item.name, item]);
|
|
8387
|
+
}
|
|
8388
|
+
} else {
|
|
8389
|
+
for (const [name, item] of Object.entries(raw.sets)) {
|
|
8390
|
+
if (name.length === 0 || !isRecord(item)) {
|
|
8391
|
+
throw new Error(`${where}: set "${name}" must be an object`);
|
|
8392
|
+
}
|
|
8393
|
+
entries.push([name, item]);
|
|
8394
|
+
}
|
|
8395
|
+
}
|
|
8396
|
+
const out = [];
|
|
8397
|
+
const seenNames = /* @__PURE__ */ new Set();
|
|
8398
|
+
for (const [name, item] of entries) {
|
|
8399
|
+
if (seenNames.has(name)) {
|
|
8400
|
+
throw new Error(`${where}: duplicate set "${name}"`);
|
|
8401
|
+
}
|
|
8402
|
+
seenNames.add(name);
|
|
8403
|
+
if (!isRecord(item.slots)) {
|
|
8404
|
+
throw new Error(`${where}: set "${name}" must have a "slots" object`);
|
|
8405
|
+
}
|
|
8406
|
+
const slots = {};
|
|
8407
|
+
for (const [slotName, attName] of Object.entries(item.slots)) {
|
|
8408
|
+
if (!knownSlots.has(slotName)) {
|
|
8409
|
+
throw new Error(`${where}: set "${name}" names unknown slot "${slotName}"`);
|
|
8410
|
+
}
|
|
8411
|
+
if (typeof attName !== "string" || attName.length === 0) {
|
|
8412
|
+
throw new Error(`${where}: set "${name}" slot "${slotName}" attachment must be a non-empty string`);
|
|
8413
|
+
}
|
|
8414
|
+
if (!attachmentsBySlot.get(slotName)?.has(attName)) {
|
|
8415
|
+
throw new Error(`${where}: set "${name}" maps slot "${slotName}" to unknown attachment "${attName}"`);
|
|
8416
|
+
}
|
|
8417
|
+
slots[slotName] = attName;
|
|
8418
|
+
}
|
|
8419
|
+
const hides = [];
|
|
8420
|
+
if (item.hides !== void 0) {
|
|
8421
|
+
if (!Array.isArray(item.hides)) {
|
|
8422
|
+
throw new Error(`${where}: set "${name}" "hides" must be an array of slot names`);
|
|
8423
|
+
}
|
|
8424
|
+
for (const hidden of item.hides) {
|
|
8425
|
+
if (typeof hidden !== "string" || hidden.length === 0) {
|
|
8426
|
+
throw new Error(`${where}: set "${name}" "hides" entries must be non-empty strings`);
|
|
8427
|
+
}
|
|
8428
|
+
if (!knownSlots.has(hidden)) {
|
|
8429
|
+
throw new Error(`${where}: set "${name}" hides unknown slot "${hidden}"`);
|
|
8430
|
+
}
|
|
8431
|
+
if (Object.prototype.hasOwnProperty.call(slots, hidden)) {
|
|
8432
|
+
throw new Error(`${where}: set "${name}" both replaces and hides slot "${hidden}"`);
|
|
8433
|
+
}
|
|
8434
|
+
if (!hides.includes(hidden)) hides.push(hidden);
|
|
8435
|
+
}
|
|
8436
|
+
}
|
|
8437
|
+
out.push(
|
|
8438
|
+
Object.freeze({
|
|
8439
|
+
name,
|
|
8440
|
+
slots: Object.freeze(slots),
|
|
8441
|
+
hides: Object.freeze(hides)
|
|
8442
|
+
})
|
|
8443
|
+
);
|
|
8444
|
+
}
|
|
8445
|
+
return Object.freeze(out);
|
|
8446
|
+
}
|
|
8447
|
+
async function loadSets(fetchImpl, modelUrl, setsUrlOption, doc) {
|
|
8448
|
+
if (setsUrlOption === null) return Object.freeze([]);
|
|
8449
|
+
if (typeof setsUrlOption === "string") {
|
|
8450
|
+
const text2 = await fetchText(fetchImpl, setsUrlOption);
|
|
8451
|
+
return readSetsText(text2, setsUrlOption, doc);
|
|
8452
|
+
}
|
|
8453
|
+
const url = resolveAgainstModel("sets.json", modelUrl);
|
|
8454
|
+
let response;
|
|
8455
|
+
try {
|
|
8456
|
+
response = await fetchImpl(url);
|
|
8457
|
+
} catch {
|
|
8458
|
+
return Object.freeze([]);
|
|
8459
|
+
}
|
|
8460
|
+
if (!response.ok) return Object.freeze([]);
|
|
8461
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
8462
|
+
if (contentType.includes("text/html")) return Object.freeze([]);
|
|
8463
|
+
const text = await response.text();
|
|
8464
|
+
const trimmed = text.trimStart();
|
|
8465
|
+
if (trimmed.length === 0 || trimmed.startsWith("<")) return Object.freeze([]);
|
|
8466
|
+
try {
|
|
8467
|
+
const parsed = JSON.parse(trimmed);
|
|
8468
|
+
if (isRecord(parsed) && typeof parsed.spec === "string" && parsed.spec.startsWith("rigc-compiled/")) {
|
|
8469
|
+
return Object.freeze([]);
|
|
8470
|
+
}
|
|
8471
|
+
} catch {
|
|
8472
|
+
}
|
|
8473
|
+
return readSetsText(text, url, doc);
|
|
8474
|
+
}
|
|
8326
8475
|
function stageOf(doc) {
|
|
8327
8476
|
const stage = doc.stated?.stage;
|
|
8328
8477
|
return stage ? { x: stage.x, y: stage.y, width: stage.width, height: stage.height } : null;
|
|
@@ -8386,12 +8535,14 @@ async function loadModel(options) {
|
|
|
8386
8535
|
pageImages.set(page.name, await loadImage(resolvePage(page.name, modelUrl), crossOrigin));
|
|
8387
8536
|
})
|
|
8388
8537
|
);
|
|
8538
|
+
const sets = await loadSets(fetchImpl, modelUrl, options.setsUrl, read.doc);
|
|
8389
8539
|
const regionImages = regions === "none" ? /* @__PURE__ */ new Map() : await unpackRegions(pages, pageImages, { encoding: regions });
|
|
8390
8540
|
let disposed = false;
|
|
8391
8541
|
return {
|
|
8392
8542
|
spec: read.spec,
|
|
8393
8543
|
animations: read.doc.animations.map((a) => ({ name: a.name, duration: a.timelines.duration })),
|
|
8394
8544
|
skins: read.doc.skins.map((s) => s.name),
|
|
8545
|
+
sets,
|
|
8395
8546
|
stage: stageOf(read.doc),
|
|
8396
8547
|
regions,
|
|
8397
8548
|
regionImages,
|
|
@@ -8547,6 +8698,84 @@ function predicateOf(names) {
|
|
|
8547
8698
|
const allowed = new Set(names);
|
|
8548
8699
|
return (slot) => allowed.has(slot);
|
|
8549
8700
|
}
|
|
8701
|
+
function applySetToPose(view, raw, set) {
|
|
8702
|
+
const coveredNames = new Set(Object.keys(set.slots));
|
|
8703
|
+
const hiddenNames = new Set(set.hides);
|
|
8704
|
+
const overrideSlots = view.slots.flatMap((slot) => {
|
|
8705
|
+
const setup = set.slots[slot.name];
|
|
8706
|
+
return setup !== void 0 ? [{ ...slot, setup }] : [];
|
|
8707
|
+
});
|
|
8708
|
+
const world = new Map(
|
|
8709
|
+
raw.bones.map((bone2) => [
|
|
8710
|
+
bone2.name,
|
|
8711
|
+
{ a: bone2.a, b: bone2.b, c: bone2.c, d: bone2.d, worldX: bone2.worldX, worldY: bone2.worldY }
|
|
8712
|
+
])
|
|
8713
|
+
);
|
|
8714
|
+
const overridePose = overrideSlots.length > 0 ? poseRawSetup(
|
|
8715
|
+
{ ...view, slots: overrideSlots, constraints: [] },
|
|
8716
|
+
{ evaluate: () => world, constraints: () => [] }
|
|
8717
|
+
) : null;
|
|
8718
|
+
const overRowBySlot = /* @__PURE__ */ new Map();
|
|
8719
|
+
const overShownBySlot = /* @__PURE__ */ new Map();
|
|
8720
|
+
const overDrawnBySlot = /* @__PURE__ */ new Map();
|
|
8721
|
+
const overClipBySlot = /* @__PURE__ */ new Map();
|
|
8722
|
+
if (overridePose !== null) {
|
|
8723
|
+
for (const row of overridePose.slots) overRowBySlot.set(row[0], row);
|
|
8724
|
+
for (const s of overridePose.shown) overShownBySlot.set(s.slot, s);
|
|
8725
|
+
for (const d of overridePose.drawn) overDrawnBySlot.set(d.slot, d);
|
|
8726
|
+
for (const c of overridePose.clips) overClipBySlot.set(c[0], c);
|
|
8727
|
+
}
|
|
8728
|
+
const rawShownBySlot = new Map(raw.shown.map((s) => [s.slot, s]));
|
|
8729
|
+
const rawDrawnBySlot = new Map(raw.drawn.map((d) => [d.slot, d]));
|
|
8730
|
+
const rawClipBySlot = new Map(raw.clips.map((c) => [c[0], c]));
|
|
8731
|
+
const hiddenSlot = (slotName) => {
|
|
8732
|
+
if (hiddenNames.has(slotName)) return true;
|
|
8733
|
+
if (slotName.endsWith("_still") && !coveredNames.has(slotName)) {
|
|
8734
|
+
const base = slotName.slice(0, -"_still".length);
|
|
8735
|
+
if (coveredNames.has(base) || hiddenNames.has(base)) return true;
|
|
8736
|
+
}
|
|
8737
|
+
return false;
|
|
8738
|
+
};
|
|
8739
|
+
const slots = raw.slots.map((rawRow) => {
|
|
8740
|
+
const slotName = rawRow[0];
|
|
8741
|
+
if (hiddenSlot(slotName)) {
|
|
8742
|
+
return [slotName, null, rawRow[2], rawRow[3], rawRow[4], rawRow[5], rawRow[6], null, rawRow[8]];
|
|
8743
|
+
}
|
|
8744
|
+
const overRow = overRowBySlot.get(slotName);
|
|
8745
|
+
if (overRow !== void 0) {
|
|
8746
|
+
return [slotName, overRow[1], rawRow[2], rawRow[3], rawRow[4], rawRow[5], rawRow[6], overRow[7], rawRow[8]];
|
|
8747
|
+
}
|
|
8748
|
+
return rawRow;
|
|
8749
|
+
});
|
|
8750
|
+
const shown = [];
|
|
8751
|
+
const drawn = [];
|
|
8752
|
+
const clips = [];
|
|
8753
|
+
for (const slotName of raw.drawOrder) {
|
|
8754
|
+
if (hiddenSlot(slotName)) continue;
|
|
8755
|
+
if (coveredNames.has(slotName)) {
|
|
8756
|
+
const s = overShownBySlot.get(slotName);
|
|
8757
|
+
if (s !== void 0) shown.push(s);
|
|
8758
|
+
const d = overDrawnBySlot.get(slotName);
|
|
8759
|
+
if (d !== void 0) drawn.push(d);
|
|
8760
|
+
const c = overClipBySlot.get(slotName);
|
|
8761
|
+
if (c !== void 0) clips.push(c);
|
|
8762
|
+
} else {
|
|
8763
|
+
const s = rawShownBySlot.get(slotName);
|
|
8764
|
+
if (s !== void 0) shown.push(s);
|
|
8765
|
+
const d = rawDrawnBySlot.get(slotName);
|
|
8766
|
+
if (d !== void 0) drawn.push(d);
|
|
8767
|
+
const c = rawClipBySlot.get(slotName);
|
|
8768
|
+
if (c !== void 0) clips.push(c);
|
|
8769
|
+
}
|
|
8770
|
+
}
|
|
8771
|
+
return {
|
|
8772
|
+
...raw,
|
|
8773
|
+
slots,
|
|
8774
|
+
shown,
|
|
8775
|
+
drawn,
|
|
8776
|
+
clips
|
|
8777
|
+
};
|
|
8778
|
+
}
|
|
8550
8779
|
class RigPlayer {
|
|
8551
8780
|
/**
|
|
8552
8781
|
* The renderer this player draws through — its knobs and counters are the
|
|
@@ -8598,7 +8827,12 @@ class RigPlayer {
|
|
|
8598
8827
|
beyondBase = false;
|
|
8599
8828
|
paused = false;
|
|
8600
8829
|
pose = null;
|
|
8830
|
+
/** The un-overridden pose from the track/tracks (or setup pose when `setSet` is called before `play`). */
|
|
8831
|
+
rawPose = null;
|
|
8601
8832
|
setup = null;
|
|
8833
|
+
setList;
|
|
8834
|
+
setsByName;
|
|
8835
|
+
activeSet = null;
|
|
8602
8836
|
adjustFn = null;
|
|
8603
8837
|
slotFilter = null;
|
|
8604
8838
|
/** `slotFilter` as a predicate; every slot when null. */
|
|
@@ -8622,6 +8856,8 @@ class RigPlayer {
|
|
|
8622
8856
|
if (!(this.seekStep > 0)) throw new Error(`seekStep must be a positive number of seconds, got ${String(options.seekStep)}`);
|
|
8623
8857
|
this.root = root;
|
|
8624
8858
|
this.assets = assets;
|
|
8859
|
+
this.setList = assets.sets ?? [];
|
|
8860
|
+
this.setsByName = new Map(this.setList.map((s) => [s.name, s]));
|
|
8625
8861
|
this.meshBackend = options.meshBackend;
|
|
8626
8862
|
this.adjustFn = options.adjust ?? null;
|
|
8627
8863
|
if (options.slots !== void 0 && options.slots !== null) this.slots = options.slots;
|
|
@@ -8697,7 +8933,7 @@ class RigPlayer {
|
|
|
8697
8933
|
this.animation = name;
|
|
8698
8934
|
this.loop = loop;
|
|
8699
8935
|
this.track = openTrack(this.view, name, { loop, reset: "animation", adjust: this.adjustHook, clock: physicsClockStep });
|
|
8700
|
-
this.
|
|
8936
|
+
this.setRawPose(this.track.first);
|
|
8701
8937
|
this.applyEnvironment(this.track);
|
|
8702
8938
|
return;
|
|
8703
8939
|
}
|
|
@@ -8708,7 +8944,7 @@ class RigPlayer {
|
|
|
8708
8944
|
this.animation = name;
|
|
8709
8945
|
this.loop = loop;
|
|
8710
8946
|
}
|
|
8711
|
-
this.
|
|
8947
|
+
this.setRawPose(tracks.step(0));
|
|
8712
8948
|
}
|
|
8713
8949
|
/**
|
|
8714
8950
|
* Queues `name` after the last entry on `track` (`QueueOptions`): with
|
|
@@ -8722,7 +8958,7 @@ class RigPlayer {
|
|
|
8722
8958
|
const tracks = this.compose();
|
|
8723
8959
|
tracks.addAnimation(track, name, { loop: options.loop ?? true, mixDuration: options.mix ?? 0, delay: options.delay ?? 0, alpha: options.alpha ?? 1, additive: options.additive ?? false });
|
|
8724
8960
|
this.trackCount = Math.max(this.trackCount, track + 1);
|
|
8725
|
-
this.
|
|
8961
|
+
this.setRawPose(tracks.step(0));
|
|
8726
8962
|
}
|
|
8727
8963
|
/**
|
|
8728
8964
|
* Mixes `track` out to nothing over `mix` seconds — the layer or one-shot
|
|
@@ -8734,7 +8970,7 @@ class RigPlayer {
|
|
|
8734
8970
|
const tracks = this.compose();
|
|
8735
8971
|
tracks.setEmptyAnimation(track, options.mix ?? 0);
|
|
8736
8972
|
this.trackCount = Math.max(this.trackCount, track + 1);
|
|
8737
|
-
this.
|
|
8973
|
+
this.setRawPose(tracks.step(0));
|
|
8738
8974
|
}
|
|
8739
8975
|
/**
|
|
8740
8976
|
* Queues a mix out to nothing after the last entry on `track`, over `mix`
|
|
@@ -8747,7 +8983,7 @@ class RigPlayer {
|
|
|
8747
8983
|
const tracks = this.compose();
|
|
8748
8984
|
tracks.addEmptyAnimation(track, options.mix ?? 0, options.delay ?? 0);
|
|
8749
8985
|
this.trackCount = Math.max(this.trackCount, track + 1);
|
|
8750
|
-
this.
|
|
8986
|
+
this.setRawPose(tracks.step(0));
|
|
8751
8987
|
}
|
|
8752
8988
|
/**
|
|
8753
8989
|
* Sets the weight of `track`'s current entry, from 0 to 1, from the next pose
|
|
@@ -8760,7 +8996,7 @@ class RigPlayer {
|
|
|
8760
8996
|
this.beyondBase = true;
|
|
8761
8997
|
const tracks = this.compose();
|
|
8762
8998
|
tracks.setAlpha(track, alpha);
|
|
8763
|
-
this.
|
|
8999
|
+
this.setRawPose(tracks.step(0));
|
|
8764
9000
|
}
|
|
8765
9001
|
/** `track`'s current entry, or null where it plays nothing (and before `play`). */
|
|
8766
9002
|
entry(track = 0) {
|
|
@@ -8797,11 +9033,16 @@ class RigPlayer {
|
|
|
8797
9033
|
}
|
|
8798
9034
|
this.tracks = tracks;
|
|
8799
9035
|
this.track = null;
|
|
8800
|
-
this.
|
|
9036
|
+
this.setRawPose(tracks.start());
|
|
8801
9037
|
this.applyEnvironment(tracks);
|
|
8802
9038
|
if (time > 0) this.stepTo(time);
|
|
8803
9039
|
return tracks;
|
|
8804
9040
|
}
|
|
9041
|
+
/** Stores `raw` and applies `activeSet` when one is active. Zero work when `activeSet === null`. */
|
|
9042
|
+
setRawPose(raw) {
|
|
9043
|
+
this.rawPose = raw;
|
|
9044
|
+
this.pose = this.activeSet === null ? raw : applySetToPose(this.view, raw, this.activeSet);
|
|
9045
|
+
}
|
|
8805
9046
|
/**
|
|
8806
9047
|
* The world the rig's physics answers (#121): `wind` and `gravity`, as
|
|
8807
9048
|
* spine-core's skeleton-level `windX/windY` and `gravityX/gravityY` — x to
|
|
@@ -8881,12 +9122,12 @@ class RigPlayer {
|
|
|
8881
9122
|
tracks.setAnimation(0, this.animation, { loop: this.loop, mixDuration: 0 });
|
|
8882
9123
|
this.trackCount = 1;
|
|
8883
9124
|
this.tracks = tracks;
|
|
8884
|
-
this.
|
|
9125
|
+
this.setRawPose(tracks.start());
|
|
8885
9126
|
this.applyEnvironment(tracks);
|
|
8886
9127
|
return;
|
|
8887
9128
|
}
|
|
8888
9129
|
this.track = openTrack(this.view, this.animation, { loop: this.loop, reset: "animation", adjust: this.adjustHook, clock: physicsClockStep });
|
|
8889
|
-
this.
|
|
9130
|
+
this.setRawPose(this.track.first);
|
|
8890
9131
|
this.applyEnvironment(this.track);
|
|
8891
9132
|
}
|
|
8892
9133
|
/** What is open: the tracks, the single track, or nothing before `play`. */
|
|
@@ -8901,9 +9142,10 @@ class RigPlayer {
|
|
|
8901
9142
|
stepTo(time) {
|
|
8902
9143
|
const stepper = this.tracks ?? this.track;
|
|
8903
9144
|
const steps = Math.floor(time / this.seekStep);
|
|
8904
|
-
for (let i = 0; i < steps; i++) this.
|
|
9145
|
+
for (let i = 0; i < steps; i++) this.rawPose = stepper.step(this.seekStep);
|
|
8905
9146
|
const rest = time - stepper.trackTime;
|
|
8906
|
-
if (rest > 0) this.
|
|
9147
|
+
if (rest > 0) this.rawPose = stepper.step(rest);
|
|
9148
|
+
if (this.rawPose !== null) this.setRawPose(this.rawPose);
|
|
8907
9149
|
}
|
|
8908
9150
|
on(type, listener) {
|
|
8909
9151
|
const set = this.listeners[type];
|
|
@@ -8936,15 +9178,17 @@ class RigPlayer {
|
|
|
8936
9178
|
if (tracks !== null) {
|
|
8937
9179
|
const before2 = [];
|
|
8938
9180
|
for (let t = 0; t < this.trackCount; t++) before2.push(tracks.current(t));
|
|
8939
|
-
|
|
8940
|
-
this.
|
|
9181
|
+
const raw2 = tracks.step(step);
|
|
9182
|
+
this.setRawPose(raw2);
|
|
9183
|
+
this.dispatch(raw2, before2, tracks);
|
|
8941
9184
|
return;
|
|
8942
9185
|
}
|
|
8943
9186
|
const track = this.track;
|
|
8944
9187
|
if (track === null) return;
|
|
8945
9188
|
const before = track.trackTime;
|
|
8946
|
-
|
|
8947
|
-
this.
|
|
9189
|
+
const raw = track.step(step);
|
|
9190
|
+
this.setRawPose(raw);
|
|
9191
|
+
this.dispatchSingle(raw, before, track);
|
|
8948
9192
|
}
|
|
8949
9193
|
/** Draws the pose the player holds. */
|
|
8950
9194
|
draw() {
|
|
@@ -8976,7 +9220,59 @@ class RigPlayer {
|
|
|
8976
9220
|
const time = this.time;
|
|
8977
9221
|
this.reopen();
|
|
8978
9222
|
this.stepTo(time);
|
|
9223
|
+
} else if (this.rawPose !== null) {
|
|
9224
|
+
this.setup = poseRawSetup(this.view);
|
|
9225
|
+
this.setRawPose(this.setup);
|
|
9226
|
+
}
|
|
9227
|
+
}
|
|
9228
|
+
/**
|
|
9229
|
+
* The named attachment sets declared in `sets.json` (`ModelAssets.sets`),
|
|
9230
|
+
* with the slots each covers (`slots`) and hides (`hides`). Empty (`[]`)
|
|
9231
|
+
* when the build has no `sets.json`.
|
|
9232
|
+
*/
|
|
9233
|
+
sets() {
|
|
9234
|
+
return this.setList;
|
|
9235
|
+
}
|
|
9236
|
+
/** The currently active attachment set's name, or `null` when the base attachments are active. */
|
|
9237
|
+
get set() {
|
|
9238
|
+
return this.activeSet?.name ?? null;
|
|
9239
|
+
}
|
|
9240
|
+
/**
|
|
9241
|
+
* Switches the active attachment set (#134): every slot the set covers takes
|
|
9242
|
+
* the set's attachment (`null` restores the base / track attachments), and
|
|
9243
|
+
* every slot the set `hides` (plus any `<base>_still` slot of a covered or
|
|
9244
|
+
* hidden base slot) is hidden. Applied immediately to the pose the player
|
|
9245
|
+
* holds (including the setup pose before `play`) and after track evaluation
|
|
9246
|
+
* on every subsequent `advance`, so a track key on a covered slot is
|
|
9247
|
+
* overridden while the set is active and restored when cleared (`setSet(null)`).
|
|
9248
|
+
* Uncovered slots keep their track attachments, mesh deforms and sequence
|
|
9249
|
+
* frames untouched; when no set is active (`null`), track evaluation runs
|
|
9250
|
+
* with zero overhead and produces byte-identical poses.
|
|
9251
|
+
*
|
|
9252
|
+
* A name not in `sets.json` throws by name; a build without `sets.json` has
|
|
9253
|
+
* `sets()` empty and `setSet` throws.
|
|
9254
|
+
*/
|
|
9255
|
+
setSet(name) {
|
|
9256
|
+
if (this.setList.length === 0) {
|
|
9257
|
+
throw new Error(`cannot setSet(${JSON.stringify(name)}): this model has no sets.json`);
|
|
9258
|
+
}
|
|
9259
|
+
if (name === null) {
|
|
9260
|
+
this.activeSet = null;
|
|
9261
|
+
const base2 = this.rawPose ?? (this.setup ?? (this.setup = poseRawSetup(this.view)));
|
|
9262
|
+
this.rawPose = base2;
|
|
9263
|
+
this.pose = base2;
|
|
9264
|
+
return;
|
|
9265
|
+
}
|
|
9266
|
+
const found = this.setsByName.get(name);
|
|
9267
|
+
if (found === void 0) {
|
|
9268
|
+
throw new Error(
|
|
9269
|
+
`no set named ${JSON.stringify(name)} in sets.json (available: ${this.setList.map((s) => s.name).join(", ")})`
|
|
9270
|
+
);
|
|
8979
9271
|
}
|
|
9272
|
+
this.activeSet = found;
|
|
9273
|
+
const base = this.rawPose ?? (this.setup ?? (this.setup = poseRawSetup(this.view)));
|
|
9274
|
+
this.rawPose = base;
|
|
9275
|
+
this.pose = applySetToPose(this.view, base, found);
|
|
8980
9276
|
}
|
|
8981
9277
|
/**
|
|
8982
9278
|
* Which slots this player draws (`SlotFilter`), or null for every slot.
|
|
@@ -9035,7 +9331,7 @@ class RigPlayer {
|
|
|
9035
9331
|
repose() {
|
|
9036
9332
|
const stepper = this.tracks ?? this.track;
|
|
9037
9333
|
if (stepper === null || this.pose === null) return;
|
|
9038
|
-
this.
|
|
9334
|
+
this.setRawPose(stepper.step(0));
|
|
9039
9335
|
}
|
|
9040
9336
|
/**
|
|
9041
9337
|
* Where `name` is in the pose the player holds — the pose of the last
|
|
@@ -9108,7 +9404,7 @@ class RigPlayer {
|
|
|
9108
9404
|
posed() {
|
|
9109
9405
|
if (this.pose !== null) return this.pose;
|
|
9110
9406
|
if (this.setup === null) this.setup = poseRawSetup(this.view);
|
|
9111
|
-
return this.setup;
|
|
9407
|
+
return this.activeSet === null ? this.setup : applySetToPose(this.view, this.setup, this.activeSet);
|
|
9112
9408
|
}
|
|
9113
9409
|
/**
|
|
9114
9410
|
* The pose the player holds, as the frame record the renderer draws — under
|
|
@@ -9128,6 +9424,7 @@ class RigPlayer {
|
|
|
9128
9424
|
this.tracks = null;
|
|
9129
9425
|
this.track = null;
|
|
9130
9426
|
this.pose = null;
|
|
9427
|
+
this.rawPose = null;
|
|
9131
9428
|
}
|
|
9132
9429
|
/** The single track's step: its events (track 0) and its complete, as every 1.x player fired them. */
|
|
9133
9430
|
dispatchSingle(pose, before, track) {
|