@flighthq/skeleton2d 0.2.1-next.841.373388f → 0.3.0-edge.1516.1b4fb2b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/applyAnimationClipToSkeleton2D.d.ts +2 -2
- package/dist/applyAnimationClipToSkeleton2D.d.ts.map +1 -1
- package/dist/applyAnimationClipToSkeleton2D.js +110 -21
- package/dist/applyAnimationClipToSkeleton2D.js.map +1 -1
- package/dist/contract.d.ts +5 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +5 -0
- package/dist/contract.js.map +1 -0
- package/dist/deformMeshAttachment2D.d.ts +1 -1
- package/dist/deformMeshAttachment2D.d.ts.map +1 -1
- package/dist/index.d.ts +1 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -4
- package/dist/index.js.map +1 -1
- package/dist/regionAttachment2D.d.ts +1 -1
- package/dist/regionAttachment2D.d.ts.map +1 -1
- package/dist/regionAttachment2D.js +2 -2
- package/dist/regionAttachment2D.js.map +1 -1
- package/dist/skeleton2d.d.ts +3 -1
- package/dist/skeleton2d.d.ts.map +1 -1
- package/dist/skeleton2d.js +95 -61
- package/dist/skeleton2d.js.map +1 -1
- package/package.json +10 -6
- package/src/applyAnimationClipToSkeleton2D.test.ts +133 -21
- package/src/deformMeshAttachment2D.test.ts +2 -2
- package/src/regionAttachment2D.test.ts +2 -2
- package/src/skeleton2d.test.ts +188 -3
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { AnimationClip, Skeleton2D } from '@flighthq/types';
|
|
2
|
-
export declare function applyAnimationClipToSkeleton2D(clip: Readonly<AnimationClip>,
|
|
1
|
+
import type { AnimationClip, Skeleton2D } from '@flighthq/types/contract';
|
|
2
|
+
export declare function applyAnimationClipToSkeleton2D(clip: Readonly<AnimationClip>, setup: Readonly<Skeleton2D>, pose: Skeleton2D, time: number): void;
|
|
3
3
|
//# sourceMappingURL=applyAnimationClipToSkeleton2D.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applyAnimationClipToSkeleton2D.d.ts","sourceRoot":"","sources":["../src/applyAnimationClipToSkeleton2D.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"applyAnimationClipToSkeleton2D.d.ts","sourceRoot":"","sources":["../src/applyAnimationClipToSkeleton2D.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,aAAa,EACb,UAAU,EAIX,MAAM,0BAA0B,CAAC;AA0BlC,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,QAAQ,CAAC,aAAa,CAAC,EAC7B,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC3B,IAAI,EAAE,UAAU,EAChB,IAAI,EAAE,MAAM,GACX,IAAI,CA6CN"}
|
|
@@ -1,45 +1,134 @@
|
|
|
1
|
-
import { sampleAnimationTrack } from '@flighthq/animation';
|
|
2
|
-
import { Skeleton2DAnimationPath } from '@flighthq/types';
|
|
3
|
-
// Poses
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
// `
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
|
|
1
|
+
import { sampleAnimationTrack } from '@flighthq/animation/contract';
|
|
2
|
+
import { Skeleton2DAnimationPath, Skeleton2DSlotAnimationPath } from '@flighthq/types/contract';
|
|
3
|
+
// Poses `pose` from an AnimationClip at `time` by COMPOSING each channel's sampled value onto the
|
|
4
|
+
// corresponding `setup` bone — the 2D-skeletal analogue of @flighthq/scene3d's `applyAnimationClipToScene3D`,
|
|
5
|
+
// but relative rather than absolute. This mirrors Spine's SkeletonData(setup)/Skeleton(instance) split:
|
|
6
|
+
// `setup` is the immutable rest pose, `pose` is the animated instance (typically a `cloneSkeleton2D(setup)`),
|
|
7
|
+
// and a clip carries RELATIVE deltas — translate/rotate/shear ADD to setup, scale MULTIPLIES it (Spine's
|
|
8
|
+
// timeline semantics; the `path` distinguishes which). Composing from `setup` every call (not from `pose`)
|
|
9
|
+
// is what makes clips blendable — a mixer accumulates deltas as `pose = setup + Σ wᵢ·deltaᵢ`, which averaging
|
|
10
|
+
// baked-absolute poses cannot express — and is why re-applying a clip does not accumulate across frames.
|
|
11
|
+
//
|
|
12
|
+
// A clip may also carry SLOT channels (a `Skeleton2DSlotAnimationTarget` rather than a bone target). Those
|
|
13
|
+
// are dispatched by target SHAPE and follow different rules: a slot colour is an ABSOLUTE authored value, so
|
|
14
|
+
// it is written rather than composed, and `setup` is not consulted at all on that path. See
|
|
15
|
+
// applySkeleton2DSlotChannel.
|
|
16
|
+
//
|
|
17
|
+
// It writes only the bones a channel targets; untouched pose bones keep their clone-of-setup values. The
|
|
18
|
+
// caller runs `computeSkeleton2DWorldTransforms(pose, …)` (then the deform) afterward, so a whole clip
|
|
19
|
+
// applies before one world propagation. Module scratch, allocation-free. A channel whose target is foreign
|
|
20
|
+
// (not a Skeleton2DAnimationTarget) or out of range is skipped (sentinel guard, no throw).
|
|
21
|
+
//
|
|
22
|
+
// This is the documented exception to the out-param aliasing rule: `setup` is read across the whole pass
|
|
23
|
+
// while `pose` is written, so they cannot be the same object. Passing one skeleton as both would clobber
|
|
24
|
+
// the rest pose the binder composes against and then accumulate against garbage every subsequent frame —
|
|
25
|
+
// a silent, delayed corruption — so it is a programmer error the guard below throws on, not a sentinel.
|
|
26
|
+
export function applyAnimationClipToSkeleton2D(clip, setup, pose, time) {
|
|
27
|
+
if (setup === pose) {
|
|
28
|
+
throw new Error('applyAnimationClipToSkeleton2D: setup and pose must be distinct skeletons — pass a cloneSkeleton2D(setup) as pose');
|
|
29
|
+
}
|
|
11
30
|
const channels = clip.channels;
|
|
12
|
-
const
|
|
31
|
+
const setupBones = setup.bones;
|
|
32
|
+
const poseBones = pose.bones;
|
|
13
33
|
for (let i = 0; i < channels.length; i++) {
|
|
14
34
|
const channel = channels[i];
|
|
15
35
|
const target = channel.targetRef;
|
|
16
|
-
if (target === null || typeof target !== 'object'
|
|
36
|
+
if (target === null || typeof target !== 'object')
|
|
37
|
+
continue;
|
|
38
|
+
// `targetRef` is opaque, so the shape itself says which array a channel addresses: a bone target names
|
|
39
|
+
// a bone index, a slot target names a slot index. Probing (rather than a discriminator field) is what
|
|
40
|
+
// lets slot channels be purely additive to a bone-only clip format.
|
|
41
|
+
if (typeof target.boneIndex !== 'number') {
|
|
42
|
+
applySkeleton2DSlotChannel(channel, pose, target, time);
|
|
17
43
|
continue;
|
|
44
|
+
}
|
|
18
45
|
const boneIndex = target.boneIndex;
|
|
19
|
-
if (boneIndex < 0 || boneIndex >=
|
|
46
|
+
if (boneIndex < 0 || boneIndex >= poseBones.length || boneIndex >= setupBones.length)
|
|
20
47
|
continue;
|
|
21
48
|
sampleAnimationTrack(_scratch, channel.track, time);
|
|
22
|
-
const
|
|
49
|
+
const setupBone = setupBones[boneIndex];
|
|
50
|
+
const poseBone = poseBones[boneIndex];
|
|
23
51
|
switch (target.path) {
|
|
24
52
|
case Skeleton2DAnimationPath.Translation:
|
|
25
|
-
|
|
26
|
-
|
|
53
|
+
poseBone.x = setupBone.x + _scratch[0];
|
|
54
|
+
poseBone.y = setupBone.y + _scratch[1];
|
|
27
55
|
break;
|
|
28
56
|
case Skeleton2DAnimationPath.Rotation:
|
|
29
|
-
|
|
57
|
+
poseBone.rotation = setupBone.rotation + _scratch[0];
|
|
30
58
|
break;
|
|
31
59
|
case Skeleton2DAnimationPath.Scale:
|
|
32
|
-
|
|
33
|
-
|
|
60
|
+
poseBone.scaleX = setupBone.scaleX * _scratch[0];
|
|
61
|
+
poseBone.scaleY = setupBone.scaleY * _scratch[1];
|
|
34
62
|
break;
|
|
35
63
|
case Skeleton2DAnimationPath.Shear:
|
|
36
|
-
|
|
37
|
-
|
|
64
|
+
poseBone.shearX = setupBone.shearX + _scratch[0];
|
|
65
|
+
poseBone.shearY = setupBone.shearY + _scratch[1];
|
|
38
66
|
break;
|
|
39
67
|
default:
|
|
40
68
|
break;
|
|
41
69
|
}
|
|
42
70
|
}
|
|
43
71
|
}
|
|
72
|
+
// Writes one slot channel's sampled value onto the pose slot. Unlike a bone channel this COMPOSES NOTHING:
|
|
73
|
+
// Spine and DragonBones both author slot colour as an ABSOLUTE value, so the sample replaces the slot's
|
|
74
|
+
// colour rather than tinting the setup colour again. There is therefore no `setup` read on this path.
|
|
75
|
+
//
|
|
76
|
+
// Channels are NORMALIZED 0..1 in R,G,B,A order and scaled to bytes here. The track holds 0..1 rather than
|
|
77
|
+
// 0..255 because that is the space Spine authors colour CURVE control points in — a byte-scaled track would
|
|
78
|
+
// rebase every colour easing against the wrong range. Samples are CLAMPED: a bezier segment may legitimately
|
|
79
|
+
// overshoot its endpoints (anticipation curves do), and an out-of-range channel would otherwise wrap when
|
|
80
|
+
// packed and flip the colour.
|
|
81
|
+
function applySkeleton2DSlotChannel(channel, pose, target, time) {
|
|
82
|
+
const slots = pose.slots;
|
|
83
|
+
if (slots === undefined || slots === null)
|
|
84
|
+
return;
|
|
85
|
+
const slotIndex = target.slotIndex;
|
|
86
|
+
if (typeof slotIndex !== 'number' || slotIndex < 0 || slotIndex >= slots.length)
|
|
87
|
+
return;
|
|
88
|
+
if (target.path === Skeleton2DSlotAnimationPath.Attachment) {
|
|
89
|
+
applySkeleton2DSlotAttachment(channel, slots[slotIndex], target, time);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (target.path !== Skeleton2DSlotAnimationPath.Color)
|
|
93
|
+
return;
|
|
94
|
+
sampleAnimationTrack(_scratch, channel.track, time);
|
|
95
|
+
slots[slotIndex].color =
|
|
96
|
+
((clampColorChannel(_scratch[0]) << 24) |
|
|
97
|
+
(clampColorChannel(_scratch[1]) << 16) |
|
|
98
|
+
(clampColorChannel(_scratch[2]) << 8) |
|
|
99
|
+
clampColorChannel(_scratch[3])) >>>
|
|
100
|
+
0;
|
|
101
|
+
}
|
|
102
|
+
// Swaps the slot's attachment by looking the sampled INDEX up in the target's table.
|
|
103
|
+
//
|
|
104
|
+
// It reads the track with its own STEP walk rather than `sampleAnimationTrack`, and that is deliberate
|
|
105
|
+
// rather than duplication: an attachment index must never be interpolated. If a track were built (or later
|
|
106
|
+
// edited) as Linear, sampling would blend between two TABLE INDICES and hand back something between them —
|
|
107
|
+
// a plausible-looking index that names the wrong art, or a fractional one. Forcing the step here means the
|
|
108
|
+
// channel is correct regardless of what the track claims its interpolation is.
|
|
109
|
+
//
|
|
110
|
+
// An index outside the table, or the `-1` Spine writes for "no attachment", clears the slot.
|
|
111
|
+
function applySkeleton2DSlotAttachment(channel, slot, target, time) {
|
|
112
|
+
const table = target.attachments;
|
|
113
|
+
if (table === undefined || table === null)
|
|
114
|
+
return;
|
|
115
|
+
const times = channel.track.times;
|
|
116
|
+
const count = times.length;
|
|
117
|
+
if (count === 0)
|
|
118
|
+
return;
|
|
119
|
+
// The last keyframe at or before `time`; before the first keyframe the first value holds.
|
|
120
|
+
let keyframe = 0;
|
|
121
|
+
for (let i = count - 1; i >= 0; i--) {
|
|
122
|
+
if (times[i] <= time) {
|
|
123
|
+
keyframe = i;
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const index = Math.round(channel.track.values[keyframe * channel.track.components]);
|
|
128
|
+
slot.attachment = index >= 0 && index < table.length ? table[index] : null;
|
|
129
|
+
}
|
|
130
|
+
function clampColorChannel(value) {
|
|
131
|
+
return value <= 0 ? 0 : value >= 1 ? 255 : Math.round(value * 255);
|
|
132
|
+
}
|
|
44
133
|
const _scratch = [0, 0, 0, 0];
|
|
45
134
|
//# sourceMappingURL=applyAnimationClipToSkeleton2D.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"applyAnimationClipToSkeleton2D.js","sourceRoot":"","sources":["../src/applyAnimationClipToSkeleton2D.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"applyAnimationClipToSkeleton2D.js","sourceRoot":"","sources":["../src/applyAnimationClipToSkeleton2D.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kCAAkC,CAAC"}
|
package/dist/contract.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kCAAkC,CAAC"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { MeshAttachment2D, Skeleton2D } from '@flighthq/types';
|
|
1
|
+
import type { MeshAttachment2D, Skeleton2D } from '@flighthq/types/contract';
|
|
2
2
|
export declare function deformSkeleton2DMeshAttachment(out: Float32Array, attachment: Readonly<MeshAttachment2D>, skeleton: Readonly<Skeleton2D>, boneIndex: number): void;
|
|
3
3
|
//# sourceMappingURL=deformMeshAttachment2D.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deformMeshAttachment2D.d.ts","sourceRoot":"","sources":["../src/deformMeshAttachment2D.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"deformMeshAttachment2D.d.ts","sourceRoot":"","sources":["../src/deformMeshAttachment2D.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAgB7E,wBAAgB,8BAA8B,CAC5C,GAAG,EAAE,YAAY,EACjB,UAAU,EAAE,QAAQ,CAAC,gBAAgB,CAAC,EACtC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC9B,SAAS,EAAE,MAAM,GAChB,IAAI,CA4CN"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
export
|
|
2
|
-
export * from './deformMeshAttachment2D';
|
|
3
|
-
export * from './regionAttachment2D';
|
|
4
|
-
export * from './applyAnimationClipToSkeleton2D';
|
|
1
|
+
export { applyAnimationClipToSkeleton2D, cloneSkeleton2D, computeSkeleton2DBoneMatrices, computeSkeleton2DRegionAttachmentVertices, computeSkeleton2DWorldTransforms, createSkeleton2D, deformSkeleton2DMeshAttachment, disposeSkeleton2D, equalsSkeleton2D, getSkeleton2DBoneIndexByName, getSkeleton2DBoneWorldMatrix, setSkeleton2DBindPose, validateSkeleton2D, } from './contract';
|
|
5
2
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,8BAA8B,EAC9B,eAAe,EACf,6BAA6B,EAC7B,yCAAyC,EACzC,gCAAgC,EAChC,gBAAgB,EAChB,8BAA8B,EAC9B,iBAAiB,EACjB,gBAAgB,EAChB,4BAA4B,EAC5B,4BAA4B,EAC5B,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
export
|
|
2
|
-
export * from './deformMeshAttachment2D';
|
|
3
|
-
export * from './regionAttachment2D';
|
|
4
|
-
export * from './applyAnimationClipToSkeleton2D';
|
|
1
|
+
export { applyAnimationClipToSkeleton2D, cloneSkeleton2D, computeSkeleton2DBoneMatrices, computeSkeleton2DRegionAttachmentVertices, computeSkeleton2DWorldTransforms, createSkeleton2D, deformSkeleton2DMeshAttachment, disposeSkeleton2D, equalsSkeleton2D, getSkeleton2DBoneIndexByName, getSkeleton2DBoneWorldMatrix, setSkeleton2DBindPose, validateSkeleton2D, } from './contract';
|
|
5
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,8BAA8B,EAC9B,eAAe,EACf,6BAA6B,EAC7B,yCAAyC,EACzC,gCAAgC,EAChC,gBAAgB,EAChB,8BAA8B,EAC9B,iBAAiB,EACjB,gBAAgB,EAChB,4BAA4B,EAC5B,4BAA4B,EAC5B,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { RegionAttachment2D, Skeleton2D } from '@flighthq/types';
|
|
1
|
+
import type { RegionAttachment2D, Skeleton2D } from '@flighthq/types/contract';
|
|
2
2
|
export declare function computeSkeleton2DRegionAttachmentVertices(out: Float32Array, attachment: Readonly<RegionAttachment2D>, skeleton: Readonly<Skeleton2D>, boneIndex: number): void;
|
|
3
3
|
//# sourceMappingURL=regionAttachment2D.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"regionAttachment2D.d.ts","sourceRoot":"","sources":["../src/regionAttachment2D.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAc,kBAAkB,EAAE,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"regionAttachment2D.d.ts","sourceRoot":"","sources":["../src/regionAttachment2D.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAc,kBAAkB,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAU3F,wBAAgB,yCAAyC,CACvD,GAAG,EAAE,YAAY,EACjB,UAAU,EAAE,QAAQ,CAAC,kBAAkB,CAAC,EACxC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC9B,SAAS,EAAE,MAAM,GAChB,IAAI,CAkCN"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { matrixTransformPointXY, multiplyMatrix, setTransformMatrix } from '@flighthq/geometry';
|
|
2
|
-
import { DEG_TO_RAD } from '@flighthq/math';
|
|
1
|
+
import { matrixTransformPointXY, multiplyMatrix, setTransformMatrix } from '@flighthq/geometry/contract';
|
|
2
|
+
import { DEG_TO_RAD } from '@flighthq/math/contract';
|
|
3
3
|
// 6 floats per bone in the flat world-transform buffer (a, b, c, d, tx, ty).
|
|
4
4
|
const MATRIX_STRIDE = 6;
|
|
5
5
|
// Writes a RegionAttachment2D's four world corner positions into `out` as flat interleaved pairs — order
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"regionAttachment2D.js","sourceRoot":"","sources":["../src/regionAttachment2D.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"regionAttachment2D.js","sourceRoot":"","sources":["../src/regionAttachment2D.ts"],"names":[],"mappings":"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"}
|
package/dist/skeleton2d.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Bone2D, MatrixLike, Skeleton2D } from '@flighthq/types';
|
|
1
|
+
import type { AttachmentSkin2D, Bone2D, MatrixLike, Skeleton2D } from '@flighthq/types/contract';
|
|
2
2
|
export declare function cloneSkeleton2D(skeleton: Readonly<Skeleton2D>): Skeleton2D;
|
|
3
3
|
export declare function computeSkeleton2DBoneMatrices(skeleton: Readonly<Skeleton2D>): void;
|
|
4
4
|
export declare function computeSkeleton2DWorldTransforms(skeleton: Readonly<Skeleton2D>): void;
|
|
@@ -7,6 +7,8 @@ export declare function disposeSkeleton2D(skeleton: Skeleton2D): void;
|
|
|
7
7
|
export declare function equalsSkeleton2D(a: Readonly<Skeleton2D>, b: Readonly<Skeleton2D>): boolean;
|
|
8
8
|
export declare function getSkeleton2DBoneIndexByName(skeleton: Readonly<Skeleton2D>, name: string): number;
|
|
9
9
|
export declare function getSkeleton2DBoneWorldMatrix(out: MatrixLike, skeleton: Readonly<Skeleton2D>, boneIndex: number): boolean;
|
|
10
|
+
export declare function getSkeleton2DSkin(skeleton: Readonly<Skeleton2D>, name: string): AttachmentSkin2D | null;
|
|
10
11
|
export declare function setSkeleton2DBindPose(skeleton: Readonly<Skeleton2D>): void;
|
|
12
|
+
export declare function setSkeleton2DSkin(skeleton: Skeleton2D, skin: Readonly<AttachmentSkin2D>): void;
|
|
11
13
|
export declare function validateSkeleton2D(skeleton: Readonly<Skeleton2D>): string | null;
|
|
12
14
|
//# sourceMappingURL=skeleton2d.d.ts.map
|
package/dist/skeleton2d.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skeleton2d.d.ts","sourceRoot":"","sources":["../src/skeleton2d.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"skeleton2d.d.ts","sourceRoot":"","sources":["../src/skeleton2d.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAQjG,wBAAgB,eAAe,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,UAAU,CAS1E;AAMD,wBAAgB,6BAA6B,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAYlF;AAOD,wBAAgB,gCAAgC,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAmFrF;AAOD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,KAAK,GAAE,UAAU,CAAC,OAAO,CAAQ,GAAG,UAAU,CAS/F;AAID,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,UAAU,GAAG,IAAI,CAG5D;AAED,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,OAAO,CAyB1F;AAGD,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAMjG;AAID,wBAAgB,4BAA4B,CAC1C,GAAG,EAAE,UAAU,EACf,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,EAC9B,SAAS,EAAE,MAAM,GAChB,OAAO,CAIT;AAID,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAOvG;AAGD,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,IAAI,CAU1E;AAeD,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,QAAQ,CAAC,gBAAgB,CAAC,GAAG,IAAI,CAM9F;AAID,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,IAAI,CAiBhF"}
|
package/dist/skeleton2d.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { createEntity } from '@flighthq/entity';
|
|
2
|
-
import { inverseMatrix, multiplyMatrix } from '@flighthq/geometry';
|
|
3
|
-
import { DEG_TO_RAD } from '@flighthq/math';
|
|
4
|
-
import { TransformMode2D } from '@flighthq/types';
|
|
1
|
+
import { createEntity } from '@flighthq/entity/contract';
|
|
2
|
+
import { inverseMatrix, multiplyMatrix } from '@flighthq/geometry/contract';
|
|
3
|
+
import { DEG_TO_RAD } from '@flighthq/math/contract';
|
|
5
4
|
// 6 floats per bone in the flat 2×3 affine buffers (a, b, c, d, tx, ty), matching the Matrix field order.
|
|
6
5
|
const MATRIX_STRIDE = 6;
|
|
7
6
|
// Deep-copies the bone array (each Bone2D cloned) and the transform buffers, producing an independently
|
|
@@ -67,62 +66,63 @@ export function computeSkeleton2DWorldTransforms(skeleton) {
|
|
|
67
66
|
const pb = world[p + 1];
|
|
68
67
|
const pc = world[p + 2];
|
|
69
68
|
const pd = world[p + 3];
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
69
|
+
const inherit = bone.transformMode;
|
|
70
|
+
// Position: the parent places the bone's local origin — unless translation inheritance is stripped, in
|
|
71
|
+
// which case the bone's local (x, y) is its world position directly.
|
|
72
|
+
if (inherit.translation) {
|
|
73
|
+
world[o + 4] = pa * bone.x + pc * bone.y + world[p + 4];
|
|
74
|
+
world[o + 5] = pb * bone.x + pd * bone.y + world[p + 5];
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
world[o + 4] = bone.x;
|
|
78
|
+
world[o + 5] = bone.y;
|
|
79
|
+
}
|
|
80
|
+
// Linear part: rotation, scale, and reflection are each inherited or stripped independently. When all
|
|
81
|
+
// three are inherited (Normal — the common case) it is the fast path: the raw parent columns × local,
|
|
82
|
+
// no decomposition. Otherwise the parent is decomposed into per-column scale (lengths) and a direction
|
|
83
|
+
// basis, each axis kept or replaced per its flag, recomposed, then × local. Reproduces the five presets
|
|
84
|
+
// exactly (NoScale keeps the parent's actual y-column, preserving shear; NoScaleOrReflection forces the
|
|
85
|
+
// y-axis to the +90° perpendicular of the x-axis, det +1, dropping shear and reflection).
|
|
86
|
+
let ea;
|
|
87
|
+
let eb;
|
|
88
|
+
let ec;
|
|
89
|
+
let ed;
|
|
90
|
+
if (inherit.rotation && inherit.scale && inherit.reflection) {
|
|
91
|
+
ea = pa;
|
|
92
|
+
eb = pb;
|
|
93
|
+
ec = pc;
|
|
94
|
+
ed = pd;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
const psx = Math.hypot(pa, pb) || 1;
|
|
98
|
+
const psy = Math.hypot(pc, pd) || 1;
|
|
99
|
+
const d0x = inherit.rotation ? pa / psx : 1;
|
|
100
|
+
const d0y = inherit.rotation ? pb / psx : 0;
|
|
101
|
+
let d1x;
|
|
102
|
+
let d1y;
|
|
103
|
+
if (inherit.rotation && inherit.reflection) {
|
|
104
|
+
d1x = pc / psy;
|
|
105
|
+
d1y = pd / psy;
|
|
91
106
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
// length, then compose with the local transform. NoScale keeps the parent's reflection (its
|
|
96
|
-
// normalized columns as-is); NoScaleOrReflection strips it, forcing the y-axis to the +90°
|
|
97
|
-
// rotation of the x-axis (det = +1) so the child never flips under a negatively-scaled parent.
|
|
98
|
-
const psx = Math.hypot(pa, pb) || 1;
|
|
99
|
-
const nax = pa / psx;
|
|
100
|
-
const nay = pb / psx;
|
|
101
|
-
let ncx;
|
|
102
|
-
let ncy;
|
|
103
|
-
if (bone.transformMode === TransformMode2D.NoScaleOrReflection) {
|
|
104
|
-
ncx = -nay;
|
|
105
|
-
ncy = nax;
|
|
106
|
-
}
|
|
107
|
-
else {
|
|
108
|
-
const psy = Math.hypot(pc, pd) || 1;
|
|
109
|
-
ncx = pc / psy;
|
|
110
|
-
ncy = pd / psy;
|
|
111
|
-
}
|
|
112
|
-
world[o] = nax * la + ncx * lb;
|
|
113
|
-
world[o + 1] = nay * la + ncy * lb;
|
|
114
|
-
world[o + 2] = nax * lc + ncx * ld;
|
|
115
|
-
world[o + 3] = nay * lc + ncy * ld;
|
|
116
|
-
break;
|
|
107
|
+
else if (inherit.rotation) {
|
|
108
|
+
d1x = -d0y;
|
|
109
|
+
d1y = d0x;
|
|
117
110
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
111
|
+
else {
|
|
112
|
+
d1x = 0;
|
|
113
|
+
d1y = inherit.reflection && pa * pd - pb * pc < 0 ? -1 : 1;
|
|
114
|
+
}
|
|
115
|
+
const sx = inherit.scale ? psx : 1;
|
|
116
|
+
const sy = inherit.scale ? psy : 1;
|
|
117
|
+
ea = d0x * sx;
|
|
118
|
+
eb = d0y * sx;
|
|
119
|
+
ec = d1x * sy;
|
|
120
|
+
ed = d1y * sy;
|
|
125
121
|
}
|
|
122
|
+
world[o] = ea * la + ec * lb;
|
|
123
|
+
world[o + 1] = eb * la + ed * lb;
|
|
124
|
+
world[o + 2] = ea * lc + ec * ld;
|
|
125
|
+
world[o + 3] = eb * lc + ed * ld;
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
// Allocates a Skeleton2D from a parent-before-child ordered bone array. Sizes the flat world/inverse-bind/
|
|
@@ -163,7 +163,10 @@ export function equalsSkeleton2D(a, b) {
|
|
|
163
163
|
x.shearX !== y.shearX ||
|
|
164
164
|
x.shearY !== y.shearY ||
|
|
165
165
|
x.length !== y.length ||
|
|
166
|
-
x.transformMode !== y.transformMode
|
|
166
|
+
x.transformMode.rotation !== y.transformMode.rotation ||
|
|
167
|
+
x.transformMode.scale !== y.transformMode.scale ||
|
|
168
|
+
x.transformMode.reflection !== y.transformMode.reflection ||
|
|
169
|
+
x.transformMode.translation !== y.transformMode.translation) {
|
|
167
170
|
return false;
|
|
168
171
|
}
|
|
169
172
|
}
|
|
@@ -186,9 +189,18 @@ export function getSkeleton2DBoneWorldMatrix(out, skeleton, boneIndex) {
|
|
|
186
189
|
readMatrix(out, skeleton.worldMatrices, boneIndex * MATRIX_STRIDE);
|
|
187
190
|
return true;
|
|
188
191
|
}
|
|
189
|
-
//
|
|
190
|
-
//
|
|
191
|
-
|
|
192
|
+
// The skeleton's named skin, or the `null` sentinel when it carries none by that name. Names are the rig's
|
|
193
|
+
// own (`"goblin"`, `"goblingirl"`); a rig with no wardrobe has no skins at all.
|
|
194
|
+
export function getSkeleton2DSkin(skeleton, name) {
|
|
195
|
+
const skins = skeleton.skins;
|
|
196
|
+
if (skins === undefined || skins === null)
|
|
197
|
+
return null;
|
|
198
|
+
for (const skin of skins) {
|
|
199
|
+
if (skin.name === name)
|
|
200
|
+
return skin;
|
|
201
|
+
}
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
192
204
|
// inverse-bind at identity (`inverseMatrix` returns false) rather than producing NaNs.
|
|
193
205
|
export function setSkeleton2DBindPose(skeleton) {
|
|
194
206
|
const world = skeleton.worldMatrices;
|
|
@@ -202,6 +214,28 @@ export function setSkeleton2DBindPose(skeleton) {
|
|
|
202
214
|
writeMatrix(out, o, _scratchB);
|
|
203
215
|
}
|
|
204
216
|
}
|
|
217
|
+
// Captures the current world transforms as the bind (setup) pose: `inverseBindMatrices[i] =
|
|
218
|
+
// inverse(worldMatrices[i])`. Call after posing the bones to setup and running
|
|
219
|
+
// `computeSkeleton2DWorldTransforms`. A non-invertible (degenerate, zero-scale) bone leaves its
|
|
220
|
+
// Dresses `skeleton` in `skin`: writes each of the skin's attachments onto the slot it names, leaving every
|
|
221
|
+
// other slot untouched. This is the whole runtime cost of the wardrobe — skins are inert until applied, and
|
|
222
|
+
// applying one is a slot-array write, no re-binding and no world propagation (a skin changes what is DRAWN,
|
|
223
|
+
// never where bones are).
|
|
224
|
+
//
|
|
225
|
+
// Slots the skin does not mention keep whatever they were showing. That is deliberate and matches how rigs
|
|
226
|
+
// are authored: a "default" skin carries the shared pieces while `goblin`/`goblingirl` override only the
|
|
227
|
+
// parts that differ, so applying one over the other must not blank the shared art. A caller wanting a clean
|
|
228
|
+
// swap applies the base skin first. An entry naming a slot outside the skeleton is skipped rather than
|
|
229
|
+
// throwing — third-party rigs are untrusted input, and a stale index is a dropped attachment, not a crash.
|
|
230
|
+
export function setSkeleton2DSkin(skeleton, skin) {
|
|
231
|
+
const slots = skeleton.slots;
|
|
232
|
+
if (slots === undefined || slots === null)
|
|
233
|
+
return;
|
|
234
|
+
for (const entry of skin.attachments) {
|
|
235
|
+
if (entry.slotIndex >= 0 && entry.slotIndex < slots.length)
|
|
236
|
+
slots[entry.slotIndex].attachment = entry.attachment;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
205
239
|
// Checks the parent-before-child ordering invariant (each bone's parentIndex is -1 or < its own index) and
|
|
206
240
|
// buffer sizing. Returns null when valid, or a message describing the first violation (sentinel over throw).
|
|
207
241
|
export function validateSkeleton2D(skeleton) {
|
package/dist/skeleton2d.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skeleton2d.js","sourceRoot":"","sources":["../src/skeleton2d.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,0GAA0G;AAC1G,MAAM,aAAa,GAAG,CAAC,CAAC;AAExB,wGAAwG;AACxG,yGAAyG;AACzG,6DAA6D;AAC7D,MAAM,UAAU,eAAe,CAAC,QAA8B;IAC5D,OAAO,YAAY,CAAC;QAClB,YAAY,EAAE,QAAQ,CAAC,YAAY,CAAC,KAAK,EAAE;QAC3C,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAC;QAClD,mBAAmB,EAAE,QAAQ,CAAC,mBAAmB,CAAC,KAAK,EAAE;QACzD,KAAK,EACH,QAAQ,CAAC,KAAK,KAAK,IAAI,IAAI,QAAQ,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QAClH,aAAa,EAAE,QAAQ,CAAC,aAAa,CAAC,KAAK,EAAE;KAC9C,CAAC,CAAC;AACL,CAAC;AAED,yGAAyG;AACzG,6GAA6G;AAC7G,yGAAyG;AACzG,oCAAoC;AACpC,MAAM,UAAU,6BAA6B,CAAC,QAA8B;IAC1E,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC;IACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,mBAAmB,CAAC;IAC7C,MAAM,GAAG,GAAG,QAAQ,CAAC,YAAY,CAAC;IAClC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;IACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC;QAC5B,UAAU,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAChC,UAAU,CAAC,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;QAClC,cAAc,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAChD,WAAW,CAAC,GAAG,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,2GAA2G;AAC3G,2GAA2G;AAC3G,yGAAyG;AACzG,0GAA0G;AAC1G,yGAAyG;AACzG,MAAM,UAAU,gCAAgC,CAAC,QAA8B;IAC7E,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;IAC7B,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC;IACrC,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC;IAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,6FAA6F;QAC7F,qGAAqG;QACrG,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC;QACxD,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,UAAU,CAAC;QAC7D,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;QACxC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;QACxC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;QACxC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC;QACxC,MAAM,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC;QAC5B,IAAI,IAAI,CAAC,WAAW,GAAG,CAAC,EAAE,CAAC;YACzB,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;YACd,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YAClB,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YAClB,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;YAClB,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;YACtB,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;YACtB,SAAS;QACX,CAAC;QACD,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,GAAG,aAAa,CAAC;QAC3C,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACpB,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACxB,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACxB,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACxB,uEAAuE;QACvE,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACxD,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACxD,QAAQ,IAAI,CAAC,aAAa,EAAE,CAAC;YAC3B,KAAK,eAAe,CAAC,eAAe;gBAClC,+FAA+F;gBAC/F,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;gBACd,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;gBAClB,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;gBAClB,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC;gBAClB,MAAM;YACR,KAAK,eAAe,CAAC,sBAAsB,CAAC,CAAC,CAAC;gBAC5C,+FAA+F;gBAC/F,mEAAmE;gBACnE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;gBAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;gBAC/B,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC;gBACpB,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC;gBACxB,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC;gBACxB,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,CAAC;gBACxB,MAAM;YACR,CAAC;YACD,KAAK,eAAe,CAAC,OAAO,CAAC;YAC7B,KAAK,eAAe,CAAC,mBAAmB,CAAC,CAAC,CAAC;gBACzC,6FAA6F;gBAC7F,4FAA4F;gBAC5F,2FAA2F;gBAC3F,+FAA+F;gBAC/F,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;gBACpC,MAAM,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC;gBACrB,MAAM,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC;gBACrB,IAAI,GAAW,CAAC;gBAChB,IAAI,GAAW,CAAC;gBAChB,IAAI,IAAI,CAAC,aAAa,KAAK,eAAe,CAAC,mBAAmB,EAAE,CAAC;oBAC/D,GAAG,GAAG,CAAC,GAAG,CAAC;oBACX,GAAG,GAAG,GAAG,CAAC;gBACZ,CAAC;qBAAM,CAAC;oBACN,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;oBACpC,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC;oBACf,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC;gBACjB,CAAC;gBACD,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC;gBAC/B,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC;gBACnC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC;gBACnC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,GAAG,EAAE,CAAC;gBACnC,MAAM;YACR,CAAC;YACD;gBACE,6DAA6D;gBAC7D,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;gBAC7B,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;gBACjC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;gBACjC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;gBACjC,MAAM;QACV,CAAC;IACH,CAAC;AACH,CAAC;AAED,2GAA2G;AAC3G,+FAA+F;AAC/F,6GAA6G;AAC7G,uGAAuG;AACvG,iFAAiF;AACjF,MAAM,UAAU,gBAAgB,CAAC,KAAe,EAAE,QAA6B,IAAI;IACjF,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC;IAC3B,OAAO,YAAY,CAAC;QAClB,YAAY,EAAE,IAAI,YAAY,CAAC,KAAK,GAAG,aAAa,CAAC;QACrD,KAAK;QACL,mBAAmB,EAAE,IAAI,YAAY,CAAC,KAAK,GAAG,aAAa,CAAC;QAC5D,KAAK;QACL,aAAa,EAAE,IAAI,YAAY,CAAC,KAAK,GAAG,aAAa,CAAC;KACvD,CAAC,CAAC;AACL,CAAC;AAED,yGAAyG;AACzG,6FAA6F;AAC7F,MAAM,UAAU,iBAAiB,CAAC,QAAoB;IACpD,QAAQ,CAAC,KAAK,GAAG,EAAE,CAAC;IACpB,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,CAAuB,EAAE,CAAuB;IAC/E,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,KAAK,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACrB,IACE,CAAC,CAAC,WAAW,KAAK,CAAC,CAAC,WAAW;YAC/B,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YACX,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;YACX,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ;YACzB,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;YACrB,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;YACrB,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;YACrB,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;YACrB,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;YACrB,CAAC,CAAC,aAAa,KAAK,CAAC,CAAC,aAAa,EACnC,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,4BAA4B,CAAC,QAA8B,EAAE,IAAY;IACvF,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;IAC7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI;YAAE,OAAO,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,CAAC,CAAC,CAAC;AACZ,CAAC;AAED,4GAA4G;AAC5G,8GAA8G;AAC9G,MAAM,UAAU,4BAA4B,CAC1C,GAAe,EACf,QAA8B,EAC9B,SAAiB;IAEjB,IAAI,SAAS,GAAG,CAAC,IAAI,SAAS,IAAI,QAAQ,CAAC,KAAK,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACtE,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC,aAAa,EAAE,SAAS,GAAG,aAAa,CAAC,CAAC;IACnE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,4FAA4F;AAC5F,+EAA+E;AAC/E,gGAAgG;AAChG,uFAAuF;AACvF,MAAM,UAAU,qBAAqB,CAAC,QAA8B;IAClE,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC;IACrC,MAAM,GAAG,GAAG,QAAQ,CAAC,mBAAmB,CAAC;IACzC,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;IACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAG,CAAC,GAAG,aAAa,CAAC;QAC5B,UAAU,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,SAAS,CAAC;YAAE,sBAAsB,CAAC,SAAS,CAAC,CAAC;QAC5E,WAAW,CAAC,GAAG,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,2GAA2G;AAC3G,6GAA6G;AAC7G,MAAM,UAAU,kBAAkB,CAAC,QAA8B;IAC/D,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC;IACpC,MAAM,QAAQ,GAAG,KAAK,GAAG,aAAa,CAAC;IACvC,IAAI,QAAQ,CAAC,aAAa,CAAC,MAAM,KAAK,QAAQ;QAC5C,OAAO,wBAAwB,QAAQ,CAAC,aAAa,CAAC,MAAM,OAAO,QAAQ,EAAE,CAAC;IAChF,IAAI,QAAQ,CAAC,mBAAmB,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;QACrD,OAAO,8BAA8B,QAAQ,CAAC,mBAAmB,CAAC,MAAM,OAAO,QAAQ,EAAE,CAAC;IAC5F,CAAC;IACD,IAAI,QAAQ,CAAC,YAAY,CAAC,MAAM,KAAK,QAAQ;QAC3C,OAAO,uBAAuB,QAAQ,CAAC,YAAY,CAAC,MAAM,OAAO,QAAQ,EAAE,CAAC;IAC9E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,MAAM,WAAW,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC;QAClD,IAAI,WAAW,IAAI,CAAC;YAClB,OAAO,QAAQ,CAAC,gBAAgB,WAAW,qEAAqE,CAAC;QACnH,IAAI,WAAW,GAAG,CAAC,CAAC;YAAE,OAAO,QAAQ,CAAC,gBAAgB,WAAW,OAAO,CAAC;IAC3E,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,UAAU,CAAC,GAAe,EAAE,MAA8B,EAAE,MAAc;IACjF,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACvB,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3B,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3B,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3B,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC5B,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,sBAAsB,CAAC,GAAe;IAC7C,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IACV,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IACV,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IACV,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;IACV,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;IACX,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;AACb,CAAC;AAED,SAAS,WAAW,CAAC,MAAoB,EAAE,MAAc,EAAE,MAA4B;IACrF,MAAM,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IAC1B,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IAC9B,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IAC9B,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC;IAC9B,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC;IAC/B,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,SAAS,GAAe,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;AACvE,MAAM,SAAS,GAAe,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;AACvE,MAAM,SAAS,GAAe,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"skeleton2d.js","sourceRoot":"","sources":["../src/skeleton2d.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flighthq/skeleton2d",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0-edge.1516.1b4fb2b",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/flighthq/flight.git",
|
|
@@ -13,6 +13,10 @@
|
|
|
13
13
|
".": {
|
|
14
14
|
"types": "./dist/index.d.ts",
|
|
15
15
|
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./contract": {
|
|
18
|
+
"types": "./dist/contract.d.ts",
|
|
19
|
+
"default": "./dist/contract.js"
|
|
16
20
|
}
|
|
17
21
|
},
|
|
18
22
|
"files": [
|
|
@@ -32,11 +36,11 @@
|
|
|
32
36
|
"clean:dist": "tsx ../../scripts/clean-package-dist.ts"
|
|
33
37
|
},
|
|
34
38
|
"dependencies": {
|
|
35
|
-
"@flighthq/animation": "0.
|
|
36
|
-
"@flighthq/entity": "0.
|
|
37
|
-
"@flighthq/geometry": "0.
|
|
38
|
-
"@flighthq/math": "0.
|
|
39
|
-
"@flighthq/types": "0.
|
|
39
|
+
"@flighthq/animation": "0.3.0-edge.1516.1b4fb2b",
|
|
40
|
+
"@flighthq/entity": "0.3.0-edge.1516.1b4fb2b",
|
|
41
|
+
"@flighthq/geometry": "0.3.0-edge.1516.1b4fb2b",
|
|
42
|
+
"@flighthq/math": "0.3.0-edge.1516.1b4fb2b",
|
|
43
|
+
"@flighthq/types": "0.3.0-edge.1516.1b4fb2b"
|
|
40
44
|
},
|
|
41
45
|
"devDependencies": {
|
|
42
46
|
"typescript": "^5.3.0"
|
|
@@ -1,10 +1,15 @@
|
|
|
1
|
-
import { createAnimationChannel, createAnimationClip, createAnimationTrack } from '@flighthq/animation';
|
|
2
|
-
import type { Bone2D } from '@flighthq/types';
|
|
3
|
-
import {
|
|
1
|
+
import { createAnimationChannel, createAnimationClip, createAnimationTrack } from '@flighthq/animation/contract';
|
|
2
|
+
import type { Bone2D } from '@flighthq/types/contract';
|
|
3
|
+
import {
|
|
4
|
+
AnimationInterpolationLinear,
|
|
5
|
+
Skeleton2DAnimationPath,
|
|
6
|
+
Skeleton2DSlotAnimationPath,
|
|
7
|
+
TransformMode2D,
|
|
8
|
+
} from '@flighthq/types/contract';
|
|
4
9
|
import { describe, expect, it } from 'vitest';
|
|
5
10
|
|
|
6
11
|
import { applyAnimationClipToSkeleton2D } from './applyAnimationClipToSkeleton2D';
|
|
7
|
-
import { createSkeleton2D } from './skeleton2d';
|
|
12
|
+
import { cloneSkeleton2D, createSkeleton2D } from './skeleton2d';
|
|
8
13
|
|
|
9
14
|
function makeBone(overrides: Partial<Bone2D> = {}): Bone2D {
|
|
10
15
|
return {
|
|
@@ -28,23 +33,26 @@ function scalarTrack(times: number[], values: number[], components: number) {
|
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
describe('applyAnimationClipToSkeleton2D', () => {
|
|
31
|
-
it('
|
|
32
|
-
const
|
|
36
|
+
it('composes a rotation delta onto the setup pose (setup + delta), leaving setup untouched', () => {
|
|
37
|
+
const setup = createSkeleton2D([makeBone({ rotation: 10 })]);
|
|
38
|
+
const pose = cloneSkeleton2D(setup);
|
|
33
39
|
const clip = createAnimationClip([
|
|
34
40
|
createAnimationChannel(scalarTrack([0, 1], [0, 90], 1), { boneIndex: 0, path: Skeleton2DAnimationPath.Rotation }),
|
|
35
41
|
]);
|
|
36
|
-
applyAnimationClipToSkeleton2D(clip,
|
|
37
|
-
expect(
|
|
42
|
+
applyAnimationClipToSkeleton2D(clip, setup, pose, 0.5);
|
|
43
|
+
expect(pose.bones[0].rotation).toBeCloseTo(55, 5); // setup 10 + delta 45 (linear 0→90 at t=0.5)
|
|
44
|
+
expect(setup.bones[0].rotation).toBe(10); // the rest pose is read-only, unchanged
|
|
38
45
|
});
|
|
39
46
|
|
|
40
|
-
it('
|
|
41
|
-
const
|
|
47
|
+
it('adds translation/shear deltas and multiplies scale deltas onto setup', () => {
|
|
48
|
+
const setup = createSkeleton2D([makeBone({ x: 5, y: -2, scaleX: 2, scaleY: 3, shearX: 1, shearY: 4 })]);
|
|
49
|
+
const pose = cloneSkeleton2D(setup);
|
|
42
50
|
const clip = createAnimationClip([
|
|
43
51
|
createAnimationChannel(scalarTrack([0, 1], [0, 0, 10, 20], 2), {
|
|
44
52
|
boneIndex: 0,
|
|
45
53
|
path: Skeleton2DAnimationPath.Translation,
|
|
46
54
|
}),
|
|
47
|
-
createAnimationChannel(scalarTrack([0, 1], [1, 1, 3,
|
|
55
|
+
createAnimationChannel(scalarTrack([0, 1], [1, 1, 3, 0.5], 2), {
|
|
48
56
|
boneIndex: 0,
|
|
49
57
|
path: Skeleton2DAnimationPath.Scale,
|
|
50
58
|
}),
|
|
@@ -53,22 +61,126 @@ describe('applyAnimationClipToSkeleton2D', () => {
|
|
|
53
61
|
path: Skeleton2DAnimationPath.Shear,
|
|
54
62
|
}),
|
|
55
63
|
]);
|
|
56
|
-
applyAnimationClipToSkeleton2D(clip,
|
|
57
|
-
expect(
|
|
58
|
-
expect(
|
|
59
|
-
expect(
|
|
60
|
-
expect(
|
|
61
|
-
expect(
|
|
62
|
-
expect(
|
|
64
|
+
applyAnimationClipToSkeleton2D(clip, setup, pose, 1);
|
|
65
|
+
expect(pose.bones[0].x).toBeCloseTo(15, 5); // 5 + 10
|
|
66
|
+
expect(pose.bones[0].y).toBeCloseTo(18, 5); // -2 + 20
|
|
67
|
+
expect(pose.bones[0].scaleX).toBeCloseTo(6, 5); // 2 * 3 (multiplier)
|
|
68
|
+
expect(pose.bones[0].scaleY).toBeCloseTo(1.5, 5); // 3 * 0.5 (multiplier)
|
|
69
|
+
expect(pose.bones[0].shearX).toBeCloseTo(6, 5); // 1 + 5
|
|
70
|
+
expect(pose.bones[0].shearY).toBeCloseTo(10, 5); // 4 + 6
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('re-applies from setup each frame — no accumulation across repeated calls', () => {
|
|
74
|
+
const setup = createSkeleton2D([makeBone({ rotation: 10 })]);
|
|
75
|
+
const pose = cloneSkeleton2D(setup);
|
|
76
|
+
const clip = createAnimationClip([
|
|
77
|
+
createAnimationChannel(scalarTrack([0, 1], [0, 90], 1), { boneIndex: 0, path: Skeleton2DAnimationPath.Rotation }),
|
|
78
|
+
]);
|
|
79
|
+
applyAnimationClipToSkeleton2D(clip, setup, pose, 1); // 10 + 90 = 100
|
|
80
|
+
applyAnimationClipToSkeleton2D(clip, setup, pose, 1); // composes from setup again → still 100, not 190
|
|
81
|
+
expect(pose.bones[0].rotation).toBeCloseTo(100, 5);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('throws when setup and pose are the same skeleton (aliasing would corrupt the rest pose)', () => {
|
|
85
|
+
const s = createSkeleton2D([makeBone({ rotation: 10 })]);
|
|
86
|
+
const clip = createAnimationClip([
|
|
87
|
+
createAnimationChannel(scalarTrack([0, 1], [0, 90], 1), { boneIndex: 0, path: Skeleton2DAnimationPath.Rotation }),
|
|
88
|
+
]);
|
|
89
|
+
expect(() => applyAnimationClipToSkeleton2D(clip, s, s, 1)).toThrow(/distinct skeletons/);
|
|
63
90
|
});
|
|
64
91
|
|
|
65
92
|
it('skips a channel with a foreign target or an out-of-range bone (no throw, no mutation)', () => {
|
|
66
|
-
const
|
|
93
|
+
const setup = createSkeleton2D([makeBone({ rotation: 7 })]);
|
|
94
|
+
const pose = cloneSkeleton2D(setup);
|
|
67
95
|
const clip = createAnimationClip([
|
|
68
96
|
createAnimationChannel(scalarTrack([0, 1], [0, 90], 1), { someOtherTarget: true }),
|
|
69
97
|
createAnimationChannel(scalarTrack([0, 1], [0, 90], 1), { boneIndex: 9, path: Skeleton2DAnimationPath.Rotation }),
|
|
70
98
|
]);
|
|
71
|
-
applyAnimationClipToSkeleton2D(clip,
|
|
72
|
-
expect(
|
|
99
|
+
applyAnimationClipToSkeleton2D(clip, setup, pose, 1);
|
|
100
|
+
expect(pose.bones[0].rotation).toBe(7); // untouched
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
describe('applyAnimationClipToSkeleton2D slot channels', () => {
|
|
105
|
+
it('WRITES an absolute slot colour rather than composing it onto the setup colour', () => {
|
|
106
|
+
// Composing would double-apply the tint; Spine and DragonBones both author colour absolutely.
|
|
107
|
+
const setup = createSkeleton2D([makeBone()], [{ attachment: null, boneIndex: 0, color: 0x112233ff, name: 's' }]);
|
|
108
|
+
const pose = cloneSkeleton2D(setup);
|
|
109
|
+
const clip = createAnimationClip([
|
|
110
|
+
createAnimationChannel(createAnimationTrack({ components: 4, times: [0, 1], values: [1, 0, 0, 1, 0, 0, 1, 1] }), {
|
|
111
|
+
path: Skeleton2DSlotAnimationPath.Color,
|
|
112
|
+
slotIndex: 0,
|
|
113
|
+
}),
|
|
114
|
+
]);
|
|
115
|
+
applyAnimationClipToSkeleton2D(clip, setup, pose, 0);
|
|
116
|
+
expect(pose.slots![0].color).toBe(0xff0000ff);
|
|
117
|
+
applyAnimationClipToSkeleton2D(clip, setup, pose, 1);
|
|
118
|
+
expect(pose.slots![0].color).toBe(0x0000ffff);
|
|
119
|
+
expect(setup.slots![0].color).toBe(0x112233ff); // setup untouched
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('interpolates colour channels between keyframes', () => {
|
|
123
|
+
const setup = createSkeleton2D([makeBone()], [{ attachment: null, boneIndex: 0, color: 0, name: 's' }]);
|
|
124
|
+
const pose = cloneSkeleton2D(setup);
|
|
125
|
+
const clip = createAnimationClip([
|
|
126
|
+
createAnimationChannel(createAnimationTrack({ components: 4, times: [0, 1], values: [0, 0, 0, 0, 1, 1, 1, 1] }), {
|
|
127
|
+
path: Skeleton2DSlotAnimationPath.Color,
|
|
128
|
+
slotIndex: 0,
|
|
129
|
+
}),
|
|
130
|
+
]);
|
|
131
|
+
applyAnimationClipToSkeleton2D(clip, setup, pose, 0.5);
|
|
132
|
+
expect(pose.slots![0].color).toBe(0x80808080); // 0.5 -> 127.5 rounds to 128 on every channel
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('CLAMPS an overshooting sample instead of letting it wrap the packed colour', () => {
|
|
136
|
+
// An easing curve can legitimately overshoot its endpoints; 1.4 must saturate, not wrap to a low byte.
|
|
137
|
+
const setup = createSkeleton2D([makeBone()], [{ attachment: null, boneIndex: 0, color: 0, name: 's' }]);
|
|
138
|
+
const pose = cloneSkeleton2D(setup);
|
|
139
|
+
const clip = createAnimationClip([
|
|
140
|
+
createAnimationChannel(createAnimationTrack({ components: 4, times: [0], values: [1.4, -0.2, 1, 1] }), {
|
|
141
|
+
path: Skeleton2DSlotAnimationPath.Color,
|
|
142
|
+
slotIndex: 0,
|
|
143
|
+
}),
|
|
144
|
+
]);
|
|
145
|
+
applyAnimationClipToSkeleton2D(clip, setup, pose, 0);
|
|
146
|
+
expect(pose.slots![0].color).toBe(0xff00ffff);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('ignores a slot channel whose index is out of range, or a skeleton with no slots', () => {
|
|
150
|
+
const setup = createSkeleton2D([makeBone()], [{ attachment: null, boneIndex: 0, color: 0x010203ff, name: 's' }]);
|
|
151
|
+
const pose = cloneSkeleton2D(setup);
|
|
152
|
+
const clip = createAnimationClip([
|
|
153
|
+
createAnimationChannel(createAnimationTrack({ components: 4, times: [0], values: [1, 1, 1, 1] }), {
|
|
154
|
+
path: Skeleton2DSlotAnimationPath.Color,
|
|
155
|
+
slotIndex: 9,
|
|
156
|
+
}),
|
|
157
|
+
]);
|
|
158
|
+
expect(() => applyAnimationClipToSkeleton2D(clip, setup, pose, 0)).not.toThrow();
|
|
159
|
+
expect(pose.slots![0].color).toBe(0x010203ff);
|
|
160
|
+
|
|
161
|
+
const boneOnly = createSkeleton2D([makeBone()]);
|
|
162
|
+
const bonePose = cloneSkeleton2D(boneOnly);
|
|
163
|
+
expect(() => applyAnimationClipToSkeleton2D(clip, boneOnly, bonePose, 0)).not.toThrow();
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('drives bone and slot channels from ONE clip, dispatching on target shape', () => {
|
|
167
|
+
const setup = createSkeleton2D(
|
|
168
|
+
[makeBone({ rotation: 10 })],
|
|
169
|
+
[{ attachment: null, boneIndex: 0, color: 0, name: 's' }],
|
|
170
|
+
);
|
|
171
|
+
const pose = cloneSkeleton2D(setup);
|
|
172
|
+
const clip = createAnimationClip([
|
|
173
|
+
createAnimationChannel(createAnimationTrack({ components: 1, times: [0], values: [90] }), {
|
|
174
|
+
boneIndex: 0,
|
|
175
|
+
path: Skeleton2DAnimationPath.Rotation,
|
|
176
|
+
}),
|
|
177
|
+
createAnimationChannel(createAnimationTrack({ components: 4, times: [0], values: [1, 1, 1, 1] }), {
|
|
178
|
+
path: Skeleton2DSlotAnimationPath.Color,
|
|
179
|
+
slotIndex: 0,
|
|
180
|
+
}),
|
|
181
|
+
]);
|
|
182
|
+
applyAnimationClipToSkeleton2D(clip, setup, pose, 0);
|
|
183
|
+
expect(pose.bones[0].rotation).toBeCloseTo(100, 5); // bone still COMPOSES onto setup
|
|
184
|
+
expect(pose.slots![0].color).toBe(0xffffffff); // slot WRITES
|
|
73
185
|
});
|
|
74
186
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Bone2D, MeshAttachment2D, Skin2D } from '@flighthq/types';
|
|
2
|
-
import { MeshAttachment2DKind, TransformMode2D } from '@flighthq/types';
|
|
1
|
+
import type { Bone2D, MeshAttachment2D, Skin2D } from '@flighthq/types/contract';
|
|
2
|
+
import { MeshAttachment2DKind, TransformMode2D } from '@flighthq/types/contract';
|
|
3
3
|
import { describe, expect, it } from 'vitest';
|
|
4
4
|
|
|
5
5
|
import { deformSkeleton2DMeshAttachment } from './deformMeshAttachment2D';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Bone2D, RegionAttachment2D } from '@flighthq/types';
|
|
2
|
-
import { RegionAttachment2DKind, TransformMode2D } from '@flighthq/types';
|
|
1
|
+
import type { Bone2D, RegionAttachment2D } from '@flighthq/types/contract';
|
|
2
|
+
import { RegionAttachment2DKind, TransformMode2D } from '@flighthq/types/contract';
|
|
3
3
|
import { describe, expect, it } from 'vitest';
|
|
4
4
|
|
|
5
5
|
import { computeSkeleton2DRegionAttachmentVertices } from './regionAttachment2D';
|
package/src/skeleton2d.test.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createMatrix } from '@flighthq/geometry';
|
|
2
|
-
import type { Bone2D } from '@flighthq/types';
|
|
3
|
-
import { TransformMode2D } from '@flighthq/types';
|
|
1
|
+
import { createMatrix } from '@flighthq/geometry/contract';
|
|
2
|
+
import type { Bone2D, RegionAttachment2D, Slot2D } from '@flighthq/types/contract';
|
|
3
|
+
import { RegionAttachment2DKind, TransformMode2D } from '@flighthq/types/contract';
|
|
4
4
|
import { describe, expect, it } from 'vitest';
|
|
5
5
|
|
|
6
6
|
import {
|
|
@@ -12,7 +12,9 @@ import {
|
|
|
12
12
|
equalsSkeleton2D,
|
|
13
13
|
getSkeleton2DBoneIndexByName,
|
|
14
14
|
getSkeleton2DBoneWorldMatrix,
|
|
15
|
+
getSkeleton2DSkin,
|
|
15
16
|
setSkeleton2DBindPose,
|
|
17
|
+
setSkeleton2DSkin,
|
|
16
18
|
validateSkeleton2D,
|
|
17
19
|
} from './skeleton2d';
|
|
18
20
|
|
|
@@ -151,6 +153,120 @@ describe('computeSkeleton2DWorldTransforms', () => {
|
|
|
151
153
|
const det = out.a * out.d - out.c * out.b;
|
|
152
154
|
expect(det).toBeCloseTo(1, 5);
|
|
153
155
|
});
|
|
156
|
+
|
|
157
|
+
// FORMULA parity — expected world matrices computed BY HAND from Spine's published bone-transform
|
|
158
|
+
// formulas (updateWorldTransform per transformMode), NOT from a real rig corpus. These use an ASYMMETRIC
|
|
159
|
+
// parent (rotation 90°, scaleX 2, scaleY 1 → world column-lengths psx=2, psy=1) so a bug that confused
|
|
160
|
+
// the two column scales, or that skipped the parent×local compose, would surface — cases the symmetric
|
|
161
|
+
// fixtures above cannot catch. Corpus parity against Spine's own runtime output remains open and requires
|
|
162
|
+
// a permissively-licensed rig AND oracle (see skeleton2d-formats charter); this proves formula match only.
|
|
163
|
+
it('FORMULA parity: Normal composes parent × local (asymmetric 90°/2×1 parent + a 90° child)', () => {
|
|
164
|
+
// Parent world = [a,b,c,d] = [cos90·2, sin90·2, cos180·1, sin180·1] = [0, 2, -1, 0].
|
|
165
|
+
// Child local (rot 90°, unit scale) = [0, 1, -1, 0]. Normal: world = parentMatrix × localMatrix:
|
|
166
|
+
// a=pa·la+pc·lb=0·0+(-1)·1=-1 b=pb·la+pd·lb=2·0+0·1=0
|
|
167
|
+
// c=pa·lc+pc·ld=0·(-1)+(-1)·0=0 d=pb·lc+pd·ld=2·(-1)+0·0=-2 → [-1, 0, 0, -2] (det 2 = parent det × child det).
|
|
168
|
+
const s = createSkeleton2D([
|
|
169
|
+
makeBone({ rotation: 90, scaleX: 2, scaleY: 1 }),
|
|
170
|
+
makeBone({ parentIndex: 0, rotation: 90 }),
|
|
171
|
+
]);
|
|
172
|
+
computeSkeleton2DWorldTransforms(s);
|
|
173
|
+
const out = createMatrix();
|
|
174
|
+
getSkeleton2DBoneWorldMatrix(out, s, 1);
|
|
175
|
+
expect(out.a).toBeCloseTo(-1, 5);
|
|
176
|
+
expect(out.b).toBeCloseTo(0, 5);
|
|
177
|
+
expect(out.c).toBeCloseTo(0, 5);
|
|
178
|
+
expect(out.d).toBeCloseTo(-2, 5);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('FORMULA parity: NoRotationOrReflection keeps per-axis parent scale (2,1), strips rotation', () => {
|
|
182
|
+
// Parent world [0,2,-1,0] → psx=hypot(0,2)=2, psy=hypot(-1,0)=1. Identity child, axis-aligned scale-only
|
|
183
|
+
// parent: a=psx·la=2·1=2, b=psy·lb=1·0=0, c=psx·lc=2·0=0, d=psy·ld=1·1=1 → [2, 0, 0, 1]. Asymmetric a≠d
|
|
184
|
+
// is the point: a uniform-scale parent would hide a psx/psy mix-up.
|
|
185
|
+
const s = createSkeleton2D([
|
|
186
|
+
makeBone({ rotation: 90, scaleX: 2, scaleY: 1 }),
|
|
187
|
+
makeBone({ parentIndex: 0, transformMode: TransformMode2D.NoRotationOrReflection }),
|
|
188
|
+
]);
|
|
189
|
+
computeSkeleton2DWorldTransforms(s);
|
|
190
|
+
const out = createMatrix();
|
|
191
|
+
getSkeleton2DBoneWorldMatrix(out, s, 1);
|
|
192
|
+
expect(out.a).toBeCloseTo(2, 5);
|
|
193
|
+
expect(out.b).toBeCloseTo(0, 5);
|
|
194
|
+
expect(out.c).toBeCloseTo(0, 5);
|
|
195
|
+
expect(out.d).toBeCloseTo(1, 5);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it('FORMULA parity: NoScale keeps the parent rotation but strips its (2,1) scale to unit', () => {
|
|
199
|
+
// Parent world [0,2,-1,0], normalized columns: nax=0/2=0, nay=2/2=1, ncx=-1/1=-1, ncy=0/1=0. Identity
|
|
200
|
+
// child: a=nax·la+ncx·lb=0, b=nay·la+ncy·lb=1, c=nax·lc+ncx·ld=-1, d=nay·lc+ncy·ld=0 → [0,1,-1,0]:
|
|
201
|
+
// a pure 90° rotation (det +1), the parent's orientation with the scale removed.
|
|
202
|
+
const s = createSkeleton2D([
|
|
203
|
+
makeBone({ rotation: 90, scaleX: 2, scaleY: 1 }),
|
|
204
|
+
makeBone({ parentIndex: 0, transformMode: TransformMode2D.NoScale }),
|
|
205
|
+
]);
|
|
206
|
+
computeSkeleton2DWorldTransforms(s);
|
|
207
|
+
const out = createMatrix();
|
|
208
|
+
getSkeleton2DBoneWorldMatrix(out, s, 1);
|
|
209
|
+
expect(out.a).toBeCloseTo(0, 5);
|
|
210
|
+
expect(out.b).toBeCloseTo(1, 5);
|
|
211
|
+
expect(out.c).toBeCloseTo(-1, 5);
|
|
212
|
+
expect(out.d).toBeCloseTo(0, 5);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('FORMULA parity: NoScale vs NoScaleOrReflection differ on a reflected parent (keep vs strip the flip)', () => {
|
|
216
|
+
// Reflected parent (scaleY -1) world = [1, 0, 0, -1] (det -1). Identity children. NoScale keeps the
|
|
217
|
+
// parent reflection → [1,0,0,-1] (det -1); NoScaleOrReflection forces y-axis = +90° of x-axis → [1,0,0,1]
|
|
218
|
+
// (det +1). This side-by-side contrast is the exact semantic boundary between the two modes.
|
|
219
|
+
const s = createSkeleton2D([
|
|
220
|
+
makeBone({ scaleX: 1, scaleY: -1 }),
|
|
221
|
+
makeBone({ parentIndex: 0, transformMode: TransformMode2D.NoScale }),
|
|
222
|
+
makeBone({ parentIndex: 0, transformMode: TransformMode2D.NoScaleOrReflection }),
|
|
223
|
+
]);
|
|
224
|
+
computeSkeleton2DWorldTransforms(s);
|
|
225
|
+
const kept = createMatrix();
|
|
226
|
+
getSkeleton2DBoneWorldMatrix(kept, s, 1);
|
|
227
|
+
expect(kept.a).toBeCloseTo(1, 5);
|
|
228
|
+
expect(kept.d).toBeCloseTo(-1, 5);
|
|
229
|
+
expect(kept.a * kept.d - kept.c * kept.b).toBeCloseTo(-1, 5); // reflection kept
|
|
230
|
+
const stripped = createMatrix();
|
|
231
|
+
getSkeleton2DBoneWorldMatrix(stripped, s, 2);
|
|
232
|
+
expect(stripped.a).toBeCloseTo(1, 5);
|
|
233
|
+
expect(stripped.d).toBeCloseTo(1, 5);
|
|
234
|
+
expect(stripped.a * stripped.d - stripped.c * stripped.b).toBeCloseTo(1, 5); // reflection stripped
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('FORMULA parity: a root bone applies shearX as an offset to the x-axis angle', () => {
|
|
238
|
+
// Local formula: a=cos(rot+shearX)·scaleX, b=sin(rot+shearX)·scaleX. With rot 0, shearX 45°, unit scale:
|
|
239
|
+
// x-axis is at 45° (a=b=cos45=√2/2) while the y-axis stays at rot+90°=90° (c=0,d=1) — non-orthogonal
|
|
240
|
+
// axes, the defining signature of shear.
|
|
241
|
+
const s = createSkeleton2D([makeBone({ shearX: 45 })]);
|
|
242
|
+
computeSkeleton2DWorldTransforms(s);
|
|
243
|
+
const root2 = Math.SQRT1_2; // cos45 = sin45 = √2/2
|
|
244
|
+
expect(s.worldMatrices[0]).toBeCloseTo(root2, 5); // a
|
|
245
|
+
expect(s.worldMatrices[1]).toBeCloseTo(root2, 5); // b
|
|
246
|
+
expect(s.worldMatrices[2]).toBeCloseTo(0, 5); // c
|
|
247
|
+
expect(s.worldMatrices[3]).toBeCloseTo(1, 5); // d
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('FORMULA parity: an inherit combo with NO named preset — keep rotation+scale, strip reflection', () => {
|
|
251
|
+
// {rotation, scale} true but reflection false has no TransformMode2D preset; the factored boolean model
|
|
252
|
+
// handles it. Under a reflected+scaled parent [2,0,0,-2] (det −4), it keeps the (2,2) scale but strips
|
|
253
|
+
// the reflection, so the child basis is [2,0,0,2] (det +4) rather than Normal's [2,0,0,-2].
|
|
254
|
+
const s = createSkeleton2D([
|
|
255
|
+
makeBone({ scaleX: 2, scaleY: -2 }), // reflected (negative Y scale)
|
|
256
|
+
makeBone({
|
|
257
|
+
parentIndex: 0,
|
|
258
|
+
transformMode: { reflection: false, rotation: true, scale: true, translation: true },
|
|
259
|
+
}),
|
|
260
|
+
]);
|
|
261
|
+
computeSkeleton2DWorldTransforms(s);
|
|
262
|
+
const out = createMatrix();
|
|
263
|
+
getSkeleton2DBoneWorldMatrix(out, s, 1);
|
|
264
|
+
expect(out.a).toBeCloseTo(2, 5);
|
|
265
|
+
expect(out.b).toBeCloseTo(0, 5);
|
|
266
|
+
expect(out.c).toBeCloseTo(0, 5);
|
|
267
|
+
expect(out.d).toBeCloseTo(2, 5); // reflection stripped: +2, not −2
|
|
268
|
+
expect(out.a * out.d - out.c * out.b).toBeCloseTo(4, 5); // det positive (scale kept, reflection dropped)
|
|
269
|
+
});
|
|
154
270
|
});
|
|
155
271
|
|
|
156
272
|
describe('createSkeleton2D', () => {
|
|
@@ -202,6 +318,23 @@ describe('getSkeleton2DBoneWorldMatrix', () => {
|
|
|
202
318
|
});
|
|
203
319
|
});
|
|
204
320
|
|
|
321
|
+
describe('getSkeleton2DSkin', () => {
|
|
322
|
+
it('finds a skin by name and returns the null sentinel otherwise', () => {
|
|
323
|
+
const skeleton = createSkeleton2D([makeBone({ name: 'root' })], [testSlot('head', 0)]);
|
|
324
|
+
skeleton.skins = [
|
|
325
|
+
{ attachments: [], name: 'goblin' },
|
|
326
|
+
{ attachments: [], name: 'goblingirl' },
|
|
327
|
+
];
|
|
328
|
+
expect(getSkeleton2DSkin(skeleton, 'goblingirl')!.name).toBe('goblingirl');
|
|
329
|
+
expect(getSkeleton2DSkin(skeleton, 'nope')).toBeNull();
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it('returns null for a rig carrying no wardrobe at all', () => {
|
|
333
|
+
const skeleton = createSkeleton2D([makeBone({ name: 'root' })]);
|
|
334
|
+
expect(getSkeleton2DSkin(skeleton, 'goblin')).toBeNull();
|
|
335
|
+
});
|
|
336
|
+
});
|
|
337
|
+
|
|
205
338
|
describe('setSkeleton2DBindPose', () => {
|
|
206
339
|
it('captures the inverse of the current world so the palette is identity at bind', () => {
|
|
207
340
|
const s = createSkeleton2D([makeBone({ x: 4, rotation: 60, scaleX: 2 })]);
|
|
@@ -215,6 +348,49 @@ describe('setSkeleton2DBindPose', () => {
|
|
|
215
348
|
});
|
|
216
349
|
});
|
|
217
350
|
|
|
351
|
+
describe('setSkeleton2DSkin', () => {
|
|
352
|
+
it('writes the skin attachments onto the slots they name', () => {
|
|
353
|
+
const skeleton = createSkeleton2D([makeBone({ name: 'root' })], [testSlot('head', 0), testSlot('hand', 0)]);
|
|
354
|
+
const hat = testRegion('hat');
|
|
355
|
+
setSkeleton2DSkin(skeleton, { attachments: [{ attachment: hat, name: 'head', slotIndex: 0 }], name: 'goblin' });
|
|
356
|
+
expect(skeleton.slots![0].attachment).toBe(hat);
|
|
357
|
+
});
|
|
358
|
+
|
|
359
|
+
it('LEAVES slots the skin does not mention alone, so a partial skin layers over a base', () => {
|
|
360
|
+
const base = testRegion('body');
|
|
361
|
+
const skeleton = createSkeleton2D([makeBone({ name: 'root' })], [testSlot('head', 0), testSlot('body', 0)]);
|
|
362
|
+
skeleton.slots![1].attachment = base;
|
|
363
|
+
const hat = testRegion('hat');
|
|
364
|
+
setSkeleton2DSkin(skeleton, { attachments: [{ attachment: hat, name: 'head', slotIndex: 0 }], name: 'goblin' });
|
|
365
|
+
expect(skeleton.slots![0].attachment).toBe(hat);
|
|
366
|
+
expect(skeleton.slots![1].attachment).toBe(base); // shared art survives the overlay
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
it('skips an entry naming a slot outside the skeleton rather than throwing', () => {
|
|
370
|
+
const skeleton = createSkeleton2D([makeBone({ name: 'root' })], [testSlot('head', 0)]);
|
|
371
|
+
expect(() =>
|
|
372
|
+
setSkeleton2DSkin(skeleton, {
|
|
373
|
+
attachments: [
|
|
374
|
+
{ attachment: testRegion('ghost'), name: 'ghost', slotIndex: 9 },
|
|
375
|
+
{ attachment: testRegion('ghost2'), name: 'ghost2', slotIndex: -1 },
|
|
376
|
+
],
|
|
377
|
+
name: 'broken',
|
|
378
|
+
}),
|
|
379
|
+
).not.toThrow();
|
|
380
|
+
expect(skeleton.slots![0].attachment).toBeNull();
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it('is a no-op on a skeleton with no slots', () => {
|
|
384
|
+
const skeleton = createSkeleton2D([makeBone({ name: 'root' })]);
|
|
385
|
+
expect(() =>
|
|
386
|
+
setSkeleton2DSkin(skeleton, {
|
|
387
|
+
attachments: [{ attachment: testRegion('x'), name: 'x', slotIndex: 0 }],
|
|
388
|
+
name: 's',
|
|
389
|
+
}),
|
|
390
|
+
).not.toThrow();
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
|
|
218
394
|
describe('validateSkeleton2D', () => {
|
|
219
395
|
it('returns null for a valid parent-before-child skeleton', () => {
|
|
220
396
|
const s = createSkeleton2D([makeBone(), makeBone({ parentIndex: 0 })]);
|
|
@@ -232,3 +408,12 @@ describe('validateSkeleton2D', () => {
|
|
|
232
408
|
expect(validateSkeleton2D(s)).toContain('worldMatrices');
|
|
233
409
|
});
|
|
234
410
|
});
|
|
411
|
+
|
|
412
|
+
// A minimal slot for wardrobe tests: no attachment until a skin supplies one.
|
|
413
|
+
function testSlot(name: string, boneIndex: number): Slot2D {
|
|
414
|
+
return { attachment: null, boneIndex, color: 0xffffffff, name };
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function testRegion(name: string): RegionAttachment2D {
|
|
418
|
+
return { height: 0, kind: RegionAttachment2DKind, name, rotation: 0, scaleX: 1, scaleY: 1, width: 0, x: 0, y: 0 };
|
|
419
|
+
}
|