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