@sarmal/core 0.5.0 → 0.7.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/dist/auto-init.cjs +174 -40
- package/dist/auto-init.cjs.map +1 -1
- package/dist/auto-init.js +174 -40
- package/dist/auto-init.js.map +1 -1
- package/dist/index.cjs +278 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -12
- package/dist/index.d.ts +52 -12
- package/dist/index.js +278 -41
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -44,8 +44,8 @@ var CircularBuffer = class {
|
|
|
44
44
|
return this.count;
|
|
45
45
|
}
|
|
46
46
|
};
|
|
47
|
-
function
|
|
48
|
-
|
|
47
|
+
function resolveCurve(curveDef) {
|
|
48
|
+
return {
|
|
49
49
|
name: curveDef.name,
|
|
50
50
|
fn: curveDef.fn,
|
|
51
51
|
period: curveDef.period ?? TWO_PI,
|
|
@@ -53,15 +53,37 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
53
53
|
skeleton: curveDef.skeleton,
|
|
54
54
|
skeletonFn: curveDef.skeletonFn
|
|
55
55
|
};
|
|
56
|
+
}
|
|
57
|
+
function createEngine(curveDef, trailLength = 120) {
|
|
58
|
+
let curve = resolveCurve(curveDef);
|
|
56
59
|
const trail = new CircularBuffer(trailLength);
|
|
57
60
|
let t = 0;
|
|
58
61
|
let actualTime = 0;
|
|
62
|
+
let morphCurveB = null;
|
|
63
|
+
let _morphAlpha = null;
|
|
64
|
+
let _morphStrategy = "normalized";
|
|
65
|
+
function sampleSkeleton(c, sampleT) {
|
|
66
|
+
if (c.skeletonFn) {
|
|
67
|
+
return c.skeletonFn(sampleT);
|
|
68
|
+
}
|
|
69
|
+
if (c.skeleton === "live") {
|
|
70
|
+
return c.fn(sampleT, actualTime, {});
|
|
71
|
+
}
|
|
72
|
+
return c.fn(sampleT, 0, {});
|
|
73
|
+
}
|
|
59
74
|
return {
|
|
60
75
|
tick(deltaTime) {
|
|
61
76
|
t = (t + curve.speed * deltaTime) % curve.period;
|
|
62
77
|
actualTime += deltaTime;
|
|
63
|
-
|
|
64
|
-
|
|
78
|
+
if (morphCurveB !== null && _morphAlpha !== null) {
|
|
79
|
+
const a = curve.fn(t, actualTime, {});
|
|
80
|
+
const tB = _morphStrategy === "normalized" ? t / curve.period * morphCurveB.period : t;
|
|
81
|
+
const b = morphCurveB.fn(tB, actualTime, {});
|
|
82
|
+
trail.push(a.x + (b.x - a.x) * _morphAlpha, a.y + (b.y - a.y) * _morphAlpha);
|
|
83
|
+
} else {
|
|
84
|
+
const point = curve.fn(t, actualTime, {});
|
|
85
|
+
trail.push(point.x, point.y);
|
|
86
|
+
}
|
|
65
87
|
return trail.toArray();
|
|
66
88
|
},
|
|
67
89
|
get trailCount() {
|
|
@@ -70,6 +92,9 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
70
92
|
get isLiveSkeleton() {
|
|
71
93
|
return curve.skeleton === "live";
|
|
72
94
|
},
|
|
95
|
+
get morphAlpha() {
|
|
96
|
+
return _morphAlpha;
|
|
97
|
+
},
|
|
73
98
|
reset() {
|
|
74
99
|
t = 0;
|
|
75
100
|
actualTime = 0;
|
|
@@ -98,24 +123,62 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
98
123
|
trail.push(point.x, point.y);
|
|
99
124
|
}
|
|
100
125
|
},
|
|
126
|
+
startMorph(target, strategy = "normalized") {
|
|
127
|
+
const resolvedTarget = resolveCurve(target);
|
|
128
|
+
if (morphCurveB !== null && _morphAlpha !== null) {
|
|
129
|
+
const frozenAlpha = _morphAlpha;
|
|
130
|
+
const frozenA = curve;
|
|
131
|
+
const frozenB = morphCurveB;
|
|
132
|
+
const frozenStrategy = _morphStrategy;
|
|
133
|
+
curve = {
|
|
134
|
+
...frozenB,
|
|
135
|
+
fn: (sampleT, time, params) => {
|
|
136
|
+
const a = frozenA.fn(sampleT, time, params);
|
|
137
|
+
const tB = frozenStrategy === "normalized" ? sampleT / frozenA.period * frozenB.period : sampleT;
|
|
138
|
+
const b = frozenB.fn(tB, time, params);
|
|
139
|
+
return {
|
|
140
|
+
x: a.x + (b.x - a.x) * frozenAlpha,
|
|
141
|
+
y: a.y + (b.y - a.y) * frozenAlpha
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
_morphStrategy = strategy;
|
|
147
|
+
morphCurveB = resolvedTarget;
|
|
148
|
+
_morphAlpha = 0;
|
|
149
|
+
},
|
|
150
|
+
setMorphAlpha(alpha) {
|
|
151
|
+
_morphAlpha = alpha;
|
|
152
|
+
},
|
|
153
|
+
completeMorph() {
|
|
154
|
+
if (morphCurveB !== null) {
|
|
155
|
+
if (_morphStrategy === "normalized" && curve.period !== morphCurveB.period) {
|
|
156
|
+
t = t / curve.period * morphCurveB.period;
|
|
157
|
+
}
|
|
158
|
+
curve = morphCurveB;
|
|
159
|
+
}
|
|
160
|
+
morphCurveB = null;
|
|
161
|
+
_morphAlpha = null;
|
|
162
|
+
},
|
|
101
163
|
getSarmalSkeleton() {
|
|
102
164
|
const steps = Math.ceil(curve.period * POINTS_PER_PERIOD_UNIT);
|
|
103
165
|
const points = new Array(steps);
|
|
104
|
-
if (
|
|
166
|
+
if (morphCurveB !== null && _morphAlpha !== null) {
|
|
105
167
|
for (let i = 0; i < steps; i++) {
|
|
106
168
|
const sampleT = i / (steps - 1) * curve.period;
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
} else {
|
|
115
|
-
for (let i = 0; i < steps; i++) {
|
|
116
|
-
const sampleT = i / (steps - 1) * curve.period;
|
|
117
|
-
points[i] = curve.fn(sampleT, 0, {});
|
|
169
|
+
const a = sampleSkeleton(curve, sampleT);
|
|
170
|
+
const tB = _morphStrategy === "normalized" ? sampleT / curve.period * morphCurveB.period : sampleT;
|
|
171
|
+
const b = sampleSkeleton(morphCurveB, tB);
|
|
172
|
+
points[i] = {
|
|
173
|
+
x: a.x + (b.x - a.x) * _morphAlpha,
|
|
174
|
+
y: a.y + (b.y - a.y) * _morphAlpha
|
|
175
|
+
};
|
|
118
176
|
}
|
|
177
|
+
return points;
|
|
178
|
+
}
|
|
179
|
+
for (let i = 0; i < steps; i++) {
|
|
180
|
+
const sampleT = i / (steps - 1) * curve.period;
|
|
181
|
+
points[i] = sampleSkeleton(curve, sampleT);
|
|
119
182
|
}
|
|
120
183
|
return points;
|
|
121
184
|
}
|
|
@@ -123,6 +186,7 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
123
186
|
}
|
|
124
187
|
|
|
125
188
|
// src/renderer.ts
|
|
189
|
+
var DEFAULT_MORPH_DURATION_MS = 300;
|
|
126
190
|
var DEFAULT_HEAD_RADIUS = 4;
|
|
127
191
|
var DEFAULT_GLOW_SIZE = 20;
|
|
128
192
|
var DEFAULT_SKELETON_COLOR = "#ffffff";
|
|
@@ -165,25 +229,20 @@ function createRenderer(options) {
|
|
|
165
229
|
let offsetY = 0;
|
|
166
230
|
let animationId = null;
|
|
167
231
|
let lastTime = 0;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
232
|
+
let morphResolve = null;
|
|
233
|
+
let morphDurationMs = DEFAULT_MORPH_DURATION_MS;
|
|
234
|
+
let morphAlpha = 0;
|
|
235
|
+
let morphBoundsA = null;
|
|
236
|
+
let morphBoundsB = null;
|
|
237
|
+
function computeBoundaries(pts) {
|
|
238
|
+
if (pts.length === 0) return null;
|
|
239
|
+
const first = pts[0];
|
|
173
240
|
let minX = first.x, maxX = first.x, minY = first.y, maxY = first.y;
|
|
174
|
-
for (const p of
|
|
175
|
-
if (p.x < minX)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (p.
|
|
179
|
-
maxX = p.x;
|
|
180
|
-
}
|
|
181
|
-
if (p.y < minY) {
|
|
182
|
-
minY = p.y;
|
|
183
|
-
}
|
|
184
|
-
if (p.y > maxY) {
|
|
185
|
-
maxY = p.y;
|
|
186
|
-
}
|
|
241
|
+
for (const p of pts) {
|
|
242
|
+
if (p.x < minX) minX = p.x;
|
|
243
|
+
if (p.x > maxX) maxX = p.x;
|
|
244
|
+
if (p.y < minY) minY = p.y;
|
|
245
|
+
if (p.y > maxY) maxY = p.y;
|
|
187
246
|
}
|
|
188
247
|
const width = maxX - minX;
|
|
189
248
|
const height = maxY - minY;
|
|
@@ -191,11 +250,22 @@ function createRenderer(options) {
|
|
|
191
250
|
const canvasHeight = canvas.height;
|
|
192
251
|
const scaleX = canvasWidth / (width * (1 + FIT_PADDING * 2));
|
|
193
252
|
const scaleY = canvasHeight / (height * (1 + FIT_PADDING * 2));
|
|
194
|
-
|
|
195
|
-
const boundsWidth = width *
|
|
196
|
-
const boundsHeight = height *
|
|
197
|
-
|
|
198
|
-
|
|
253
|
+
const s = Math.min(scaleX, scaleY);
|
|
254
|
+
const boundsWidth = width * s;
|
|
255
|
+
const boundsHeight = height * s;
|
|
256
|
+
return {
|
|
257
|
+
scale: s,
|
|
258
|
+
offsetX: (canvasWidth - boundsWidth) / 2 - minX * s,
|
|
259
|
+
offsetY: (canvasHeight - boundsHeight) / 2 - minY * s
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
function calculateBoundaries() {
|
|
263
|
+
const b = computeBoundaries(skeleton);
|
|
264
|
+
if (b) {
|
|
265
|
+
scale = b.scale;
|
|
266
|
+
offsetX = b.offsetX;
|
|
267
|
+
offsetY = b.offsetY;
|
|
268
|
+
}
|
|
199
269
|
}
|
|
200
270
|
function buildSkeletonCanvas() {
|
|
201
271
|
if (skeleton.length < 2) return;
|
|
@@ -212,10 +282,25 @@ function createRenderer(options) {
|
|
|
212
282
|
}
|
|
213
283
|
skeletonCtx.stroke();
|
|
214
284
|
}
|
|
285
|
+
function drawSkeletonPath(pts, opacity) {
|
|
286
|
+
if (pts.length < 2) return;
|
|
287
|
+
ctx.strokeStyle = `rgba(${hexToRgbComponents(opts.skeletonColor)},${opacity})`;
|
|
288
|
+
ctx.lineWidth = 1.5;
|
|
289
|
+
ctx.beginPath();
|
|
290
|
+
ctx.moveTo(pts[0].x * scale + offsetX, pts[0].y * scale + offsetY);
|
|
291
|
+
for (let i = 1; i < pts.length; i++) {
|
|
292
|
+
ctx.lineTo(pts[i].x * scale + offsetX, pts[i].y * scale + offsetY);
|
|
293
|
+
}
|
|
294
|
+
ctx.stroke();
|
|
295
|
+
}
|
|
215
296
|
function drawSkeleton() {
|
|
216
297
|
if (opts.skeletonColor === "transparent") {
|
|
217
298
|
return;
|
|
218
299
|
}
|
|
300
|
+
if (engine.morphAlpha !== null) {
|
|
301
|
+
drawSkeletonPath(engine.getSarmalSkeleton(), DEFAULT_SKELETON_OPACITY);
|
|
302
|
+
return;
|
|
303
|
+
}
|
|
219
304
|
if (engine.isLiveSkeleton) {
|
|
220
305
|
if (skeleton.length < 2) {
|
|
221
306
|
return;
|
|
@@ -282,11 +367,34 @@ function createRenderer(options) {
|
|
|
282
367
|
const now = performance.now();
|
|
283
368
|
const deltaTime = Math.min((now - lastTime) / 1e3, 1 / 30);
|
|
284
369
|
lastTime = now;
|
|
370
|
+
if (engine.morphAlpha !== null) {
|
|
371
|
+
morphAlpha = Math.min(1, morphAlpha + deltaTime / (morphDurationMs / 1e3));
|
|
372
|
+
engine.setMorphAlpha(morphAlpha);
|
|
373
|
+
if (morphBoundsA && morphBoundsB) {
|
|
374
|
+
const a = morphBoundsA;
|
|
375
|
+
const b = morphBoundsB;
|
|
376
|
+
scale = a.scale + (b.scale - a.scale) * morphAlpha;
|
|
377
|
+
offsetX = a.offsetX + (b.offsetX - a.offsetX) * morphAlpha;
|
|
378
|
+
offsetY = a.offsetY + (b.offsetY - a.offsetY) * morphAlpha;
|
|
379
|
+
}
|
|
380
|
+
if (morphAlpha >= 1) {
|
|
381
|
+
engine.completeMorph();
|
|
382
|
+
morphResolve?.();
|
|
383
|
+
morphResolve = null;
|
|
384
|
+
morphAlpha = 0;
|
|
385
|
+
morphBoundsA = null;
|
|
386
|
+
morphBoundsB = null;
|
|
387
|
+
skeleton = engine.getSarmalSkeleton();
|
|
388
|
+
if (!engine.isLiveSkeleton) {
|
|
389
|
+
buildSkeletonCanvas();
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
285
393
|
trail = engine.tick(deltaTime);
|
|
286
394
|
trailCount = engine.trailCount;
|
|
287
395
|
head = trailCount > 0 ? trail[trailCount - 1] : null;
|
|
288
396
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
289
|
-
if (engine.isLiveSkeleton) {
|
|
397
|
+
if (engine.isLiveSkeleton && engine.morphAlpha === null) {
|
|
290
398
|
skeleton = engine.getSarmalSkeleton();
|
|
291
399
|
calculateBoundaries();
|
|
292
400
|
}
|
|
@@ -331,11 +439,38 @@ function createRenderer(options) {
|
|
|
331
439
|
},
|
|
332
440
|
seekWithTrail(t) {
|
|
333
441
|
engine.seekWithTrail(t);
|
|
442
|
+
},
|
|
443
|
+
morphTo(target, options2) {
|
|
444
|
+
const interruptBounds = morphResolve !== null ? { scale, offsetX, offsetY } : null;
|
|
445
|
+
if (morphResolve !== null) {
|
|
446
|
+
engine.completeMorph();
|
|
447
|
+
morphResolve();
|
|
448
|
+
morphResolve = null;
|
|
449
|
+
morphAlpha = 0;
|
|
450
|
+
morphBoundsA = null;
|
|
451
|
+
morphBoundsB = null;
|
|
452
|
+
}
|
|
453
|
+
morphDurationMs = options2?.duration ?? DEFAULT_MORPH_DURATION_MS;
|
|
454
|
+
morphAlpha = 0;
|
|
455
|
+
morphBoundsA = interruptBounds ?? computeBoundaries(engine.getSarmalSkeleton()) ?? { scale, offsetX, offsetY };
|
|
456
|
+
engine.startMorph(target, options2?.morphStrategy);
|
|
457
|
+
const period = target.period ?? Math.PI * 2;
|
|
458
|
+
const samples = Math.max(50, Math.round(period * 20));
|
|
459
|
+
const skeletonFn = target.skeletonFn ?? ((t) => target.fn(t, 0, {}));
|
|
460
|
+
const skeletonB = Array.from(
|
|
461
|
+
{ length: samples + 1 },
|
|
462
|
+
(_, i) => skeletonFn(i / samples * period)
|
|
463
|
+
);
|
|
464
|
+
morphBoundsB = computeBoundaries(skeletonB) ?? { scale, offsetX, offsetY };
|
|
465
|
+
return new Promise((resolve) => {
|
|
466
|
+
morphResolve = resolve;
|
|
467
|
+
});
|
|
334
468
|
}
|
|
335
469
|
};
|
|
336
470
|
}
|
|
337
471
|
|
|
338
472
|
// src/renderer-svg.ts
|
|
473
|
+
var DEFAULT_MORPH_DURATION_MS2 = 300;
|
|
339
474
|
var TRAIL_BATCH_COUNT = 12;
|
|
340
475
|
var TRAIL_FADE_CURVE2 = 1.5;
|
|
341
476
|
var TRAIL_MAX_OPACITY2 = 0.88;
|
|
@@ -400,6 +535,20 @@ function createSVGRenderer(options) {
|
|
|
400
535
|
skeletonPath.setAttribute("stroke-opacity", String(DEFAULT_SKELETON_OPACITY2));
|
|
401
536
|
skeletonPath.setAttribute("stroke-width", "1.5");
|
|
402
537
|
svg.appendChild(skeletonPath);
|
|
538
|
+
const skeletonPathA = el("path");
|
|
539
|
+
skeletonPathA.setAttribute("fill", "none");
|
|
540
|
+
skeletonPathA.setAttribute("stroke", opts.skeletonColor);
|
|
541
|
+
skeletonPathA.setAttribute("stroke-width", "1.5");
|
|
542
|
+
skeletonPathA.setAttribute("visibility", "hidden");
|
|
543
|
+
svg.appendChild(skeletonPathA);
|
|
544
|
+
const skeletonPathB = el("path");
|
|
545
|
+
skeletonPathB.setAttribute("fill", "none");
|
|
546
|
+
skeletonPathB.setAttribute("stroke", opts.skeletonColor);
|
|
547
|
+
skeletonPathB.setAttribute("stroke-width", "1.5");
|
|
548
|
+
skeletonPathB.setAttribute("visibility", "hidden");
|
|
549
|
+
svg.appendChild(skeletonPathB);
|
|
550
|
+
let morphPathABuilt = "";
|
|
551
|
+
let morphPathBBuilt = "";
|
|
403
552
|
const trailPaths = [];
|
|
404
553
|
for (let i = 0; i < TRAIL_BATCH_COUNT; i++) {
|
|
405
554
|
const path = el("path");
|
|
@@ -515,13 +664,69 @@ function createSVGRenderer(options) {
|
|
|
515
664
|
let animationId = null;
|
|
516
665
|
let lastTime = 0;
|
|
517
666
|
const prefersReducedMotion = typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
667
|
+
let morphResolve = null;
|
|
668
|
+
let morphDurationMs = DEFAULT_MORPH_DURATION_MS2;
|
|
669
|
+
let morphTarget = null;
|
|
670
|
+
let morphAlpha = 0;
|
|
671
|
+
function buildSkeletonPath(target, scale2, offsetX2, offsetY2) {
|
|
672
|
+
const period = target.period ?? Math.PI * 2;
|
|
673
|
+
const samples = Math.max(50, Math.round(period * 20));
|
|
674
|
+
const points = [];
|
|
675
|
+
for (let i = 0; i <= samples; i++) {
|
|
676
|
+
const t = i / samples * period;
|
|
677
|
+
const p = target.fn(t, 0, {});
|
|
678
|
+
points.push(p);
|
|
679
|
+
}
|
|
680
|
+
if (points.length < 2) {
|
|
681
|
+
return "";
|
|
682
|
+
}
|
|
683
|
+
const px2 = (p) => (p.x * scale2 + offsetX2).toFixed(2);
|
|
684
|
+
const py2 = (p) => (p.y * scale2 + offsetY2).toFixed(2);
|
|
685
|
+
let d = `M${px2(points[0])} ${py2(points[0])}`;
|
|
686
|
+
for (let i = 1; i < points.length; i++) {
|
|
687
|
+
d += ` L${px2(points[i])} ${py2(points[i])}`;
|
|
688
|
+
}
|
|
689
|
+
d += " Z";
|
|
690
|
+
return d;
|
|
691
|
+
}
|
|
518
692
|
function renderFrame() {
|
|
519
693
|
const now = performance.now();
|
|
520
694
|
const dt = Math.min((now - lastTime) / 1e3, 1 / 30);
|
|
521
695
|
lastTime = now;
|
|
696
|
+
if (engine.morphAlpha !== null) {
|
|
697
|
+
morphAlpha = Math.min(1, morphAlpha + dt / (morphDurationMs / 1e3));
|
|
698
|
+
engine.setMorphAlpha(morphAlpha);
|
|
699
|
+
if (morphPathABuilt) {
|
|
700
|
+
skeletonPathA.setAttribute("d", morphPathABuilt);
|
|
701
|
+
skeletonPathA.setAttribute("visibility", "visible");
|
|
702
|
+
skeletonPathA.setAttribute(
|
|
703
|
+
"stroke-opacity",
|
|
704
|
+
String((1 - morphAlpha) * DEFAULT_SKELETON_OPACITY2)
|
|
705
|
+
);
|
|
706
|
+
}
|
|
707
|
+
if (morphPathBBuilt) {
|
|
708
|
+
skeletonPathB.setAttribute("d", morphPathBBuilt);
|
|
709
|
+
skeletonPathB.setAttribute("visibility", "visible");
|
|
710
|
+
skeletonPathB.setAttribute("stroke-opacity", String(morphAlpha * DEFAULT_SKELETON_OPACITY2));
|
|
711
|
+
}
|
|
712
|
+
if (morphAlpha >= 1) {
|
|
713
|
+
engine.completeMorph();
|
|
714
|
+
morphResolve?.();
|
|
715
|
+
morphResolve = null;
|
|
716
|
+
morphTarget = null;
|
|
717
|
+
morphAlpha = 0;
|
|
718
|
+
morphPathABuilt = "";
|
|
719
|
+
morphPathBBuilt = "";
|
|
720
|
+
skeletonPathA.setAttribute("visibility", "hidden");
|
|
721
|
+
skeletonPathB.setAttribute("visibility", "hidden");
|
|
722
|
+
const newSkeleton = engine.getSarmalSkeleton();
|
|
723
|
+
calculateBoundaries(newSkeleton);
|
|
724
|
+
updateSkeleton(newSkeleton);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
522
727
|
const trail = engine.tick(dt);
|
|
523
728
|
const trailCount = engine.trailCount;
|
|
524
|
-
if (engine.isLiveSkeleton) {
|
|
729
|
+
if (engine.isLiveSkeleton && engine.morphAlpha === null) {
|
|
525
730
|
const liveSkeleton = engine.getSarmalSkeleton();
|
|
526
731
|
calculateBoundaries(liveSkeleton);
|
|
527
732
|
updateSkeleton(liveSkeleton);
|
|
@@ -562,6 +767,38 @@ function createSVGRenderer(options) {
|
|
|
562
767
|
},
|
|
563
768
|
seekWithTrail(t) {
|
|
564
769
|
engine.seekWithTrail(t);
|
|
770
|
+
},
|
|
771
|
+
morphTo(target, options2) {
|
|
772
|
+
if (morphResolve !== null) {
|
|
773
|
+
engine.completeMorph();
|
|
774
|
+
morphResolve();
|
|
775
|
+
morphResolve = null;
|
|
776
|
+
morphAlpha = 0;
|
|
777
|
+
skeletonPathA.setAttribute("visibility", "hidden");
|
|
778
|
+
skeletonPathB.setAttribute("visibility", "hidden");
|
|
779
|
+
}
|
|
780
|
+
morphDurationMs = options2?.duration ?? DEFAULT_MORPH_DURATION_MS2;
|
|
781
|
+
morphTarget = target;
|
|
782
|
+
morphAlpha = 0;
|
|
783
|
+
const currentSkeleton = engine.getSarmalSkeleton();
|
|
784
|
+
if (currentSkeleton.length >= 2) {
|
|
785
|
+
const px2 = (p) => (p.x * scale + offsetX).toFixed(2);
|
|
786
|
+
const py2 = (p) => (p.y * scale + offsetY).toFixed(2);
|
|
787
|
+
morphPathABuilt = `M${px2(currentSkeleton[0])} ${py2(currentSkeleton[0])}`;
|
|
788
|
+
for (let i = 1; i < currentSkeleton.length; i++) {
|
|
789
|
+
morphPathABuilt += ` L${px2(currentSkeleton[i])} ${py2(currentSkeleton[i])}`;
|
|
790
|
+
}
|
|
791
|
+
morphPathABuilt += " Z";
|
|
792
|
+
} else {
|
|
793
|
+
morphPathABuilt = "";
|
|
794
|
+
}
|
|
795
|
+
engine.startMorph(target, options2?.morphStrategy);
|
|
796
|
+
if (morphTarget) {
|
|
797
|
+
morphPathBBuilt = buildSkeletonPath(morphTarget, scale, offsetX, offsetY);
|
|
798
|
+
}
|
|
799
|
+
return new Promise((resolve) => {
|
|
800
|
+
morphResolve = resolve;
|
|
801
|
+
});
|
|
565
802
|
}
|
|
566
803
|
};
|
|
567
804
|
}
|