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