@sarmal/core 0.23.0 → 0.25.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 +255 -175
- package/dist/auto-init.cjs.map +1 -1
- package/dist/auto-init.js +254 -174
- package/dist/auto-init.js.map +1 -1
- package/dist/curves/artemis2.cjs +82 -17
- package/dist/curves/artemis2.cjs.map +1 -1
- package/dist/curves/artemis2.d.cts +1 -5
- package/dist/curves/artemis2.d.ts +1 -5
- package/dist/curves/artemis2.js +81 -16
- package/dist/curves/artemis2.js.map +1 -1
- 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 +139 -84
- package/dist/curves/index.cjs.map +1 -1
- package/dist/curves/index.d.cts +29 -29
- package/dist/curves/index.d.ts +29 -29
- package/dist/curves/index.js +139 -100
- package/dist/curves/index.js.map +1 -1
- 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/curves/rose52.cjs +5 -5
- package/dist/curves/rose52.d.cts +1 -1
- package/dist/curves/rose52.d.ts +1 -1
- package/dist/curves/rose52.js +4 -4
- package/dist/curves/star.cjs +5 -8
- package/dist/curves/star.d.cts +1 -1
- package/dist/curves/star.d.ts +1 -1
- package/dist/curves/star.js +4 -7
- package/dist/curves/star4.cjs +5 -8
- package/dist/curves/star4.d.cts +1 -1
- package/dist/curves/star4.d.ts +1 -1
- package/dist/curves/star4.js +4 -7
- package/dist/curves/star7.cjs +5 -8
- package/dist/curves/star7.d.cts +1 -1
- package/dist/curves/star7.d.ts +1 -1
- package/dist/curves/star7.js +4 -7
- package/dist/index.cjs +244 -210
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +55 -78
- package/dist/index.d.ts +55 -78
- package/dist/index.js +243 -230
- package/dist/index.js.map +1 -1
- package/dist/types-BZpzgNau.d.cts +332 -0
- package/dist/types-BZpzgNau.d.ts +332 -0
- package/package.json +1 -1
- package/dist/types-C0b4MPtI.d.cts +0 -321
- package/dist/types-C0b4MPtI.d.ts +0 -321
package/dist/index.js
CHANGED
|
@@ -61,13 +61,13 @@ function resolveCurve(curveDef) {
|
|
|
61
61
|
period,
|
|
62
62
|
speed,
|
|
63
63
|
skeleton: curveDef.skeleton,
|
|
64
|
-
skeletonFn: curveDef.skeletonFn
|
|
64
|
+
skeletonFn: curveDef.skeletonFn
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
67
|
function createEngine(curveDef, trailLength = 120) {
|
|
68
68
|
if (!Number.isFinite(trailLength) || trailLength <= 0) {
|
|
69
69
|
throw new RangeError(
|
|
70
|
-
`[sarmal] trailLength must be a positive finite number, got ${trailLength}
|
|
70
|
+
`[sarmal] trailLength must be a positive finite number, got ${trailLength}`
|
|
71
71
|
);
|
|
72
72
|
}
|
|
73
73
|
let curve = resolveCurve(curveDef);
|
|
@@ -108,7 +108,7 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
108
108
|
actualTime += deltaTime;
|
|
109
109
|
if (morphCurveB !== null && _morphAlpha !== null) {
|
|
110
110
|
const a = curve.fn(t, actualTime, EMPTY_PARAMS);
|
|
111
|
-
const tB = _morphStrategy === "normalized" ?
|
|
111
|
+
const tB = _morphStrategy === "normalized" ? t / curve.period * morphCurveB.period : t;
|
|
112
112
|
const b = morphCurveB.fn(tB, actualTime, EMPTY_PARAMS);
|
|
113
113
|
trail.push(a.x + (b.x - a.x) * _morphAlpha, a.y + (b.y - a.y) * _morphAlpha);
|
|
114
114
|
} else {
|
|
@@ -135,14 +135,14 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
135
135
|
trail.clear();
|
|
136
136
|
},
|
|
137
137
|
jump(newT, { clearTrail = false } = {}) {
|
|
138
|
-
t = (
|
|
138
|
+
t = (newT % curve.period + curve.period) % curve.period;
|
|
139
139
|
if (clearTrail) {
|
|
140
140
|
trail.clear();
|
|
141
141
|
}
|
|
142
142
|
},
|
|
143
143
|
seek(targetT, { wrap = false, step = curve.period / trailLength } = {}) {
|
|
144
144
|
const advance = curve.speed * step;
|
|
145
|
-
const target = (
|
|
145
|
+
const target = (targetT % curve.period + curve.period) % curve.period;
|
|
146
146
|
const targetTime = target / curve.speed;
|
|
147
147
|
t = target;
|
|
148
148
|
actualTime = targetTime;
|
|
@@ -151,7 +151,7 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
151
151
|
const count = wrap ? trailLength : Math.min(trailLength, pointsFromStart);
|
|
152
152
|
for (let i = count - 1; i >= 0; i--) {
|
|
153
153
|
const sampleT = target - i * advance;
|
|
154
|
-
const wrappedT = (
|
|
154
|
+
const wrappedT = (sampleT % curve.period + curve.period) % curve.period;
|
|
155
155
|
const time = targetTime - i * step;
|
|
156
156
|
const point = curve.fn(wrappedT, time, EMPTY_PARAMS);
|
|
157
157
|
trail.push(point.x, point.y);
|
|
@@ -168,16 +168,13 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
168
168
|
...frozenB,
|
|
169
169
|
fn: (sampleT, time, params) => {
|
|
170
170
|
const a = frozenA.fn(sampleT, time, params);
|
|
171
|
-
const tB =
|
|
172
|
-
frozenStrategy === "normalized"
|
|
173
|
-
? (sampleT / frozenA.period) * frozenB.period
|
|
174
|
-
: sampleT;
|
|
171
|
+
const tB = frozenStrategy === "normalized" ? sampleT / frozenA.period * frozenB.period : sampleT;
|
|
175
172
|
const b = frozenB.fn(tB, time, params);
|
|
176
173
|
return {
|
|
177
174
|
x: a.x + (b.x - a.x) * frozenAlpha,
|
|
178
|
-
y: a.y + (b.y - a.y) * frozenAlpha
|
|
175
|
+
y: a.y + (b.y - a.y) * frozenAlpha
|
|
179
176
|
};
|
|
180
|
-
}
|
|
177
|
+
}
|
|
181
178
|
};
|
|
182
179
|
}
|
|
183
180
|
_morphStrategy = strategy;
|
|
@@ -190,7 +187,7 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
190
187
|
completeMorph() {
|
|
191
188
|
if (morphCurveB !== null) {
|
|
192
189
|
if (_morphStrategy === "normalized" && curve.period !== morphCurveB.period) {
|
|
193
|
-
t =
|
|
190
|
+
t = t / curve.period * morphCurveB.period;
|
|
194
191
|
}
|
|
195
192
|
curve = morphCurveB;
|
|
196
193
|
}
|
|
@@ -199,28 +196,25 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
199
196
|
},
|
|
200
197
|
getSarmalSkeleton() {
|
|
201
198
|
const steps = Math.ceil(curve.period * POINTS_PER_PERIOD_UNIT);
|
|
202
|
-
const
|
|
199
|
+
const points2 = new Array(steps);
|
|
203
200
|
if (morphCurveB !== null && _morphAlpha !== null) {
|
|
204
201
|
for (let i = 0; i < steps; i++) {
|
|
205
|
-
const sampleT =
|
|
202
|
+
const sampleT = i / (steps - 1) * curve.period;
|
|
206
203
|
const a = sampleSkeleton(curve, sampleT);
|
|
207
|
-
const tB =
|
|
208
|
-
_morphStrategy === "normalized"
|
|
209
|
-
? (sampleT / curve.period) * morphCurveB.period
|
|
210
|
-
: sampleT;
|
|
204
|
+
const tB = _morphStrategy === "normalized" ? sampleT / curve.period * morphCurveB.period : sampleT;
|
|
211
205
|
const b = sampleSkeleton(morphCurveB, tB);
|
|
212
|
-
|
|
206
|
+
points2[i] = {
|
|
213
207
|
x: a.x + (b.x - a.x) * _morphAlpha,
|
|
214
|
-
y: a.y + (b.y - a.y) * _morphAlpha
|
|
208
|
+
y: a.y + (b.y - a.y) * _morphAlpha
|
|
215
209
|
};
|
|
216
210
|
}
|
|
217
|
-
return
|
|
211
|
+
return points2;
|
|
218
212
|
}
|
|
219
213
|
for (let i = 0; i < steps; i++) {
|
|
220
|
-
const sampleT =
|
|
221
|
-
|
|
214
|
+
const sampleT = i / (steps - 1) * curve.period;
|
|
215
|
+
points2[i] = sampleSkeleton(curve, sampleT);
|
|
222
216
|
}
|
|
223
|
-
return
|
|
217
|
+
return points2;
|
|
224
218
|
},
|
|
225
219
|
setSpeed(speed) {
|
|
226
220
|
if (!Number.isFinite(speed)) {
|
|
@@ -259,7 +253,7 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
259
253
|
_speedTransition.reject(new Error("Speed transition cancelled"));
|
|
260
254
|
_speedTransition = null;
|
|
261
255
|
}
|
|
262
|
-
}
|
|
256
|
+
}
|
|
263
257
|
};
|
|
264
258
|
}
|
|
265
259
|
|
|
@@ -298,15 +292,7 @@ function computeNormal(trail, i) {
|
|
|
298
292
|
const tangent = computeTangent(trail, i);
|
|
299
293
|
return { x: -tangent.y, y: tangent.x };
|
|
300
294
|
}
|
|
301
|
-
function computeTrailQuad(
|
|
302
|
-
trail,
|
|
303
|
-
i,
|
|
304
|
-
trailCount,
|
|
305
|
-
toX,
|
|
306
|
-
toY,
|
|
307
|
-
minWidth = TRAIL_MIN_WIDTH,
|
|
308
|
-
maxWidth = TRAIL_MAX_WIDTH,
|
|
309
|
-
) {
|
|
295
|
+
function computeTrailQuad(trail, i, trailCount, toX, toY, minWidth = TRAIL_MIN_WIDTH, maxWidth = TRAIL_MAX_WIDTH) {
|
|
310
296
|
const progress = i / (trailCount - 1);
|
|
311
297
|
const nextProgress = (i + 1) / (trailCount - 1);
|
|
312
298
|
const opacity = Math.pow(progress, TRAIL_FADE_CURVE) * TRAIL_MAX_OPACITY;
|
|
@@ -330,16 +316,13 @@ function computeTrailQuad(
|
|
|
330
316
|
r1x: nx - n1.x * w1,
|
|
331
317
|
r1y: ny - n1.y * w1,
|
|
332
318
|
opacity,
|
|
333
|
-
progress
|
|
319
|
+
progress
|
|
334
320
|
};
|
|
335
321
|
}
|
|
336
|
-
function computeBoundaries(pts, logicalWidth, logicalHeight) {
|
|
322
|
+
function computeBoundaries(pts, logicalWidth, logicalHeight, minPaddingPx = FIT_PADDING_MIN) {
|
|
337
323
|
if (pts.length === 0) return null;
|
|
338
324
|
const first = pts[0];
|
|
339
|
-
let minX = first.x,
|
|
340
|
-
maxX = first.x,
|
|
341
|
-
minY = first.y,
|
|
342
|
-
maxY = first.y;
|
|
325
|
+
let minX = first.x, maxX = first.x, minY = first.y, maxY = first.y;
|
|
343
326
|
for (const p of pts) {
|
|
344
327
|
if (p.x < minX) {
|
|
345
328
|
minX = p.x;
|
|
@@ -358,23 +341,23 @@ function computeBoundaries(pts, logicalWidth, logicalHeight) {
|
|
|
358
341
|
const h = maxY - minY;
|
|
359
342
|
if (w === 0 && h === 0) {
|
|
360
343
|
throw new Error(
|
|
361
|
-
"[sarmal] Degenerate curve: all skeleton points are identical. Check that your curve fn returns distinct points for different values of t."
|
|
344
|
+
"[sarmal] Degenerate curve: all skeleton points are identical. Check that your curve fn returns distinct points for different values of t."
|
|
362
345
|
);
|
|
363
346
|
}
|
|
364
347
|
const scaleXProportional = logicalWidth / (w * (1 + FIT_PADDING * 2));
|
|
365
348
|
const scaleYProportional = logicalHeight / (h * (1 + FIT_PADDING * 2));
|
|
366
|
-
const scaleXMinPadding = (logicalWidth -
|
|
367
|
-
const scaleYMinPadding = (logicalHeight -
|
|
349
|
+
const scaleXMinPadding = (logicalWidth - minPaddingPx * 2) / w;
|
|
350
|
+
const scaleYMinPadding = (logicalHeight - minPaddingPx * 2) / h;
|
|
368
351
|
const scale = Math.min(
|
|
369
352
|
scaleXProportional,
|
|
370
353
|
scaleYProportional,
|
|
371
354
|
scaleXMinPadding,
|
|
372
|
-
scaleYMinPadding
|
|
355
|
+
scaleYMinPadding
|
|
373
356
|
);
|
|
374
357
|
return {
|
|
375
358
|
scale,
|
|
376
359
|
offsetX: (logicalWidth - w * scale) / 2 - minX * scale,
|
|
377
|
-
offsetY: (logicalHeight - h * scale) / 2 - minY * scale
|
|
360
|
+
offsetY: (logicalHeight - h * scale) / 2 - minY * scale
|
|
378
361
|
};
|
|
379
362
|
}
|
|
380
363
|
function enginePassthroughs(engine) {
|
|
@@ -385,6 +368,7 @@ function enginePassthroughs(engine) {
|
|
|
385
368
|
getSpeed: engine.getSpeed,
|
|
386
369
|
resetSpeed: engine.resetSpeed,
|
|
387
370
|
setSpeedOver: engine.setSpeedOver,
|
|
371
|
+
getSarmalSkeleton: engine.getSarmalSkeleton
|
|
388
372
|
};
|
|
389
373
|
}
|
|
390
374
|
var palettes = {
|
|
@@ -393,16 +377,16 @@ var palettes = {
|
|
|
393
377
|
ocean: ["#1e3a8a", "#06b6d4", "#22d3ee", "#e0f2fe"],
|
|
394
378
|
ice: ["#1e3a8a", "#67e8f9"],
|
|
395
379
|
fire: ["#7f1d1d", "#fbbf24"],
|
|
396
|
-
forest: ["#14532d", "#86efac"]
|
|
380
|
+
forest: ["#14532d", "#86efac"]
|
|
397
381
|
};
|
|
398
382
|
function hexToRgb(hex) {
|
|
399
383
|
const n = parseInt(hex.slice(1), 16);
|
|
400
|
-
return { r: n >> 16, g:
|
|
384
|
+
return { r: n >> 16, g: n >> 8 & 255, b: n & 255 };
|
|
401
385
|
}
|
|
402
386
|
var lerpRgb = (a, b, t) => ({
|
|
403
387
|
r: Math.round(a.r + (b.r - a.r) * t),
|
|
404
388
|
g: Math.round(a.g + (b.g - a.g) * t),
|
|
405
|
-
b: Math.round(a.b + (b.b - a.b) * t)
|
|
389
|
+
b: Math.round(a.b + (b.b - a.b) * t)
|
|
406
390
|
});
|
|
407
391
|
function getPaletteColor(palette, position, timeOffset = 0) {
|
|
408
392
|
if (palette.length === 0) {
|
|
@@ -411,7 +395,7 @@ function getPaletteColor(palette, position, timeOffset = 0) {
|
|
|
411
395
|
if (palette.length === 1) {
|
|
412
396
|
return hexToRgb(palette[0]);
|
|
413
397
|
}
|
|
414
|
-
const cyclePos = ((
|
|
398
|
+
const cyclePos = ((position + timeOffset) % 1 + 1) % 1;
|
|
415
399
|
const scaled = cyclePos * palette.length;
|
|
416
400
|
const idx = Math.floor(scaled);
|
|
417
401
|
const t = scaled - idx;
|
|
@@ -426,7 +410,7 @@ var RENDER_OPTION_KEYS = /* @__PURE__ */ new Set([
|
|
|
426
410
|
"headColor",
|
|
427
411
|
"skeletonColor",
|
|
428
412
|
"trailStyle",
|
|
429
|
-
"headRadius"
|
|
413
|
+
"headRadius"
|
|
430
414
|
]);
|
|
431
415
|
function validateRenderOptions(partial) {
|
|
432
416
|
for (const key of Object.keys(partial)) {
|
|
@@ -454,7 +438,7 @@ function assertTrailColor(value) {
|
|
|
454
438
|
if (typeof value === "string") {
|
|
455
439
|
if (!HEX_COLOR_RE.test(value)) {
|
|
456
440
|
throw new TypeError(
|
|
457
|
-
`[sarmal] setRenderOptions: trailColor must be a 6-digit hex string, got "${value}"
|
|
441
|
+
`[sarmal] setRenderOptions: trailColor must be a 6-digit hex string, got "${value}"`
|
|
458
442
|
);
|
|
459
443
|
}
|
|
460
444
|
return;
|
|
@@ -462,21 +446,21 @@ function assertTrailColor(value) {
|
|
|
462
446
|
if (Array.isArray(value)) {
|
|
463
447
|
if (value.length < 2) {
|
|
464
448
|
throw new RangeError(
|
|
465
|
-
`[sarmal] setRenderOptions: trailColor array must have at least 2 entries, got ${value.length}
|
|
449
|
+
`[sarmal] setRenderOptions: trailColor array must have at least 2 entries, got ${value.length}`
|
|
466
450
|
);
|
|
467
451
|
}
|
|
468
452
|
for (let i = 0; i < value.length; i++) {
|
|
469
453
|
const entry = value[i];
|
|
470
454
|
if (typeof entry !== "string" || !HEX_COLOR_RE.test(entry)) {
|
|
471
455
|
throw new TypeError(
|
|
472
|
-
`[sarmal] setRenderOptions: trailColor[${i}] must be a 6-digit hex string, got ${JSON.stringify(entry)}
|
|
456
|
+
`[sarmal] setRenderOptions: trailColor[${i}] must be a 6-digit hex string, got ${JSON.stringify(entry)}`
|
|
473
457
|
);
|
|
474
458
|
}
|
|
475
459
|
}
|
|
476
460
|
return;
|
|
477
461
|
}
|
|
478
462
|
throw new TypeError(
|
|
479
|
-
`[sarmal] setRenderOptions: trailColor must be a 6-digit hex string or an array of hex strings, got ${JSON.stringify(value)}
|
|
463
|
+
`[sarmal] setRenderOptions: trailColor must be a 6-digit hex string or an array of hex strings, got ${JSON.stringify(value)}`
|
|
480
464
|
);
|
|
481
465
|
}
|
|
482
466
|
function assertHeadColor(value) {
|
|
@@ -485,7 +469,7 @@ function assertHeadColor(value) {
|
|
|
485
469
|
}
|
|
486
470
|
if (typeof value !== "string" || !HEX_COLOR_RE.test(value)) {
|
|
487
471
|
throw new TypeError(
|
|
488
|
-
`[sarmal] setRenderOptions: headColor must be a 6-digit hex string or null, got ${JSON.stringify(value)}
|
|
472
|
+
`[sarmal] setRenderOptions: headColor must be a 6-digit hex string or null, got ${JSON.stringify(value)}`
|
|
489
473
|
);
|
|
490
474
|
}
|
|
491
475
|
}
|
|
@@ -495,26 +479,26 @@ function assertSkeletonColor(value) {
|
|
|
495
479
|
}
|
|
496
480
|
if (typeof value !== "string" || !HEX_COLOR_RE.test(value)) {
|
|
497
481
|
throw new TypeError(
|
|
498
|
-
`[sarmal] setRenderOptions: skeletonColor must be a 6-digit hex string or "transparent", got ${JSON.stringify(value)}
|
|
482
|
+
`[sarmal] setRenderOptions: skeletonColor must be a 6-digit hex string or "transparent", got ${JSON.stringify(value)}`
|
|
499
483
|
);
|
|
500
484
|
}
|
|
501
485
|
}
|
|
502
486
|
function assertTrailStyle(value) {
|
|
503
487
|
if (!TRAIL_STYLES.includes(value)) {
|
|
504
488
|
throw new RangeError(
|
|
505
|
-
`[sarmal] setRenderOptions: trailStyle must be one of "default", "gradient-static", "gradient-animated", got ${JSON.stringify(value)}
|
|
489
|
+
`[sarmal] setRenderOptions: trailStyle must be one of "default", "gradient-static", "gradient-animated", got ${JSON.stringify(value)}`
|
|
506
490
|
);
|
|
507
491
|
}
|
|
508
492
|
}
|
|
509
493
|
function assertHeadRadius(value) {
|
|
510
494
|
if (typeof value !== "number") {
|
|
511
495
|
throw new TypeError(
|
|
512
|
-
`[sarmal] setRenderOptions: headRadius must be a number, got ${JSON.stringify(value)}
|
|
496
|
+
`[sarmal] setRenderOptions: headRadius must be a number, got ${JSON.stringify(value)}`
|
|
513
497
|
);
|
|
514
498
|
}
|
|
515
499
|
if (!Number.isFinite(value) || value <= 0) {
|
|
516
500
|
throw new TypeError(
|
|
517
|
-
`[sarmal] setRenderOptions: headRadius must be a finite positive number, got ${value}
|
|
501
|
+
`[sarmal] setRenderOptions: headRadius must be a finite positive number, got ${value}`
|
|
518
502
|
);
|
|
519
503
|
}
|
|
520
504
|
}
|
|
@@ -536,13 +520,13 @@ function resolveHeadColor(trailColor, trailStyle) {
|
|
|
536
520
|
function warnIfTrailColorMismatch(trailColor, trailStyle) {
|
|
537
521
|
if (trailStyle === "default" && Array.isArray(trailColor)) {
|
|
538
522
|
console.warn(
|
|
539
|
-
'[sarmal] trailColor is an array but trailStyle is "default"; only the first color will be used. Pass a gradient trailStyle to use the whole palette.'
|
|
523
|
+
'[sarmal] trailColor is an array but trailStyle is "default"; only the first color will be used. Pass a gradient trailStyle to use the whole palette.'
|
|
540
524
|
);
|
|
541
525
|
return;
|
|
542
526
|
}
|
|
543
527
|
if (trailStyle !== "default" && typeof trailColor === "string") {
|
|
544
528
|
console.warn(
|
|
545
|
-
`[sarmal] trailColor is a single color but trailStyle is "${trailStyle}"; the trail will render as a solid color. Pass an array of hex colors to use a real gradient
|
|
529
|
+
`[sarmal] trailColor is a single color but trailStyle is "${trailStyle}"; the trail will render as a solid color. Pass an array of hex colors to use a real gradient.`
|
|
546
530
|
);
|
|
547
531
|
}
|
|
548
532
|
}
|
|
@@ -552,7 +536,7 @@ var getHeadDotRadius = (w, h) => Math.max(1, 3 * Math.sqrt(Math.min(w, h) / 160)
|
|
|
552
536
|
var WHITE_HEX = "#ffffff";
|
|
553
537
|
function hexToRgbComponents(hex) {
|
|
554
538
|
const n = parseInt(hex.slice(1), 16);
|
|
555
|
-
return `${n >> 16},${
|
|
539
|
+
return `${n >> 16},${n >> 8 & 255},${n & 255}`;
|
|
556
540
|
}
|
|
557
541
|
function applyDprSizing(target, logicalWidth, logicalHeight, dpr) {
|
|
558
542
|
target.style.width = `${logicalWidth}px`;
|
|
@@ -596,6 +580,7 @@ function createRenderer(options) {
|
|
|
596
580
|
let offsetY = 0;
|
|
597
581
|
let animationId = null;
|
|
598
582
|
let lastTime = 0;
|
|
583
|
+
let pausedByVisibility = false;
|
|
599
584
|
let morphResolve = null;
|
|
600
585
|
let morphReject = null;
|
|
601
586
|
let morphDurationMs = DEFAULT_MORPH_DURATION_MS;
|
|
@@ -678,7 +663,7 @@ function createRenderer(options) {
|
|
|
678
663
|
i,
|
|
679
664
|
trailCount,
|
|
680
665
|
toX,
|
|
681
|
-
toY
|
|
666
|
+
toY
|
|
682
667
|
);
|
|
683
668
|
if (trailStyle === "default") {
|
|
684
669
|
ctx.fillStyle = `rgba(${trailSolidRgb},${opacity})`;
|
|
@@ -789,6 +774,7 @@ function createRenderer(options) {
|
|
|
789
774
|
cancelAnimationFrame(animationId);
|
|
790
775
|
animationId = null;
|
|
791
776
|
}
|
|
777
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
792
778
|
if (morphReject !== null) {
|
|
793
779
|
morphReject(new Error("Instance destroyed during morph"));
|
|
794
780
|
morphResolve = null;
|
|
@@ -842,10 +828,30 @@ function createRenderer(options) {
|
|
|
842
828
|
if (partial.trailColor !== void 0 || partial.trailStyle !== void 0) {
|
|
843
829
|
warnIfTrailColorMismatch(trailColor, trailStyle);
|
|
844
830
|
}
|
|
845
|
-
}
|
|
831
|
+
}
|
|
846
832
|
};
|
|
847
|
-
|
|
833
|
+
const pauseOnHidden = options.pauseOnHidden !== false;
|
|
834
|
+
function handleVisibilityChange() {
|
|
835
|
+
if (document.hidden) {
|
|
836
|
+
if (animationId !== null) {
|
|
837
|
+
instance.pause();
|
|
838
|
+
pausedByVisibility = true;
|
|
839
|
+
}
|
|
840
|
+
} else {
|
|
841
|
+
if (pausedByVisibility) {
|
|
842
|
+
pausedByVisibility = false;
|
|
843
|
+
instance.play();
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
if (pauseOnHidden) {
|
|
848
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
849
|
+
}
|
|
850
|
+
const actuallyAutoStart = shouldAutoStart && !(pauseOnHidden && document.hidden);
|
|
851
|
+
if (actuallyAutoStart) {
|
|
848
852
|
instance.play();
|
|
853
|
+
} else if (shouldAutoStart) {
|
|
854
|
+
pausedByVisibility = true;
|
|
849
855
|
}
|
|
850
856
|
return instance;
|
|
851
857
|
}
|
|
@@ -872,7 +878,7 @@ function sampleCurveSkeleton(curveDef) {
|
|
|
872
878
|
const samples = Math.ceil(period * 50);
|
|
873
879
|
const pts = Array.from({ length: samples });
|
|
874
880
|
for (let i = 0; i < samples; i++) {
|
|
875
|
-
const t =
|
|
881
|
+
const t = i / (samples - 1) * period;
|
|
876
882
|
pts[i] = curveDef.skeletonFn ? curveDef.skeletonFn(t) : curveDef.fn(t, 0, EMPTY_PARAMS2);
|
|
877
883
|
}
|
|
878
884
|
return pts;
|
|
@@ -885,7 +891,7 @@ function createSVGRenderer(options) {
|
|
|
885
891
|
const poolSize = engine.trailLength;
|
|
886
892
|
if (poolSize > HIGH_TRAIL_LENGTH_THRESHOLD) {
|
|
887
893
|
console.warn(
|
|
888
|
-
`[sarmal] High trailLength in SVG renderer (${poolSize}). Consider using the canvas renderer for long trails
|
|
894
|
+
`[sarmal] High trailLength in SVG renderer (${poolSize}). Consider using the canvas renderer for long trails.`
|
|
889
895
|
);
|
|
890
896
|
}
|
|
891
897
|
let trailStyle = options.trailStyle ?? "default";
|
|
@@ -904,9 +910,9 @@ function createSVGRenderer(options) {
|
|
|
904
910
|
return rect.width && rect.height ? Math.min(rect.width, rect.height) : 200;
|
|
905
911
|
}
|
|
906
912
|
const containerPx = getContainerPixelSize();
|
|
907
|
-
const svgTrailMinWidth =
|
|
908
|
-
const svgTrailMaxWidth =
|
|
909
|
-
const svgSkeletonStrokeWidth = String(
|
|
913
|
+
const svgTrailMinWidth = TRAIL_MIN_WIDTH * viewSize / containerPx;
|
|
914
|
+
const svgTrailMaxWidth = TRAIL_MAX_WIDTH * viewSize / containerPx;
|
|
915
|
+
const svgSkeletonStrokeWidth = String(SKELETON_STROKE_WIDTH_PX * viewSize / containerPx);
|
|
910
916
|
headRadius = options.headRadius ?? SVG_DEFAULT_HEAD_RADIUS;
|
|
911
917
|
container.setAttribute("viewBox", `0 0 ${viewSize} ${viewSize}`);
|
|
912
918
|
container.setAttribute("role", "img");
|
|
@@ -994,7 +1000,7 @@ function createSVGRenderer(options) {
|
|
|
994
1000
|
px,
|
|
995
1001
|
py,
|
|
996
1002
|
svgTrailMinWidth,
|
|
997
|
-
svgTrailMaxWidth
|
|
1003
|
+
svgTrailMaxWidth
|
|
998
1004
|
);
|
|
999
1005
|
const d = `M${l0x.toFixed(2)} ${l0y.toFixed(2)} L${l1x.toFixed(2)} ${l1y.toFixed(2)} L${r1x.toFixed(2)} ${r1y.toFixed(2)} L${r0x.toFixed(2)} ${r0y.toFixed(2)} Z`;
|
|
1000
1006
|
trailPaths[i].setAttribute("d", d);
|
|
@@ -1021,8 +1027,8 @@ function createSVGRenderer(options) {
|
|
|
1021
1027
|
}
|
|
1022
1028
|
let animationId = null;
|
|
1023
1029
|
let lastTime = 0;
|
|
1024
|
-
|
|
1025
|
-
|
|
1030
|
+
let pausedByVisibility = false;
|
|
1031
|
+
const prefersReducedMotion = typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
1026
1032
|
let morphResolve = null;
|
|
1027
1033
|
let morphReject = null;
|
|
1028
1034
|
let morphDurationMs = DEFAULT_MORPH_DURATION_MS;
|
|
@@ -1040,7 +1046,7 @@ function createSVGRenderer(options) {
|
|
|
1040
1046
|
skeletonPathA.setAttribute("visibility", "visible");
|
|
1041
1047
|
skeletonPathA.setAttribute(
|
|
1042
1048
|
"stroke-opacity",
|
|
1043
|
-
String((1 - morphAlpha) * DEFAULT_SKELETON_OPACITY)
|
|
1049
|
+
String((1 - morphAlpha) * DEFAULT_SKELETON_OPACITY)
|
|
1044
1050
|
);
|
|
1045
1051
|
}
|
|
1046
1052
|
if (morphPathBBuilt) {
|
|
@@ -1112,6 +1118,7 @@ function createSVGRenderer(options) {
|
|
|
1112
1118
|
cancelAnimationFrame(animationId);
|
|
1113
1119
|
animationId = null;
|
|
1114
1120
|
}
|
|
1121
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
1115
1122
|
if (morphReject !== null) {
|
|
1116
1123
|
morphReject(new Error("Instance destroyed during morph"));
|
|
1117
1124
|
morphResolve = null;
|
|
@@ -1193,10 +1200,30 @@ function createSVGRenderer(options) {
|
|
|
1193
1200
|
if (partial.trailColor !== void 0 || partial.trailStyle !== void 0) {
|
|
1194
1201
|
warnIfTrailColorMismatch(trailColor, trailStyle);
|
|
1195
1202
|
}
|
|
1196
|
-
}
|
|
1203
|
+
}
|
|
1197
1204
|
};
|
|
1198
|
-
|
|
1205
|
+
const pauseOnHidden = options.pauseOnHidden !== false;
|
|
1206
|
+
function handleVisibilityChange() {
|
|
1207
|
+
if (document.hidden) {
|
|
1208
|
+
if (animationId !== null) {
|
|
1209
|
+
instance.pause();
|
|
1210
|
+
pausedByVisibility = true;
|
|
1211
|
+
}
|
|
1212
|
+
} else {
|
|
1213
|
+
if (pausedByVisibility) {
|
|
1214
|
+
pausedByVisibility = false;
|
|
1215
|
+
instance.play();
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
if (pauseOnHidden) {
|
|
1220
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
1221
|
+
}
|
|
1222
|
+
const actuallyAutoStart = shouldAutoStart && !(pauseOnHidden && document.hidden);
|
|
1223
|
+
if (actuallyAutoStart) {
|
|
1199
1224
|
instance.play();
|
|
1225
|
+
} else if (shouldAutoStart) {
|
|
1226
|
+
pausedByVisibility = true;
|
|
1200
1227
|
}
|
|
1201
1228
|
return instance;
|
|
1202
1229
|
}
|
|
@@ -1206,254 +1233,309 @@ function createSarmalSVG(container, curveDef, options) {
|
|
|
1206
1233
|
return createSVGRenderer({ container, engine, ...rendererOpts });
|
|
1207
1234
|
}
|
|
1208
1235
|
|
|
1209
|
-
// src/
|
|
1210
|
-
var
|
|
1211
|
-
function
|
|
1212
|
-
const
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
const
|
|
1236
|
+
// src/catmull-rom.ts
|
|
1237
|
+
var PERIOD = 2 * Math.PI;
|
|
1238
|
+
function catmullRom1D(p0, p1, p2, p3, u) {
|
|
1239
|
+
const u2 = u * u;
|
|
1240
|
+
const u3 = u2 * u;
|
|
1241
|
+
return 0.5 * (2 * p1 + (-p0 + p2) * u + (2 * p0 - 5 * p1 + 4 * p2 - p3) * u2 + (-p0 + 3 * p1 - 3 * p2 + p3) * u3);
|
|
1242
|
+
}
|
|
1243
|
+
function evaluateCatmullRom(points2, t) {
|
|
1244
|
+
const N = points2.length;
|
|
1245
|
+
if (N === 0) {
|
|
1246
|
+
return { x: 0, y: 0 };
|
|
1247
|
+
}
|
|
1248
|
+
if (N === 1) {
|
|
1249
|
+
return { x: points2[0][0], y: points2[0][1] };
|
|
1250
|
+
}
|
|
1251
|
+
t = (t % PERIOD + PERIOD) % PERIOD;
|
|
1252
|
+
const segmentSize = PERIOD / N;
|
|
1253
|
+
let i = Math.floor(t / segmentSize);
|
|
1254
|
+
if (i >= N) {
|
|
1255
|
+
i = N - 1;
|
|
1256
|
+
}
|
|
1257
|
+
let u = (t - i * segmentSize) / segmentSize;
|
|
1258
|
+
u = Math.max(0, Math.min(1, u));
|
|
1259
|
+
const p0 = points2[(i - 1 + N) % N];
|
|
1260
|
+
const p1 = points2[i];
|
|
1261
|
+
const p2 = points2[(i + 1) % N];
|
|
1262
|
+
const p3 = points2[(i + 2) % N];
|
|
1263
|
+
return {
|
|
1264
|
+
x: catmullRom1D(p0[0], p1[0], p2[0], p3[0], u),
|
|
1265
|
+
y: catmullRom1D(p0[1], p1[1], p2[1], p3[1], u)
|
|
1266
|
+
};
|
|
1267
|
+
}
|
|
1268
|
+
function drawCurve(points2, opts) {
|
|
1269
|
+
if (points2.length < 3) {
|
|
1270
|
+
throw new Error(`drawCurve requires at least 3 points, received ${points2.length}.`);
|
|
1271
|
+
}
|
|
1272
|
+
const first = points2[0];
|
|
1273
|
+
if (points2.every((p) => p[0] === first[0] && p[1] === first[1])) {
|
|
1274
|
+
console.warn(
|
|
1275
|
+
"[sarmal].drawCurve: all control points are identical. The curve will be a single point."
|
|
1276
|
+
);
|
|
1277
|
+
}
|
|
1278
|
+
const maxAbs = points2.reduce((m, p) => Math.max(m, Math.abs(p[0]), Math.abs(p[1])), 0);
|
|
1279
|
+
if (maxAbs > 2) {
|
|
1280
|
+
console.warn(
|
|
1281
|
+
`[sarmal].drawCurve: control points extend to \xB1${maxAbs.toFixed(1)}, which may render off-screen. Coordinates should be in [-1, 1].`
|
|
1282
|
+
);
|
|
1283
|
+
}
|
|
1284
|
+
const pts = points2.map(([x, y]) => [x, y]);
|
|
1218
1285
|
return {
|
|
1219
|
-
|
|
1220
|
-
|
|
1286
|
+
name: opts?.name ?? "drawn",
|
|
1287
|
+
fn: (t) => evaluateCatmullRom(pts, t),
|
|
1288
|
+
period: PERIOD,
|
|
1289
|
+
kind: "drawn"
|
|
1221
1290
|
};
|
|
1222
1291
|
}
|
|
1292
|
+
|
|
1293
|
+
// src/curves/artemis2.ts
|
|
1294
|
+
var points = [
|
|
1295
|
+
[-0.44, -0.45],
|
|
1296
|
+
[-0.53, -0.77],
|
|
1297
|
+
[-0.82, -0.66],
|
|
1298
|
+
[-0.82, -0.18],
|
|
1299
|
+
[-0.25, -0.04],
|
|
1300
|
+
[0.16, -0.49],
|
|
1301
|
+
[-0.03, -0.87],
|
|
1302
|
+
[-0.68, -0.94],
|
|
1303
|
+
[-0.95, -0.61],
|
|
1304
|
+
[-0.87, -0],
|
|
1305
|
+
[-0.34, 0.21],
|
|
1306
|
+
[0.27, -0.04],
|
|
1307
|
+
[0.87, 0.06],
|
|
1308
|
+
[0.87, 0.57],
|
|
1309
|
+
[0.32, 0.66],
|
|
1310
|
+
[-0.21, -0.43],
|
|
1311
|
+
[-0.43, -0.81],
|
|
1312
|
+
[-0.69, -0.84],
|
|
1313
|
+
[-0.87, -0.66],
|
|
1314
|
+
[-0.9, -0.47],
|
|
1315
|
+
[-0.76, -0.35]
|
|
1316
|
+
];
|
|
1223
1317
|
var artemis2 = {
|
|
1224
|
-
name: "Artemis II",
|
|
1225
|
-
|
|
1226
|
-
period: TWO_PI2,
|
|
1227
|
-
speed: 0.7,
|
|
1318
|
+
...drawCurve(points, { name: "Artemis II" }),
|
|
1319
|
+
speed: 0.7
|
|
1228
1320
|
};
|
|
1229
1321
|
|
|
1230
1322
|
// src/curves/astroid.ts
|
|
1231
|
-
var
|
|
1323
|
+
var TWO_PI2 = Math.PI * 2;
|
|
1232
1324
|
function astroidFn(t, _time, _params) {
|
|
1233
1325
|
const c = Math.cos(t);
|
|
1234
1326
|
const s = Math.sin(t);
|
|
1235
1327
|
return {
|
|
1236
1328
|
x: c * c * c,
|
|
1237
|
-
y: s * s * s
|
|
1329
|
+
y: s * s * s
|
|
1238
1330
|
};
|
|
1239
1331
|
}
|
|
1240
1332
|
var astroid = {
|
|
1241
1333
|
name: "Astroid",
|
|
1242
1334
|
fn: astroidFn,
|
|
1243
|
-
period:
|
|
1244
|
-
speed: 1.1
|
|
1335
|
+
period: TWO_PI2,
|
|
1336
|
+
speed: 1.1
|
|
1245
1337
|
};
|
|
1246
1338
|
|
|
1247
1339
|
// src/curves/deltoid.ts
|
|
1248
|
-
var
|
|
1340
|
+
var TWO_PI3 = Math.PI * 2;
|
|
1249
1341
|
function deltoidFn(t, _time, _params) {
|
|
1250
1342
|
return {
|
|
1251
1343
|
x: 2 * Math.cos(t) + Math.cos(2 * t),
|
|
1252
|
-
y: 2 * Math.sin(t) - Math.sin(2 * t)
|
|
1344
|
+
y: 2 * Math.sin(t) - Math.sin(2 * t)
|
|
1253
1345
|
};
|
|
1254
1346
|
}
|
|
1255
1347
|
var deltoid = {
|
|
1256
1348
|
name: "Deltoid",
|
|
1257
1349
|
fn: deltoidFn,
|
|
1258
|
-
period:
|
|
1259
|
-
speed: 0.9
|
|
1350
|
+
period: TWO_PI3,
|
|
1351
|
+
speed: 0.9
|
|
1260
1352
|
};
|
|
1261
1353
|
|
|
1262
1354
|
// src/curves/epicycloid3.ts
|
|
1263
|
-
var
|
|
1355
|
+
var TWO_PI4 = Math.PI * 2;
|
|
1264
1356
|
function epicycloid3Fn(t, _time, _params) {
|
|
1265
1357
|
return {
|
|
1266
1358
|
x: 4 * Math.cos(t) - Math.cos(4 * t),
|
|
1267
|
-
y: 4 * Math.sin(t) - Math.sin(4 * t)
|
|
1359
|
+
y: 4 * Math.sin(t) - Math.sin(4 * t)
|
|
1268
1360
|
};
|
|
1269
1361
|
}
|
|
1270
1362
|
var epicycloid3 = {
|
|
1271
1363
|
name: "Epicycloid (n=3)",
|
|
1272
1364
|
fn: epicycloid3Fn,
|
|
1273
|
-
period:
|
|
1274
|
-
speed: 0.75
|
|
1365
|
+
period: TWO_PI4,
|
|
1366
|
+
speed: 0.75
|
|
1275
1367
|
};
|
|
1276
1368
|
|
|
1277
1369
|
// src/curves/epitrochoid7.ts
|
|
1278
|
-
var
|
|
1370
|
+
var TWO_PI5 = Math.PI * 2;
|
|
1279
1371
|
function epitrochoid7Fn(t, _time, _params) {
|
|
1280
1372
|
const d = 1 + 0.55 * Math.sin(t * 0.5);
|
|
1281
1373
|
return {
|
|
1282
1374
|
x: 7 * Math.cos(t) - d * Math.cos(7 * t),
|
|
1283
|
-
y: 7 * Math.sin(t) - d * Math.sin(7 * t)
|
|
1375
|
+
y: 7 * Math.sin(t) - d * Math.sin(7 * t)
|
|
1284
1376
|
};
|
|
1285
1377
|
}
|
|
1286
1378
|
function epitrochoid7SkeletonFn(t) {
|
|
1287
1379
|
const d = 1.275;
|
|
1288
1380
|
return {
|
|
1289
1381
|
x: 7 * Math.cos(t) - d * Math.cos(7 * t),
|
|
1290
|
-
y: 7 * Math.sin(t) - d * Math.sin(7 * t)
|
|
1382
|
+
y: 7 * Math.sin(t) - d * Math.sin(7 * t)
|
|
1291
1383
|
};
|
|
1292
1384
|
}
|
|
1293
1385
|
var epitrochoid7 = {
|
|
1294
1386
|
name: "Epitrochoid",
|
|
1295
1387
|
fn: epitrochoid7Fn,
|
|
1296
|
-
period:
|
|
1388
|
+
period: TWO_PI5,
|
|
1297
1389
|
speed: 1.4,
|
|
1298
|
-
skeletonFn: epitrochoid7SkeletonFn
|
|
1390
|
+
skeletonFn: epitrochoid7SkeletonFn
|
|
1299
1391
|
};
|
|
1300
1392
|
|
|
1301
1393
|
// src/curves/lissajous32.ts
|
|
1302
|
-
var
|
|
1394
|
+
var TWO_PI6 = Math.PI * 2;
|
|
1303
1395
|
function lissajous32Fn(t, time, _params) {
|
|
1304
1396
|
const phi = time * 0.45;
|
|
1305
1397
|
return {
|
|
1306
1398
|
x: Math.sin(3 * t + phi),
|
|
1307
|
-
y: Math.sin(2 * t)
|
|
1399
|
+
y: Math.sin(2 * t)
|
|
1308
1400
|
};
|
|
1309
1401
|
}
|
|
1310
1402
|
var lissajous32 = {
|
|
1311
1403
|
name: "Lissajous 3:2",
|
|
1312
1404
|
fn: lissajous32Fn,
|
|
1313
|
-
period:
|
|
1405
|
+
period: TWO_PI6,
|
|
1314
1406
|
speed: 2,
|
|
1315
|
-
skeleton: "live"
|
|
1407
|
+
skeleton: "live"
|
|
1316
1408
|
};
|
|
1317
1409
|
|
|
1318
1410
|
// src/curves/lissajous43.ts
|
|
1319
|
-
var
|
|
1411
|
+
var TWO_PI7 = Math.PI * 2;
|
|
1320
1412
|
function lissajous43Fn(t, time, _params) {
|
|
1321
1413
|
const phi = time * 0.38;
|
|
1322
1414
|
return {
|
|
1323
1415
|
x: Math.sin(4 * t + phi),
|
|
1324
|
-
y: Math.sin(3 * t)
|
|
1416
|
+
y: Math.sin(3 * t)
|
|
1325
1417
|
};
|
|
1326
1418
|
}
|
|
1327
1419
|
var lissajous43 = {
|
|
1328
1420
|
name: "Lissajous 4:3",
|
|
1329
1421
|
fn: lissajous43Fn,
|
|
1330
|
-
period:
|
|
1422
|
+
period: TWO_PI7,
|
|
1331
1423
|
speed: 1.8,
|
|
1332
|
-
skeleton: "live"
|
|
1424
|
+
skeleton: "live"
|
|
1333
1425
|
};
|
|
1334
1426
|
|
|
1335
1427
|
// src/curves/lame.ts
|
|
1336
|
-
var
|
|
1428
|
+
var TWO_PI8 = Math.PI * 2;
|
|
1337
1429
|
function lameFn(t, time, _params) {
|
|
1338
1430
|
const p = 1.75 + 1.25 * Math.sin(time * 0.48);
|
|
1339
|
-
const c = Math.cos(t),
|
|
1340
|
-
s = Math.sin(t);
|
|
1431
|
+
const c = Math.cos(t), s = Math.sin(t);
|
|
1341
1432
|
return {
|
|
1342
1433
|
x: Math.sign(c) * Math.pow(Math.abs(c), p),
|
|
1343
|
-
y: Math.sign(s) * Math.pow(Math.abs(s), p)
|
|
1434
|
+
y: Math.sign(s) * Math.pow(Math.abs(s), p)
|
|
1344
1435
|
};
|
|
1345
1436
|
}
|
|
1346
1437
|
var lame = {
|
|
1347
1438
|
name: "Lam\xE9 Curve",
|
|
1348
1439
|
fn: lameFn,
|
|
1349
|
-
period:
|
|
1440
|
+
period: TWO_PI8,
|
|
1350
1441
|
speed: 1,
|
|
1351
|
-
skeleton: "live"
|
|
1442
|
+
skeleton: "live"
|
|
1352
1443
|
};
|
|
1353
1444
|
|
|
1354
1445
|
// src/curves/rose3.ts
|
|
1355
|
-
var
|
|
1446
|
+
var TWO_PI9 = Math.PI * 2;
|
|
1356
1447
|
function rose3Fn(t, _time, _params) {
|
|
1357
1448
|
const r = Math.cos(3 * t);
|
|
1358
1449
|
return {
|
|
1359
1450
|
x: r * Math.cos(t),
|
|
1360
|
-
y: r * Math.sin(t)
|
|
1451
|
+
y: r * Math.sin(t)
|
|
1361
1452
|
};
|
|
1362
1453
|
}
|
|
1363
1454
|
var rose3 = {
|
|
1364
1455
|
name: "Rose (n=3)",
|
|
1365
1456
|
fn: rose3Fn,
|
|
1366
|
-
period:
|
|
1367
|
-
speed: 1.15
|
|
1457
|
+
period: TWO_PI9,
|
|
1458
|
+
speed: 1.15
|
|
1368
1459
|
};
|
|
1369
1460
|
|
|
1370
1461
|
// src/curves/rose5.ts
|
|
1371
|
-
var
|
|
1462
|
+
var TWO_PI10 = Math.PI * 2;
|
|
1372
1463
|
function rose5Fn(t, _time, _params) {
|
|
1373
1464
|
const r = Math.cos(5 * t);
|
|
1374
1465
|
return {
|
|
1375
1466
|
x: r * Math.cos(t),
|
|
1376
|
-
y: r * Math.sin(t)
|
|
1467
|
+
y: r * Math.sin(t)
|
|
1377
1468
|
};
|
|
1378
1469
|
}
|
|
1379
1470
|
var rose5 = {
|
|
1380
1471
|
name: "Rose (n=5)",
|
|
1381
1472
|
fn: rose5Fn,
|
|
1382
|
-
period:
|
|
1383
|
-
speed: 1
|
|
1473
|
+
period: TWO_PI10,
|
|
1474
|
+
speed: 1
|
|
1384
1475
|
};
|
|
1385
1476
|
|
|
1386
1477
|
// src/curves/rose52.ts
|
|
1387
1478
|
var FOUR_PI = Math.PI * 4;
|
|
1388
1479
|
function rose52Fn(t, _time, _params) {
|
|
1389
|
-
const r = Math.cos(
|
|
1480
|
+
const r = Math.cos(5 / 2 * t);
|
|
1390
1481
|
return {
|
|
1391
1482
|
x: r * Math.cos(t),
|
|
1392
|
-
y: r * Math.sin(t)
|
|
1483
|
+
y: r * Math.sin(t)
|
|
1393
1484
|
};
|
|
1394
1485
|
}
|
|
1395
1486
|
var rose52 = {
|
|
1396
1487
|
name: "Rose (n=5/2)",
|
|
1397
1488
|
fn: rose52Fn,
|
|
1398
1489
|
period: FOUR_PI,
|
|
1399
|
-
speed: 0.8
|
|
1490
|
+
speed: 0.8
|
|
1400
1491
|
};
|
|
1401
1492
|
|
|
1402
1493
|
// src/curves/star.ts
|
|
1403
|
-
var
|
|
1494
|
+
var TWO_PI11 = Math.PI * 2;
|
|
1404
1495
|
function starFn(t, _time, _params) {
|
|
1405
|
-
const r =
|
|
1406
|
-
Math.abs(Math.cos((5 / 2) * t)) +
|
|
1407
|
-
0.35 * Math.abs(Math.cos((15 / 2) * t)) +
|
|
1408
|
-
0.15 * Math.abs(Math.cos((25 / 2) * t));
|
|
1496
|
+
const r = Math.abs(Math.cos(5 / 2 * t)) + 0.35 * Math.abs(Math.cos(15 / 2 * t)) + 0.15 * Math.abs(Math.cos(25 / 2 * t));
|
|
1409
1497
|
return {
|
|
1410
1498
|
x: r * Math.cos(t),
|
|
1411
|
-
y: r * Math.sin(t)
|
|
1499
|
+
y: r * Math.sin(t)
|
|
1412
1500
|
};
|
|
1413
1501
|
}
|
|
1414
1502
|
var star = {
|
|
1415
1503
|
name: "Star",
|
|
1416
1504
|
fn: starFn,
|
|
1417
|
-
period:
|
|
1418
|
-
speed: 1
|
|
1505
|
+
period: TWO_PI11,
|
|
1506
|
+
speed: 1
|
|
1419
1507
|
};
|
|
1420
1508
|
|
|
1421
1509
|
// src/curves/star4.ts
|
|
1422
|
-
var
|
|
1510
|
+
var TWO_PI12 = Math.PI * 2;
|
|
1423
1511
|
function star4Fn(t, _time, _params) {
|
|
1424
|
-
const r =
|
|
1425
|
-
Math.abs(Math.cos(2 * t)) +
|
|
1426
|
-
0.35 * Math.abs(Math.cos(6 * t)) +
|
|
1427
|
-
0.15 * Math.abs(Math.cos(10 * t));
|
|
1512
|
+
const r = Math.abs(Math.cos(2 * t)) + 0.35 * Math.abs(Math.cos(6 * t)) + 0.15 * Math.abs(Math.cos(10 * t));
|
|
1428
1513
|
return {
|
|
1429
1514
|
x: r * Math.cos(t),
|
|
1430
|
-
y: r * Math.sin(t)
|
|
1515
|
+
y: r * Math.sin(t)
|
|
1431
1516
|
};
|
|
1432
1517
|
}
|
|
1433
1518
|
var star4 = {
|
|
1434
1519
|
name: "Star (4-arm)",
|
|
1435
1520
|
fn: star4Fn,
|
|
1436
|
-
period:
|
|
1437
|
-
speed: 1
|
|
1521
|
+
period: TWO_PI12,
|
|
1522
|
+
speed: 1
|
|
1438
1523
|
};
|
|
1439
1524
|
|
|
1440
1525
|
// src/curves/star7.ts
|
|
1441
|
-
var
|
|
1526
|
+
var TWO_PI13 = Math.PI * 2;
|
|
1442
1527
|
function star7Fn(t, _time, _params) {
|
|
1443
|
-
const r =
|
|
1444
|
-
Math.abs(Math.cos((7 / 2) * t)) +
|
|
1445
|
-
0.35 * Math.abs(Math.cos((21 / 2) * t)) +
|
|
1446
|
-
0.15 * Math.abs(Math.cos((35 / 2) * t));
|
|
1528
|
+
const r = Math.abs(Math.cos(7 / 2 * t)) + 0.35 * Math.abs(Math.cos(21 / 2 * t)) + 0.15 * Math.abs(Math.cos(35 / 2 * t));
|
|
1447
1529
|
return {
|
|
1448
1530
|
x: r * Math.cos(t),
|
|
1449
|
-
y: r * Math.sin(t)
|
|
1531
|
+
y: r * Math.sin(t)
|
|
1450
1532
|
};
|
|
1451
1533
|
}
|
|
1452
1534
|
var star7 = {
|
|
1453
1535
|
name: "Star (7-arm)",
|
|
1454
1536
|
fn: star7Fn,
|
|
1455
|
-
period:
|
|
1456
|
-
speed: 1
|
|
1537
|
+
period: TWO_PI13,
|
|
1538
|
+
speed: 1
|
|
1457
1539
|
};
|
|
1458
1540
|
|
|
1459
1541
|
// src/curves/index.ts
|
|
@@ -1471,58 +1553,9 @@ var curves = {
|
|
|
1471
1553
|
lissajous32,
|
|
1472
1554
|
lissajous43,
|
|
1473
1555
|
epicycloid3,
|
|
1474
|
-
lame
|
|
1556
|
+
lame
|
|
1475
1557
|
};
|
|
1476
1558
|
|
|
1477
|
-
// src/catmull-rom.ts
|
|
1478
|
-
var PERIOD = 2 * Math.PI;
|
|
1479
|
-
function catmullRom1D(p0, p1, p2, p3, u) {
|
|
1480
|
-
const u2 = u * u;
|
|
1481
|
-
const u3 = u2 * u;
|
|
1482
|
-
return (
|
|
1483
|
-
0.5 *
|
|
1484
|
-
(2 * p1 +
|
|
1485
|
-
(-p0 + p2) * u +
|
|
1486
|
-
(2 * p0 - 5 * p1 + 4 * p2 - p3) * u2 +
|
|
1487
|
-
(-p0 + 3 * p1 - 3 * p2 + p3) * u3)
|
|
1488
|
-
);
|
|
1489
|
-
}
|
|
1490
|
-
function evaluateCatmullRom(points, t) {
|
|
1491
|
-
const N = points.length;
|
|
1492
|
-
if (N === 0) {
|
|
1493
|
-
return { x: 0, y: 0 };
|
|
1494
|
-
}
|
|
1495
|
-
if (N === 1) {
|
|
1496
|
-
return { x: points[0][0], y: points[0][1] };
|
|
1497
|
-
}
|
|
1498
|
-
t = ((t % PERIOD) + PERIOD) % PERIOD;
|
|
1499
|
-
const segmentSize = PERIOD / N;
|
|
1500
|
-
let i = Math.floor(t / segmentSize);
|
|
1501
|
-
if (i >= N) {
|
|
1502
|
-
i = N - 1;
|
|
1503
|
-
}
|
|
1504
|
-
let u = (t - i * segmentSize) / segmentSize;
|
|
1505
|
-
u = Math.max(0, Math.min(1, u));
|
|
1506
|
-
const p0 = points[(i - 1 + N) % N];
|
|
1507
|
-
const p1 = points[i];
|
|
1508
|
-
const p2 = points[(i + 1) % N];
|
|
1509
|
-
const p3 = points[(i + 2) % N];
|
|
1510
|
-
return {
|
|
1511
|
-
x: catmullRom1D(p0[0], p1[0], p2[0], p3[0], u),
|
|
1512
|
-
y: catmullRom1D(p0[1], p1[1], p2[1], p3[1], u),
|
|
1513
|
-
};
|
|
1514
|
-
}
|
|
1515
|
-
function drawCurve(points) {
|
|
1516
|
-
if (points.length < 3) {
|
|
1517
|
-
throw new Error(`drawCurve requires at least 3 points, received ${points.length}.`);
|
|
1518
|
-
}
|
|
1519
|
-
return {
|
|
1520
|
-
name: "custom",
|
|
1521
|
-
fn: (t) => evaluateCatmullRom(points, t),
|
|
1522
|
-
period: PERIOD,
|
|
1523
|
-
};
|
|
1524
|
-
}
|
|
1525
|
-
|
|
1526
1559
|
// src/index.ts
|
|
1527
1560
|
function createSarmal(canvas, curveDef, options) {
|
|
1528
1561
|
const { trailLength, ...rendererOpts } = options ?? {};
|
|
@@ -1530,26 +1563,6 @@ function createSarmal(canvas, curveDef, options) {
|
|
|
1530
1563
|
return createRenderer({ canvas, engine, ...rendererOpts });
|
|
1531
1564
|
}
|
|
1532
1565
|
|
|
1533
|
-
export {
|
|
1534
|
-
artemis2,
|
|
1535
|
-
astroid,
|
|
1536
|
-
createEngine,
|
|
1537
|
-
createRenderer,
|
|
1538
|
-
createSVGRenderer,
|
|
1539
|
-
createSarmal,
|
|
1540
|
-
createSarmalSVG,
|
|
1541
|
-
curves,
|
|
1542
|
-
deltoid,
|
|
1543
|
-
drawCurve,
|
|
1544
|
-
epicycloid3,
|
|
1545
|
-
epitrochoid7,
|
|
1546
|
-
evaluateCatmullRom,
|
|
1547
|
-
lame,
|
|
1548
|
-
lissajous32,
|
|
1549
|
-
lissajous43,
|
|
1550
|
-
palettes,
|
|
1551
|
-
rose3,
|
|
1552
|
-
rose5,
|
|
1553
|
-
};
|
|
1554
|
-
//# sourceMappingURL=index.js.map
|
|
1566
|
+
export { artemis2, astroid, computeBoundaries, createEngine, createRenderer, createSVGRenderer, createSarmal, createSarmalSVG, curves, deltoid, drawCurve, epicycloid3, epitrochoid7, evaluateCatmullRom, lame, lissajous32, lissajous43, palettes, rose3, rose5 };
|
|
1555
1567
|
//# sourceMappingURL=index.js.map
|
|
1568
|
+
//# sourceMappingURL=index.js.map
|