@sarmal/core 0.9.1 → 0.9.10
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 +196 -157
- package/dist/auto-init.cjs.map +1 -1
- package/dist/auto-init.d.cts +2 -1
- package/dist/auto-init.d.ts +2 -1
- package/dist/auto-init.js +195 -156
- package/dist/auto-init.js.map +1 -1
- package/dist/curves/artemis2.cjs +7 -10
- package/dist/curves/artemis2.d.cts +1 -1
- package/dist/curves/artemis2.d.ts +1 -1
- package/dist/curves/artemis2.js +6 -9
- package/dist/curves/astroid.cjs +4 -4
- package/dist/curves/astroid.d.cts +1 -1
- package/dist/curves/astroid.d.ts +1 -1
- package/dist/curves/astroid.js +3 -3
- package/dist/curves/deltoid.cjs +4 -4
- package/dist/curves/deltoid.d.cts +1 -1
- package/dist/curves/deltoid.d.ts +1 -1
- package/dist/curves/deltoid.js +3 -3
- package/dist/curves/epicycloid3.cjs +4 -4
- package/dist/curves/epicycloid3.d.cts +1 -1
- package/dist/curves/epicycloid3.d.ts +1 -1
- package/dist/curves/epicycloid3.js +3 -3
- package/dist/curves/epitrochoid7.cjs +5 -5
- package/dist/curves/epitrochoid7.d.cts +1 -1
- package/dist/curves/epitrochoid7.d.ts +1 -1
- package/dist/curves/epitrochoid7.js +4 -4
- package/dist/curves/index.cjs +28 -32
- package/dist/curves/index.d.cts +11 -11
- package/dist/curves/index.d.ts +11 -11
- package/dist/curves/index.js +28 -44
- package/dist/curves/lame.cjs +5 -6
- package/dist/curves/lame.d.cts +1 -1
- package/dist/curves/lame.d.ts +1 -1
- package/dist/curves/lame.js +4 -5
- package/dist/curves/lissajous32.cjs +4 -4
- package/dist/curves/lissajous32.d.cts +1 -1
- package/dist/curves/lissajous32.d.ts +1 -1
- package/dist/curves/lissajous32.js +3 -3
- package/dist/curves/lissajous43.cjs +4 -4
- package/dist/curves/lissajous43.d.cts +1 -1
- package/dist/curves/lissajous43.d.ts +1 -1
- package/dist/curves/lissajous43.js +3 -3
- package/dist/curves/rose3.cjs +4 -4
- package/dist/curves/rose3.d.cts +1 -1
- package/dist/curves/rose3.d.ts +1 -1
- package/dist/curves/rose3.js +3 -3
- package/dist/curves/rose5.cjs +4 -4
- package/dist/curves/rose5.d.cts +1 -1
- package/dist/curves/rose5.d.ts +1 -1
- package/dist/curves/rose5.js +3 -3
- package/dist/index.cjs +233 -265
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +31 -64
- package/dist/index.d.ts +31 -64
- package/dist/index.js +233 -282
- package/dist/index.js.map +1 -1
- package/dist/types-cR2xOewv.d.cts +223 -0
- package/dist/types-cR2xOewv.d.ts +223 -0
- package/package.json +5 -3
- package/dist/types-DX8VfIVK.d.cts +0 -226
- package/dist/types-DX8VfIVK.d.ts +0 -226
package/dist/auto-init.cjs
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
// src/engine.ts
|
|
4
4
|
var TWO_PI = Math.PI * 2;
|
|
5
5
|
var POINTS_PER_PERIOD_UNIT = 50;
|
|
6
|
+
function lerp(start, end, t) {
|
|
7
|
+
return start + (end - start) * t;
|
|
8
|
+
}
|
|
9
|
+
var EMPTY_PARAMS = {};
|
|
6
10
|
var CircularBuffer = class {
|
|
7
11
|
constructor(capacity) {
|
|
8
12
|
this.head = 0;
|
|
@@ -45,16 +49,29 @@ var CircularBuffer = class {
|
|
|
45
49
|
}
|
|
46
50
|
};
|
|
47
51
|
function resolveCurve(curveDef) {
|
|
52
|
+
const period = curveDef.period ?? TWO_PI;
|
|
53
|
+
if (!Number.isFinite(period) || period <= 0) {
|
|
54
|
+
throw new RangeError(`[sarmal] period must be a positive finite number, got ${period}`);
|
|
55
|
+
}
|
|
56
|
+
const speed = curveDef.speed ?? 1;
|
|
57
|
+
if (!Number.isFinite(speed)) {
|
|
58
|
+
throw new RangeError(`[sarmal] speed must be a finite number, got ${speed}`);
|
|
59
|
+
}
|
|
48
60
|
return {
|
|
49
61
|
name: curveDef.name,
|
|
50
62
|
fn: curveDef.fn,
|
|
51
|
-
period
|
|
52
|
-
speed
|
|
63
|
+
period,
|
|
64
|
+
speed,
|
|
53
65
|
skeleton: curveDef.skeleton,
|
|
54
|
-
skeletonFn: curveDef.skeletonFn
|
|
66
|
+
skeletonFn: curveDef.skeletonFn
|
|
55
67
|
};
|
|
56
68
|
}
|
|
57
69
|
function createEngine(curveDef, trailLength = 120) {
|
|
70
|
+
if (!Number.isFinite(trailLength) || trailLength <= 0) {
|
|
71
|
+
throw new RangeError(
|
|
72
|
+
`[sarmal] trailLength must be a positive finite number, got ${trailLength}`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
58
75
|
let curve = resolveCurve(curveDef);
|
|
59
76
|
const trail = new CircularBuffer(trailLength);
|
|
60
77
|
let t = 0;
|
|
@@ -67,21 +84,25 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
67
84
|
return c.skeletonFn(sampleT);
|
|
68
85
|
}
|
|
69
86
|
if (c.skeleton === "live") {
|
|
70
|
-
return c.fn(sampleT, actualTime,
|
|
87
|
+
return c.fn(sampleT, actualTime, EMPTY_PARAMS);
|
|
71
88
|
}
|
|
72
|
-
return c.fn(sampleT, 0,
|
|
89
|
+
return c.fn(sampleT, 0, EMPTY_PARAMS);
|
|
73
90
|
}
|
|
74
91
|
return {
|
|
75
92
|
tick(deltaTime) {
|
|
76
|
-
|
|
93
|
+
let effectiveSpeed = curve.speed;
|
|
94
|
+
if (morphCurveB !== null && _morphAlpha !== null) {
|
|
95
|
+
effectiveSpeed = lerp(curve.speed, morphCurveB.speed, _morphAlpha);
|
|
96
|
+
}
|
|
97
|
+
t = (t + effectiveSpeed * deltaTime) % curve.period;
|
|
77
98
|
actualTime += deltaTime;
|
|
78
99
|
if (morphCurveB !== null && _morphAlpha !== null) {
|
|
79
|
-
const a = curve.fn(t, actualTime,
|
|
80
|
-
const tB = _morphStrategy === "normalized" ?
|
|
81
|
-
const b = morphCurveB.fn(tB, actualTime,
|
|
100
|
+
const a = curve.fn(t, actualTime, EMPTY_PARAMS);
|
|
101
|
+
const tB = _morphStrategy === "normalized" ? t / curve.period * morphCurveB.period : t;
|
|
102
|
+
const b = morphCurveB.fn(tB, actualTime, EMPTY_PARAMS);
|
|
82
103
|
trail.push(a.x + (b.x - a.x) * _morphAlpha, a.y + (b.y - a.y) * _morphAlpha);
|
|
83
104
|
} else {
|
|
84
|
-
const point = curve.fn(t, actualTime,
|
|
105
|
+
const point = curve.fn(t, actualTime, EMPTY_PARAMS);
|
|
85
106
|
trail.push(point.x, point.y);
|
|
86
107
|
}
|
|
87
108
|
return trail.toArray();
|
|
@@ -101,14 +122,14 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
101
122
|
trail.clear();
|
|
102
123
|
},
|
|
103
124
|
seek(newT, { clearTrail = false } = {}) {
|
|
104
|
-
t = (
|
|
125
|
+
t = (newT % curve.period + curve.period) % curve.period;
|
|
105
126
|
if (clearTrail) {
|
|
106
127
|
trail.clear();
|
|
107
128
|
}
|
|
108
129
|
},
|
|
109
130
|
seekWithTrail(targetT, { wrap = false, step = curve.period / trailLength } = {}) {
|
|
110
131
|
const advance = curve.speed * step;
|
|
111
|
-
const target = (
|
|
132
|
+
const target = (targetT % curve.period + curve.period) % curve.period;
|
|
112
133
|
const targetTime = target / curve.speed;
|
|
113
134
|
t = target;
|
|
114
135
|
actualTime = targetTime;
|
|
@@ -117,9 +138,9 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
117
138
|
const count = wrap ? trailLength : Math.min(trailLength, pointsFromStart);
|
|
118
139
|
for (let i = count - 1; i >= 0; i--) {
|
|
119
140
|
const sampleT = target - i * advance;
|
|
120
|
-
const wrappedT = sampleT
|
|
141
|
+
const wrappedT = (sampleT % curve.period + curve.period) % curve.period;
|
|
121
142
|
const time = targetTime - i * step;
|
|
122
|
-
const point = curve.fn(wrappedT, time,
|
|
143
|
+
const point = curve.fn(wrappedT, time, EMPTY_PARAMS);
|
|
123
144
|
trail.push(point.x, point.y);
|
|
124
145
|
}
|
|
125
146
|
},
|
|
@@ -134,16 +155,13 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
134
155
|
...frozenB,
|
|
135
156
|
fn: (sampleT, time, params) => {
|
|
136
157
|
const a = frozenA.fn(sampleT, time, params);
|
|
137
|
-
const tB =
|
|
138
|
-
frozenStrategy === "normalized"
|
|
139
|
-
? (sampleT / frozenA.period) * frozenB.period
|
|
140
|
-
: sampleT;
|
|
158
|
+
const tB = frozenStrategy === "normalized" ? sampleT / frozenA.period * frozenB.period : sampleT;
|
|
141
159
|
const b = frozenB.fn(tB, time, params);
|
|
142
160
|
return {
|
|
143
161
|
x: a.x + (b.x - a.x) * frozenAlpha,
|
|
144
|
-
y: a.y + (b.y - a.y) * frozenAlpha
|
|
162
|
+
y: a.y + (b.y - a.y) * frozenAlpha
|
|
145
163
|
};
|
|
146
|
-
}
|
|
164
|
+
}
|
|
147
165
|
};
|
|
148
166
|
}
|
|
149
167
|
_morphStrategy = strategy;
|
|
@@ -156,7 +174,7 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
156
174
|
completeMorph() {
|
|
157
175
|
if (morphCurveB !== null) {
|
|
158
176
|
if (_morphStrategy === "normalized" && curve.period !== morphCurveB.period) {
|
|
159
|
-
t =
|
|
177
|
+
t = t / curve.period * morphCurveB.period;
|
|
160
178
|
}
|
|
161
179
|
curve = morphCurveB;
|
|
162
180
|
}
|
|
@@ -168,46 +186,132 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
168
186
|
const points = new Array(steps);
|
|
169
187
|
if (morphCurveB !== null && _morphAlpha !== null) {
|
|
170
188
|
for (let i = 0; i < steps; i++) {
|
|
171
|
-
const sampleT =
|
|
189
|
+
const sampleT = i / (steps - 1) * curve.period;
|
|
172
190
|
const a = sampleSkeleton(curve, sampleT);
|
|
173
|
-
const tB =
|
|
174
|
-
_morphStrategy === "normalized"
|
|
175
|
-
? (sampleT / curve.period) * morphCurveB.period
|
|
176
|
-
: sampleT;
|
|
191
|
+
const tB = _morphStrategy === "normalized" ? sampleT / curve.period * morphCurveB.period : sampleT;
|
|
177
192
|
const b = sampleSkeleton(morphCurveB, tB);
|
|
178
193
|
points[i] = {
|
|
179
194
|
x: a.x + (b.x - a.x) * _morphAlpha,
|
|
180
|
-
y: a.y + (b.y - a.y) * _morphAlpha
|
|
195
|
+
y: a.y + (b.y - a.y) * _morphAlpha
|
|
181
196
|
};
|
|
182
197
|
}
|
|
183
198
|
return points;
|
|
184
199
|
}
|
|
185
200
|
for (let i = 0; i < steps; i++) {
|
|
186
|
-
const sampleT =
|
|
201
|
+
const sampleT = i / (steps - 1) * curve.period;
|
|
187
202
|
points[i] = sampleSkeleton(curve, sampleT);
|
|
188
203
|
}
|
|
189
204
|
return points;
|
|
190
|
-
}
|
|
205
|
+
}
|
|
191
206
|
};
|
|
192
207
|
}
|
|
193
208
|
|
|
194
|
-
// src/renderer.ts
|
|
209
|
+
// src/renderer-shared.ts
|
|
195
210
|
var DEFAULT_MORPH_DURATION_MS = 300;
|
|
196
|
-
var DEFAULT_HEAD_RADIUS = 4;
|
|
197
|
-
var DEFAULT_SKELETON_COLOR = "#ffffff";
|
|
198
211
|
var DEFAULT_SKELETON_OPACITY = 0.15;
|
|
199
212
|
var FIT_PADDING = 0.1;
|
|
200
213
|
var TRAIL_FADE_CURVE = 1.5;
|
|
201
214
|
var TRAIL_MAX_OPACITY = 0.88;
|
|
202
215
|
var TRAIL_MIN_WIDTH = 0.5;
|
|
203
216
|
var TRAIL_MAX_WIDTH = 2.5;
|
|
217
|
+
function computeTangent(trail, i) {
|
|
218
|
+
const count = trail.length;
|
|
219
|
+
if (count < 2) {
|
|
220
|
+
return { x: 1, y: 0 };
|
|
221
|
+
}
|
|
222
|
+
if (i === 0) {
|
|
223
|
+
const dx2 = trail[1].x - trail[0].x;
|
|
224
|
+
const dy2 = trail[1].y - trail[0].y;
|
|
225
|
+
const len2 = Math.sqrt(dx2 * dx2 + dy2 * dy2) || 1;
|
|
226
|
+
return { x: dx2 / len2, y: dy2 / len2 };
|
|
227
|
+
}
|
|
228
|
+
if (i === count - 1) {
|
|
229
|
+
const dx2 = trail[count - 1].x - trail[count - 2].x;
|
|
230
|
+
const dy2 = trail[count - 1].y - trail[count - 2].y;
|
|
231
|
+
const len2 = Math.sqrt(dx2 * dx2 + dy2 * dy2) || 1;
|
|
232
|
+
return { x: dx2 / len2, y: dy2 / len2 };
|
|
233
|
+
}
|
|
234
|
+
const dx = trail[i + 1].x - trail[i - 1].x;
|
|
235
|
+
const dy = trail[i + 1].y - trail[i - 1].y;
|
|
236
|
+
const len = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
237
|
+
return { x: dx / len, y: dy / len };
|
|
238
|
+
}
|
|
239
|
+
function computeNormal(trail, i) {
|
|
240
|
+
const tangent = computeTangent(trail, i);
|
|
241
|
+
return { x: -tangent.y, y: tangent.x };
|
|
242
|
+
}
|
|
243
|
+
function computeTrailQuad(trail, i, trailCount, toX, toY) {
|
|
244
|
+
const progress = i / (trailCount - 1);
|
|
245
|
+
const nextProgress = (i + 1) / (trailCount - 1);
|
|
246
|
+
const opacity = Math.pow(progress, TRAIL_FADE_CURVE) * TRAIL_MAX_OPACITY;
|
|
247
|
+
const w0 = (TRAIL_MIN_WIDTH + progress * (TRAIL_MAX_WIDTH - TRAIL_MIN_WIDTH)) / 2;
|
|
248
|
+
const w1 = (TRAIL_MIN_WIDTH + nextProgress * (TRAIL_MAX_WIDTH - TRAIL_MIN_WIDTH)) / 2;
|
|
249
|
+
const curr = trail[i];
|
|
250
|
+
const next = trail[i + 1];
|
|
251
|
+
const n0 = computeNormal(trail, i);
|
|
252
|
+
const n1 = computeNormal(trail, i + 1);
|
|
253
|
+
const cx = toX(curr);
|
|
254
|
+
const cy = toY(curr);
|
|
255
|
+
const nx = toX(next);
|
|
256
|
+
const ny = toY(next);
|
|
257
|
+
return {
|
|
258
|
+
l0x: cx + n0.x * w0,
|
|
259
|
+
l0y: cy + n0.y * w0,
|
|
260
|
+
r0x: cx - n0.x * w0,
|
|
261
|
+
r0y: cy - n0.y * w0,
|
|
262
|
+
l1x: nx + n1.x * w1,
|
|
263
|
+
l1y: ny + n1.y * w1,
|
|
264
|
+
r1x: nx - n1.x * w1,
|
|
265
|
+
r1y: ny - n1.y * w1,
|
|
266
|
+
opacity,
|
|
267
|
+
progress
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
function computeBoundaries(pts, logicalWidth, logicalHeight) {
|
|
271
|
+
if (pts.length === 0) return null;
|
|
272
|
+
const first = pts[0];
|
|
273
|
+
let minX = first.x, maxX = first.x, minY = first.y, maxY = first.y;
|
|
274
|
+
for (const p of pts) {
|
|
275
|
+
if (p.x < minX) {
|
|
276
|
+
minX = p.x;
|
|
277
|
+
}
|
|
278
|
+
if (p.x > maxX) {
|
|
279
|
+
maxX = p.x;
|
|
280
|
+
}
|
|
281
|
+
if (p.y < minY) {
|
|
282
|
+
minY = p.y;
|
|
283
|
+
}
|
|
284
|
+
if (p.y > maxY) {
|
|
285
|
+
maxY = p.y;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const w = maxX - minX;
|
|
289
|
+
const h = maxY - minY;
|
|
290
|
+
if (w === 0 && h === 0) {
|
|
291
|
+
throw new Error(
|
|
292
|
+
"[sarmal] Degenerate curve: all skeleton points are identical. Check that your curve fn returns distinct points for different values of t."
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
const scaleX = logicalWidth / (w * (1 + FIT_PADDING * 2));
|
|
296
|
+
const scaleY = logicalHeight / (h * (1 + FIT_PADDING * 2));
|
|
297
|
+
const scale = Math.min(scaleX, scaleY);
|
|
298
|
+
return {
|
|
299
|
+
scale,
|
|
300
|
+
offsetX: (logicalWidth - w * scale) / 2 - minX * scale,
|
|
301
|
+
offsetY: (logicalHeight - h * scale) / 2 - minY * scale
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// src/renderer.ts
|
|
306
|
+
var DEFAULT_HEAD_RADIUS = 4;
|
|
307
|
+
var DEFAULT_SKELETON_COLOR = "#ffffff";
|
|
204
308
|
var GRADIENT = {
|
|
205
309
|
bard: ["#a855f7", "#3b82f6", "#14b8a6", "#ec4899"],
|
|
206
310
|
sunset: ["#f97316", "#dc2626", "#9333ea", "#f472b6"],
|
|
207
311
|
ocean: ["#1e3a8a", "#06b6d4", "#22d3ee", "#e0f2fe"],
|
|
208
312
|
ice: ["#1e3a8a", "#67e8f9"],
|
|
209
313
|
fire: ["#7f1d1d", "#fbbf24"],
|
|
210
|
-
forest: ["#14532d", "#86efac"]
|
|
314
|
+
forest: ["#14532d", "#86efac"]
|
|
211
315
|
};
|
|
212
316
|
var PRESETS = {
|
|
213
317
|
bard: GRADIENT.bard,
|
|
@@ -215,16 +319,16 @@ var PRESETS = {
|
|
|
215
319
|
ocean: GRADIENT.ocean,
|
|
216
320
|
ice: GRADIENT.ice,
|
|
217
321
|
fire: GRADIENT.fire,
|
|
218
|
-
forest: GRADIENT.forest
|
|
322
|
+
forest: GRADIENT.forest
|
|
219
323
|
};
|
|
220
324
|
function hexToRgb(hex) {
|
|
221
325
|
const n = parseInt(hex.slice(1), 16);
|
|
222
|
-
return { r: n >> 16, g:
|
|
326
|
+
return { r: n >> 16, g: n >> 8 & 255, b: n & 255 };
|
|
223
327
|
}
|
|
224
328
|
var lerpRgb = (a, b, t) => ({
|
|
225
329
|
r: Math.round(a.r + (b.r - a.r) * t),
|
|
226
330
|
g: Math.round(a.g + (b.g - a.g) * t),
|
|
227
|
-
b: Math.round(a.b + (b.b - a.b) * t)
|
|
331
|
+
b: Math.round(a.b + (b.b - a.b) * t)
|
|
228
332
|
});
|
|
229
333
|
function getPaletteColor(palette, position, timeOffset = 0) {
|
|
230
334
|
if (palette.length === 0) return { r: 255, g: 255, b: 255 };
|
|
@@ -244,33 +348,7 @@ function resolvePalette(palette, trailStyle) {
|
|
|
244
348
|
}
|
|
245
349
|
function hexToRgbComponents(hex) {
|
|
246
350
|
const n = parseInt(hex.slice(1), 16);
|
|
247
|
-
return `${n >> 16},${
|
|
248
|
-
}
|
|
249
|
-
function computeTangent(trail, i) {
|
|
250
|
-
const count = trail.length;
|
|
251
|
-
if (count < 2) {
|
|
252
|
-
return { x: 1, y: 0 };
|
|
253
|
-
}
|
|
254
|
-
if (i === 0) {
|
|
255
|
-
const dx2 = trail[1].x - trail[0].x;
|
|
256
|
-
const dy2 = trail[1].y - trail[0].y;
|
|
257
|
-
const len2 = Math.sqrt(dx2 * dx2 + dy2 * dy2) || 1;
|
|
258
|
-
return { x: dx2 / len2, y: dy2 / len2 };
|
|
259
|
-
}
|
|
260
|
-
if (i === count - 1) {
|
|
261
|
-
const dx2 = trail[count - 1].x - trail[count - 2].x;
|
|
262
|
-
const dy2 = trail[count - 1].y - trail[count - 2].y;
|
|
263
|
-
const len2 = Math.sqrt(dx2 * dx2 + dy2 * dy2) || 1;
|
|
264
|
-
return { x: dx2 / len2, y: dy2 / len2 };
|
|
265
|
-
}
|
|
266
|
-
const dx = trail[i + 1].x - trail[i - 1].x;
|
|
267
|
-
const dy = trail[i + 1].y - trail[i - 1].y;
|
|
268
|
-
const len = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
269
|
-
return { x: dx / len, y: dy / len };
|
|
270
|
-
}
|
|
271
|
-
function computeNormal(trail, i) {
|
|
272
|
-
const tangent = computeTangent(trail, i);
|
|
273
|
-
return { x: -tangent.y, y: tangent.x };
|
|
351
|
+
return `${n >> 16},${n >> 8 & 255},${n & 255}`;
|
|
274
352
|
}
|
|
275
353
|
function applyDprSizing(target, logicalWidth, logicalHeight, dpr) {
|
|
276
354
|
target.style.width = `${logicalWidth}px`;
|
|
@@ -289,7 +367,7 @@ function createRenderer(options) {
|
|
|
289
367
|
skeletonColor: options.skeletonColor ?? DEFAULT_SKELETON_COLOR,
|
|
290
368
|
trailColor: options.trailColor ?? "#ffffff",
|
|
291
369
|
headColor: options.headColor ?? "#ffffff",
|
|
292
|
-
headRadius: options.headRadius ?? DEFAULT_HEAD_RADIUS
|
|
370
|
+
headRadius: options.headRadius ?? DEFAULT_HEAD_RADIUS
|
|
293
371
|
};
|
|
294
372
|
const trailStyle = options.trailStyle ?? "default";
|
|
295
373
|
const palette = resolvePalette(options.palette, trailStyle);
|
|
@@ -319,34 +397,8 @@ function createRenderer(options) {
|
|
|
319
397
|
let morphDurationMs = DEFAULT_MORPH_DURATION_MS;
|
|
320
398
|
let morphAlpha = 0;
|
|
321
399
|
let gradientAnimTime = 0;
|
|
322
|
-
function computeBoundaries(pts) {
|
|
323
|
-
if (pts.length === 0) return null;
|
|
324
|
-
const first = pts[0];
|
|
325
|
-
let minX = first.x,
|
|
326
|
-
maxX = first.x,
|
|
327
|
-
minY = first.y,
|
|
328
|
-
maxY = first.y;
|
|
329
|
-
for (const p of pts) {
|
|
330
|
-
if (p.x < minX) minX = p.x;
|
|
331
|
-
if (p.x > maxX) maxX = p.x;
|
|
332
|
-
if (p.y < minY) minY = p.y;
|
|
333
|
-
if (p.y > maxY) maxY = p.y;
|
|
334
|
-
}
|
|
335
|
-
const width = maxX - minX;
|
|
336
|
-
const height = maxY - minY;
|
|
337
|
-
const scaleX = logicalWidth / (width * (1 + FIT_PADDING * 2));
|
|
338
|
-
const scaleY = logicalHeight / (height * (1 + FIT_PADDING * 2));
|
|
339
|
-
const s = Math.min(scaleX, scaleY);
|
|
340
|
-
const boundsWidth = width * s;
|
|
341
|
-
const boundsHeight = height * s;
|
|
342
|
-
return {
|
|
343
|
-
scale: s,
|
|
344
|
-
offsetX: (logicalWidth - boundsWidth) / 2 - minX * s,
|
|
345
|
-
offsetY: (logicalHeight - boundsHeight) / 2 - minY * s,
|
|
346
|
-
};
|
|
347
|
-
}
|
|
348
400
|
function calculateBoundaries() {
|
|
349
|
-
const b = computeBoundaries(skeleton);
|
|
401
|
+
const b = computeBoundaries(skeleton, logicalWidth, logicalHeight);
|
|
350
402
|
if (b) {
|
|
351
403
|
scale = b.scale;
|
|
352
404
|
offsetX = b.offsetX;
|
|
@@ -410,32 +462,22 @@ function createRenderer(options) {
|
|
|
410
462
|
if (trailCount < 2) {
|
|
411
463
|
return;
|
|
412
464
|
}
|
|
465
|
+
const toX = (p) => p.x * scale + offsetX;
|
|
466
|
+
const toY = (p) => p.y * scale + offsetY;
|
|
413
467
|
for (let i = 0; i < trailCount - 1; i++) {
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
const n0 = computeNormal(trail, i);
|
|
422
|
-
const n1 = computeNormal(trail, i + 1);
|
|
423
|
-
const halfW0 = width / 2;
|
|
424
|
-
const halfW1 = nextWidth / 2;
|
|
425
|
-
const l0x = curr.x * scale + offsetX + n0.x * halfW0;
|
|
426
|
-
const l0y = curr.y * scale + offsetY + n0.y * halfW0;
|
|
427
|
-
const r0x = curr.x * scale + offsetX - n0.x * halfW0;
|
|
428
|
-
const r0y = curr.y * scale + offsetY - n0.y * halfW0;
|
|
429
|
-
const l1x = next.x * scale + offsetX + n1.x * halfW1;
|
|
430
|
-
const l1y = next.y * scale + offsetY + n1.y * halfW1;
|
|
431
|
-
const r1x = next.x * scale + offsetX - n1.x * halfW1;
|
|
432
|
-
const r1y = next.y * scale + offsetY - n1.y * halfW1;
|
|
468
|
+
const { l0x, l0y, r0x, r0y, l1x, l1y, r1x, r1y, opacity, progress } = computeTrailQuad(
|
|
469
|
+
trail,
|
|
470
|
+
i,
|
|
471
|
+
trailCount,
|
|
472
|
+
toX,
|
|
473
|
+
toY
|
|
474
|
+
);
|
|
433
475
|
if (trailStyle === "default") {
|
|
434
|
-
ctx.fillStyle = `rgba(${trailRgb},${
|
|
476
|
+
ctx.fillStyle = `rgba(${trailRgb},${opacity})`;
|
|
435
477
|
} else {
|
|
436
478
|
const timeOffset = trailStyle === "gradient-animated" ? gradientAnimTime * 5e-4 : 0;
|
|
437
479
|
const color = getPaletteColor(palette, progress, timeOffset);
|
|
438
|
-
ctx.fillStyle = `rgba(${color.r},${color.g},${color.b},${
|
|
480
|
+
ctx.fillStyle = `rgba(${color.r},${color.g},${color.b},${opacity})`;
|
|
439
481
|
}
|
|
440
482
|
ctx.beginPath();
|
|
441
483
|
ctx.moveTo(l0x, l0y);
|
|
@@ -468,7 +510,7 @@ function createRenderer(options) {
|
|
|
468
510
|
morphAlpha = Math.min(1, morphAlpha + deltaTime / (morphDurationMs / 1e3));
|
|
469
511
|
engine.setMorphAlpha(morphAlpha);
|
|
470
512
|
const interpolatedSkeleton = engine.getSarmalSkeleton();
|
|
471
|
-
const bounds = computeBoundaries(interpolatedSkeleton);
|
|
513
|
+
const bounds = computeBoundaries(interpolatedSkeleton, logicalWidth, logicalHeight);
|
|
472
514
|
if (bounds) {
|
|
473
515
|
scale = bounds.scale;
|
|
474
516
|
offsetX = bounds.offsetX;
|
|
@@ -548,29 +590,26 @@ function createRenderer(options) {
|
|
|
548
590
|
return new Promise((resolve) => {
|
|
549
591
|
morphResolve = resolve;
|
|
550
592
|
});
|
|
551
|
-
}
|
|
593
|
+
}
|
|
552
594
|
};
|
|
553
595
|
}
|
|
554
596
|
|
|
555
597
|
// src/curves/artemis2.ts
|
|
556
598
|
var TWO_PI2 = Math.PI * 2;
|
|
557
599
|
function artemis2Fn(t, _time, _params) {
|
|
558
|
-
const a = 0.35,
|
|
559
|
-
|
|
560
|
-
ox = 0.175;
|
|
561
|
-
const s = Math.sin(t),
|
|
562
|
-
c = Math.cos(t);
|
|
600
|
+
const a = 0.35, b = 0.15, ox = 0.175;
|
|
601
|
+
const s = Math.sin(t), c = Math.cos(t);
|
|
563
602
|
const denom = 1 + s * s;
|
|
564
603
|
return {
|
|
565
|
-
x:
|
|
566
|
-
y:
|
|
604
|
+
x: c * (1 + a * c) / denom - ox,
|
|
605
|
+
y: s * c * (1 + b * c) / denom
|
|
567
606
|
};
|
|
568
607
|
}
|
|
569
608
|
var artemis2 = {
|
|
570
609
|
name: "Artemis II",
|
|
571
610
|
fn: artemis2Fn,
|
|
572
611
|
period: TWO_PI2,
|
|
573
|
-
speed: 0.7
|
|
612
|
+
speed: 0.7
|
|
574
613
|
};
|
|
575
614
|
|
|
576
615
|
// src/curves/astroid.ts
|
|
@@ -580,14 +619,14 @@ function astroidFn(t, _time, _params) {
|
|
|
580
619
|
const s = Math.sin(t);
|
|
581
620
|
return {
|
|
582
621
|
x: c * c * c,
|
|
583
|
-
y: s * s * s
|
|
622
|
+
y: s * s * s
|
|
584
623
|
};
|
|
585
624
|
}
|
|
586
625
|
var astroid = {
|
|
587
626
|
name: "Astroid",
|
|
588
627
|
fn: astroidFn,
|
|
589
628
|
period: TWO_PI3,
|
|
590
|
-
speed: 1.1
|
|
629
|
+
speed: 1.1
|
|
591
630
|
};
|
|
592
631
|
|
|
593
632
|
// src/curves/deltoid.ts
|
|
@@ -595,14 +634,14 @@ var TWO_PI4 = Math.PI * 2;
|
|
|
595
634
|
function deltoidFn(t, _time, _params) {
|
|
596
635
|
return {
|
|
597
636
|
x: 2 * Math.cos(t) + Math.cos(2 * t),
|
|
598
|
-
y: 2 * Math.sin(t) - Math.sin(2 * t)
|
|
637
|
+
y: 2 * Math.sin(t) - Math.sin(2 * t)
|
|
599
638
|
};
|
|
600
639
|
}
|
|
601
640
|
var deltoid = {
|
|
602
641
|
name: "Deltoid",
|
|
603
642
|
fn: deltoidFn,
|
|
604
643
|
period: TWO_PI4,
|
|
605
|
-
speed: 0.9
|
|
644
|
+
speed: 0.9
|
|
606
645
|
};
|
|
607
646
|
|
|
608
647
|
// src/curves/epicycloid3.ts
|
|
@@ -610,14 +649,14 @@ var TWO_PI5 = Math.PI * 2;
|
|
|
610
649
|
function epicycloid3Fn(t, _time, _params) {
|
|
611
650
|
return {
|
|
612
651
|
x: 4 * Math.cos(t) - Math.cos(4 * t),
|
|
613
|
-
y: 4 * Math.sin(t) - Math.sin(4 * t)
|
|
652
|
+
y: 4 * Math.sin(t) - Math.sin(4 * t)
|
|
614
653
|
};
|
|
615
654
|
}
|
|
616
655
|
var epicycloid3 = {
|
|
617
656
|
name: "Epicycloid (n=3)",
|
|
618
657
|
fn: epicycloid3Fn,
|
|
619
658
|
period: TWO_PI5,
|
|
620
|
-
speed: 0.75
|
|
659
|
+
speed: 0.75
|
|
621
660
|
};
|
|
622
661
|
|
|
623
662
|
// src/curves/epitrochoid7.ts
|
|
@@ -626,14 +665,14 @@ function epitrochoid7Fn(t, _time, _params) {
|
|
|
626
665
|
const d = 1 + 0.55 * Math.sin(t * 0.5);
|
|
627
666
|
return {
|
|
628
667
|
x: 7 * Math.cos(t) - d * Math.cos(7 * t),
|
|
629
|
-
y: 7 * Math.sin(t) - d * Math.sin(7 * t)
|
|
668
|
+
y: 7 * Math.sin(t) - d * Math.sin(7 * t)
|
|
630
669
|
};
|
|
631
670
|
}
|
|
632
671
|
function epitrochoid7SkeletonFn(t) {
|
|
633
672
|
const d = 1.275;
|
|
634
673
|
return {
|
|
635
674
|
x: 7 * Math.cos(t) - d * Math.cos(7 * t),
|
|
636
|
-
y: 7 * Math.sin(t) - d * Math.sin(7 * t)
|
|
675
|
+
y: 7 * Math.sin(t) - d * Math.sin(7 * t)
|
|
637
676
|
};
|
|
638
677
|
}
|
|
639
678
|
var epitrochoid7 = {
|
|
@@ -641,7 +680,7 @@ var epitrochoid7 = {
|
|
|
641
680
|
fn: epitrochoid7Fn,
|
|
642
681
|
period: TWO_PI6,
|
|
643
682
|
speed: 1.4,
|
|
644
|
-
skeletonFn: epitrochoid7SkeletonFn
|
|
683
|
+
skeletonFn: epitrochoid7SkeletonFn
|
|
645
684
|
};
|
|
646
685
|
|
|
647
686
|
// src/curves/lissajous32.ts
|
|
@@ -650,7 +689,7 @@ function lissajous32Fn(t, time, _params) {
|
|
|
650
689
|
const phi = time * 0.45;
|
|
651
690
|
return {
|
|
652
691
|
x: Math.sin(3 * t + phi),
|
|
653
|
-
y: Math.sin(2 * t)
|
|
692
|
+
y: Math.sin(2 * t)
|
|
654
693
|
};
|
|
655
694
|
}
|
|
656
695
|
var lissajous32 = {
|
|
@@ -658,7 +697,7 @@ var lissajous32 = {
|
|
|
658
697
|
fn: lissajous32Fn,
|
|
659
698
|
period: TWO_PI7,
|
|
660
699
|
speed: 2,
|
|
661
|
-
skeleton: "live"
|
|
700
|
+
skeleton: "live"
|
|
662
701
|
};
|
|
663
702
|
|
|
664
703
|
// src/curves/lissajous43.ts
|
|
@@ -667,7 +706,7 @@ function lissajous43Fn(t, time, _params) {
|
|
|
667
706
|
const phi = time * 0.38;
|
|
668
707
|
return {
|
|
669
708
|
x: Math.sin(4 * t + phi),
|
|
670
|
-
y: Math.sin(3 * t)
|
|
709
|
+
y: Math.sin(3 * t)
|
|
671
710
|
};
|
|
672
711
|
}
|
|
673
712
|
var lissajous43 = {
|
|
@@ -675,18 +714,17 @@ var lissajous43 = {
|
|
|
675
714
|
fn: lissajous43Fn,
|
|
676
715
|
period: TWO_PI8,
|
|
677
716
|
speed: 1.8,
|
|
678
|
-
skeleton: "live"
|
|
717
|
+
skeleton: "live"
|
|
679
718
|
};
|
|
680
719
|
|
|
681
720
|
// src/curves/lame.ts
|
|
682
721
|
var TWO_PI9 = Math.PI * 2;
|
|
683
722
|
function lameFn(t, time, _params) {
|
|
684
723
|
const p = 1.75 + 1.25 * Math.sin(time * 0.48);
|
|
685
|
-
const c = Math.cos(t),
|
|
686
|
-
s = Math.sin(t);
|
|
724
|
+
const c = Math.cos(t), s = Math.sin(t);
|
|
687
725
|
return {
|
|
688
726
|
x: Math.sign(c) * Math.pow(Math.abs(c), p),
|
|
689
|
-
y: Math.sign(s) * Math.pow(Math.abs(s), p)
|
|
727
|
+
y: Math.sign(s) * Math.pow(Math.abs(s), p)
|
|
690
728
|
};
|
|
691
729
|
}
|
|
692
730
|
var lame = {
|
|
@@ -694,7 +732,7 @@ var lame = {
|
|
|
694
732
|
fn: lameFn,
|
|
695
733
|
period: TWO_PI9,
|
|
696
734
|
speed: 1,
|
|
697
|
-
skeleton: "live"
|
|
735
|
+
skeleton: "live"
|
|
698
736
|
};
|
|
699
737
|
|
|
700
738
|
// src/curves/rose3.ts
|
|
@@ -703,14 +741,14 @@ function rose3Fn(t, _time, _params) {
|
|
|
703
741
|
const r = Math.cos(3 * t);
|
|
704
742
|
return {
|
|
705
743
|
x: r * Math.cos(t),
|
|
706
|
-
y: r * Math.sin(t)
|
|
744
|
+
y: r * Math.sin(t)
|
|
707
745
|
};
|
|
708
746
|
}
|
|
709
747
|
var rose3 = {
|
|
710
748
|
name: "Rose (n=3)",
|
|
711
749
|
fn: rose3Fn,
|
|
712
750
|
period: TWO_PI10,
|
|
713
|
-
speed: 1.15
|
|
751
|
+
speed: 1.15
|
|
714
752
|
};
|
|
715
753
|
|
|
716
754
|
// src/curves/rose5.ts
|
|
@@ -719,14 +757,14 @@ function rose5Fn(t, _time, _params) {
|
|
|
719
757
|
const r = Math.cos(5 * t);
|
|
720
758
|
return {
|
|
721
759
|
x: r * Math.cos(t),
|
|
722
|
-
y: r * Math.sin(t)
|
|
760
|
+
y: r * Math.sin(t)
|
|
723
761
|
};
|
|
724
762
|
}
|
|
725
763
|
var rose5 = {
|
|
726
764
|
name: "Rose (n=5)",
|
|
727
765
|
fn: rose5Fn,
|
|
728
766
|
period: TWO_PI11,
|
|
729
|
-
speed: 1
|
|
767
|
+
speed: 1
|
|
730
768
|
};
|
|
731
769
|
|
|
732
770
|
// src/curves/index.ts
|
|
@@ -740,7 +778,7 @@ var curves = {
|
|
|
740
778
|
lissajous32,
|
|
741
779
|
lissajous43,
|
|
742
780
|
epicycloid3,
|
|
743
|
-
lame
|
|
781
|
+
lame
|
|
744
782
|
};
|
|
745
783
|
|
|
746
784
|
// src/index.ts
|
|
@@ -757,7 +795,8 @@ function parsePalette(value) {
|
|
|
757
795
|
if (Array.isArray(parsed)) {
|
|
758
796
|
return parsed;
|
|
759
797
|
}
|
|
760
|
-
} catch {
|
|
798
|
+
} catch {
|
|
799
|
+
}
|
|
761
800
|
return value;
|
|
762
801
|
}
|
|
763
802
|
function init() {
|
|
@@ -765,22 +804,22 @@ function init() {
|
|
|
765
804
|
canvases.forEach((canvas) => {
|
|
766
805
|
const curveName = canvas.getAttribute("data-sarmal");
|
|
767
806
|
if (curveName == null) {
|
|
768
|
-
return console.warn("[sarmal] curveName
|
|
807
|
+
return console.warn("[sarmal] curveName is required");
|
|
769
808
|
}
|
|
770
809
|
const curveDef = curves[curveName];
|
|
771
810
|
if (!curveDef) {
|
|
772
811
|
return console.error(`[sarmal] "${curveName}" is not a valid curve name`);
|
|
773
812
|
}
|
|
774
813
|
const sarmal = createSarmal(canvas, curveDef, {
|
|
775
|
-
...
|
|
776
|
-
...
|
|
777
|
-
...
|
|
778
|
-
...
|
|
779
|
-
...
|
|
780
|
-
...
|
|
781
|
-
trailStyle: canvas.dataset.trailStyle
|
|
782
|
-
}
|
|
783
|
-
...
|
|
814
|
+
...canvas.dataset.trailColor && { trailColor: canvas.dataset.trailColor },
|
|
815
|
+
...canvas.dataset.skeletonColor && { skeletonColor: canvas.dataset.skeletonColor },
|
|
816
|
+
...canvas.dataset.headColor && { headColor: canvas.dataset.headColor },
|
|
817
|
+
...canvas.dataset.headRadius && { headRadius: parseFloat(canvas.dataset.headRadius) },
|
|
818
|
+
...canvas.dataset.trailLength && { trailLength: parseInt(canvas.dataset.trailLength, 10) },
|
|
819
|
+
...canvas.dataset.trailStyle && {
|
|
820
|
+
trailStyle: canvas.dataset.trailStyle
|
|
821
|
+
},
|
|
822
|
+
...canvas.dataset.palette && { palette: parsePalette(canvas.dataset.palette) }
|
|
784
823
|
});
|
|
785
824
|
sarmal.start();
|
|
786
825
|
});
|
|
@@ -793,4 +832,4 @@ if (document.readyState === "loading") {
|
|
|
793
832
|
requestAnimationFrame(init);
|
|
794
833
|
}
|
|
795
834
|
//# sourceMappingURL=auto-init.cjs.map
|
|
796
|
-
//# sourceMappingURL=auto-init.cjs.map
|
|
835
|
+
//# sourceMappingURL=auto-init.cjs.map
|