@sarmal/core 0.19.0 → 0.22.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.
Files changed (45) hide show
  1. package/dist/auto-init.cjs +393 -18
  2. package/dist/auto-init.cjs.map +1 -1
  3. package/dist/auto-init.d.cts +4 -0
  4. package/dist/auto-init.d.ts +4 -0
  5. package/dist/auto-init.js +393 -18
  6. package/dist/auto-init.js.map +1 -1
  7. package/dist/curves/artemis2.d.cts +1 -1
  8. package/dist/curves/artemis2.d.ts +1 -1
  9. package/dist/curves/astroid.d.cts +1 -1
  10. package/dist/curves/astroid.d.ts +1 -1
  11. package/dist/curves/deltoid.d.cts +1 -1
  12. package/dist/curves/deltoid.d.ts +1 -1
  13. package/dist/curves/epicycloid3.d.cts +1 -1
  14. package/dist/curves/epicycloid3.d.ts +1 -1
  15. package/dist/curves/epitrochoid7.d.cts +1 -1
  16. package/dist/curves/epitrochoid7.d.ts +1 -1
  17. package/dist/curves/index.d.cts +1 -1
  18. package/dist/curves/index.d.ts +1 -1
  19. package/dist/curves/lame.d.cts +1 -1
  20. package/dist/curves/lame.d.ts +1 -1
  21. package/dist/curves/lissajous32.d.cts +1 -1
  22. package/dist/curves/lissajous32.d.ts +1 -1
  23. package/dist/curves/lissajous43.d.cts +1 -1
  24. package/dist/curves/lissajous43.d.ts +1 -1
  25. package/dist/curves/rose3.d.cts +1 -1
  26. package/dist/curves/rose3.d.ts +1 -1
  27. package/dist/curves/rose5.d.cts +1 -1
  28. package/dist/curves/rose5.d.ts +1 -1
  29. package/dist/curves/rose52.d.cts +1 -1
  30. package/dist/curves/rose52.d.ts +1 -1
  31. package/dist/curves/star.d.cts +1 -1
  32. package/dist/curves/star.d.ts +1 -1
  33. package/dist/curves/star4.d.cts +1 -1
  34. package/dist/curves/star4.d.ts +1 -1
  35. package/dist/curves/star7.d.cts +1 -1
  36. package/dist/curves/star7.d.ts +1 -1
  37. package/dist/index.cjs +77 -2
  38. package/dist/index.cjs.map +1 -1
  39. package/dist/index.d.cts +45 -3
  40. package/dist/index.d.ts +45 -3
  41. package/dist/index.js +77 -2
  42. package/dist/index.js.map +1 -1
  43. package/dist/{types-frtEoAq6.d.cts → types-DVerJ9cl.d.cts} +4 -0
  44. package/dist/{types-frtEoAq6.d.ts → types-DVerJ9cl.d.ts} +4 -0
  45. package/package.json +1 -1
package/dist/index.d.cts CHANGED
@@ -4,16 +4,16 @@ import {
4
4
  S as SarmalInstance,
5
5
  C as CurveDef,
6
6
  R as RendererOptions,
7
+ P as Point,
7
8
  a as SarmalOptions,
8
- } from "./types-frtEoAq6.cjs";
9
+ } from "./types-DVerJ9cl.cjs";
9
10
  export {
10
11
  J as JumpOptions,
11
- P as Point,
12
12
  b as RuntimeRenderOptions,
13
13
  c as SeekOptions,
14
14
  T as TrailColor,
15
15
  d as TrailStyle,
16
- } from "./types-frtEoAq6.cjs";
16
+ } from "./types-DVerJ9cl.cjs";
17
17
  export { CurveName, curves } from "./curves/index.cjs";
18
18
  export { artemis2 } from "./curves/artemis2.cjs";
19
19
  export { astroid } from "./curves/astroid.cjs";
@@ -92,6 +92,45 @@ declare function createEngine(curveDef: CurveDef, trailLength?: number): Engine;
92
92
  */
93
93
  declare function createRenderer(options: RendererOptions): SarmalInstance;
94
94
 
95
+ /**
96
+ * Evaluates a closed Catmull-Rom spline through every point in `points`
97
+ *
98
+ * The spline treats `points` as a **closed loop**
99
+ * The last point wraps back to the first,
100
+ * and each segment uses a phantom predecessor / successor so the
101
+ * curve passes exactly through every control point.
102
+ *
103
+ * @param points At least 1 point. An empty array yields `(0, 0)`. A single point returns that point for every `t`
104
+ * @param t Parametric position along the closed loop. Wraps into `[0, 2π)` automatically, so values outside that range are remapped rather than rejected
105
+ * @returns The `(x, y)` position on the spline at time `t`
106
+ */
107
+ declare function evaluateCatmullRom(points: Array<[number, number]>, t: number): Point;
108
+ /**
109
+ * The returned curve definition produces a closed Catmull-Rom spline that
110
+ * passes through every point in order, looping back from the last point to the first.
111
+ *
112
+ * @param points Array of control points in **normalized `[−1, 1]` space**,
113
+ * matching the playground's draw-mode coordinate system.
114
+ * ! Must contain at least 3 points.
115
+ * @returns A `CurveDef` with `period: 2π` and the spline evaluator as its `fn`.
116
+ * `name` is set to `"custom"`.
117
+ * @throws If `points` has fewer than 3 entries.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * import { createSarmal, drawCurve } from '@sarmal/core'
122
+ *
123
+ * const curve = drawCurve([
124
+ * [-0.5, 0.3],
125
+ * [ 0.2, -0.8],
126
+ * [ 0.7, 0.4],
127
+ * ])
128
+ *
129
+ * createSarmal(canvas, curve)
130
+ * ```
131
+ */
132
+ declare function drawCurve(points: Array<[number, number]>): CurveDef;
133
+
95
134
  /**
96
135
  * Creates a sarmal animation on a canvas element
97
136
  *
@@ -116,6 +155,7 @@ export {
116
155
  BaseRendererOptions,
117
156
  CurveDef,
118
157
  Engine,
158
+ Point,
119
159
  RendererOptions,
120
160
  type SVGRendererOptions,
121
161
  type SVGSarmalOptions,
@@ -127,5 +167,7 @@ export {
127
167
  createSVGRenderer,
128
168
  createSarmal,
129
169
  createSarmalSVG,
170
+ drawCurve,
171
+ evaluateCatmullRom,
130
172
  palettes,
131
173
  };
package/dist/index.d.ts CHANGED
@@ -4,16 +4,16 @@ import {
4
4
  S as SarmalInstance,
5
5
  C as CurveDef,
6
6
  R as RendererOptions,
7
+ P as Point,
7
8
  a as SarmalOptions,
8
- } from "./types-frtEoAq6.js";
9
+ } from "./types-DVerJ9cl.js";
9
10
  export {
10
11
  J as JumpOptions,
11
- P as Point,
12
12
  b as RuntimeRenderOptions,
13
13
  c as SeekOptions,
14
14
  T as TrailColor,
15
15
  d as TrailStyle,
16
- } from "./types-frtEoAq6.js";
16
+ } from "./types-DVerJ9cl.js";
17
17
  export { CurveName, curves } from "./curves/index.js";
18
18
  export { artemis2 } from "./curves/artemis2.js";
19
19
  export { astroid } from "./curves/astroid.js";
@@ -92,6 +92,45 @@ declare function createEngine(curveDef: CurveDef, trailLength?: number): Engine;
92
92
  */
93
93
  declare function createRenderer(options: RendererOptions): SarmalInstance;
94
94
 
95
+ /**
96
+ * Evaluates a closed Catmull-Rom spline through every point in `points`
97
+ *
98
+ * The spline treats `points` as a **closed loop**
99
+ * The last point wraps back to the first,
100
+ * and each segment uses a phantom predecessor / successor so the
101
+ * curve passes exactly through every control point.
102
+ *
103
+ * @param points At least 1 point. An empty array yields `(0, 0)`. A single point returns that point for every `t`
104
+ * @param t Parametric position along the closed loop. Wraps into `[0, 2π)` automatically, so values outside that range are remapped rather than rejected
105
+ * @returns The `(x, y)` position on the spline at time `t`
106
+ */
107
+ declare function evaluateCatmullRom(points: Array<[number, number]>, t: number): Point;
108
+ /**
109
+ * The returned curve definition produces a closed Catmull-Rom spline that
110
+ * passes through every point in order, looping back from the last point to the first.
111
+ *
112
+ * @param points Array of control points in **normalized `[−1, 1]` space**,
113
+ * matching the playground's draw-mode coordinate system.
114
+ * ! Must contain at least 3 points.
115
+ * @returns A `CurveDef` with `period: 2π` and the spline evaluator as its `fn`.
116
+ * `name` is set to `"custom"`.
117
+ * @throws If `points` has fewer than 3 entries.
118
+ *
119
+ * @example
120
+ * ```ts
121
+ * import { createSarmal, drawCurve } from '@sarmal/core'
122
+ *
123
+ * const curve = drawCurve([
124
+ * [-0.5, 0.3],
125
+ * [ 0.2, -0.8],
126
+ * [ 0.7, 0.4],
127
+ * ])
128
+ *
129
+ * createSarmal(canvas, curve)
130
+ * ```
131
+ */
132
+ declare function drawCurve(points: Array<[number, number]>): CurveDef;
133
+
95
134
  /**
96
135
  * Creates a sarmal animation on a canvas element
97
136
  *
@@ -116,6 +155,7 @@ export {
116
155
  BaseRendererOptions,
117
156
  CurveDef,
118
157
  Engine,
158
+ Point,
119
159
  RendererOptions,
120
160
  type SVGRendererOptions,
121
161
  type SVGSarmalOptions,
@@ -127,5 +167,7 @@ export {
127
167
  createSVGRenderer,
128
168
  createSarmal,
129
169
  createSarmalSVG,
170
+ drawCurve,
171
+ evaluateCatmullRom,
130
172
  palettes,
131
173
  };
package/dist/index.js CHANGED
@@ -426,6 +426,7 @@ var RENDER_OPTION_KEYS = /* @__PURE__ */ new Set([
426
426
  "headColor",
427
427
  "skeletonColor",
428
428
  "trailStyle",
429
+ "headRadius",
429
430
  ]);
430
431
  function validateRenderOptions(partial) {
431
432
  for (const key of Object.keys(partial)) {
@@ -445,6 +446,9 @@ function validateRenderOptions(partial) {
445
446
  if (partial.trailStyle !== void 0) {
446
447
  assertTrailStyle(partial.trailStyle);
447
448
  }
449
+ if (partial.headRadius !== void 0) {
450
+ assertHeadRadius(partial.headRadius);
451
+ }
448
452
  }
449
453
  function assertTrailColor(value) {
450
454
  if (typeof value === "string") {
@@ -502,6 +506,18 @@ function assertTrailStyle(value) {
502
506
  );
503
507
  }
504
508
  }
509
+ function assertHeadRadius(value) {
510
+ if (typeof value !== "number") {
511
+ throw new TypeError(
512
+ `[sarmal] setRenderOptions: headRadius must be a number, got ${JSON.stringify(value)}`,
513
+ );
514
+ }
515
+ if (!Number.isFinite(value) || value <= 0) {
516
+ throw new TypeError(
517
+ `[sarmal] setRenderOptions: headRadius must be a finite positive number, got ${value}`,
518
+ );
519
+ }
520
+ }
505
521
  function resolveTrailMainColor(trailColor) {
506
522
  return typeof trailColor === "string" ? trailColor : trailColor[0];
507
523
  }
@@ -569,6 +585,7 @@ function createRenderer(options) {
569
585
  setupCanvas();
570
586
  let logicalWidth = canvas.width / dpr;
571
587
  let logicalHeight = canvas.height / dpr;
588
+ let headRadius = options.headRadius ?? getHeadDotRadius(logicalWidth, logicalHeight);
572
589
  let skeleton = [];
573
590
  let skeletonCanvas = null;
574
591
  let trail = [];
@@ -685,7 +702,7 @@ function createRenderer(options) {
685
702
  }
686
703
  const x = head.x * scale + offsetX;
687
704
  const y = head.y * scale + offsetY;
688
- const r = options.headRadius ?? getHeadDotRadius(logicalWidth, logicalHeight);
705
+ const r = headRadius;
689
706
  ctx.fillStyle = headColor;
690
707
  ctx.beginPath();
691
708
  ctx.arc(x, y, r, 0, Math.PI * 2);
@@ -814,6 +831,9 @@ function createRenderer(options) {
814
831
  if (partial.headColor !== void 0) {
815
832
  userHeadColor = partial.headColor;
816
833
  }
834
+ if (partial.headRadius !== void 0) {
835
+ headRadius = partial.headRadius;
836
+ }
817
837
  if (userHeadColor === null) {
818
838
  headColor = resolveHeadColor(trailColor, trailStyle);
819
839
  } else {
@@ -871,12 +891,12 @@ function createSVGRenderer(options) {
871
891
  let skeletonColor = options.skeletonColor ?? "#ffffff";
872
892
  let userHeadColor = options.headColor ?? null;
873
893
  let headColor = userHeadColor ?? resolveHeadColor(trailColor, trailStyle);
894
+ let headRadius = options.headRadius ?? 1.5;
874
895
  let trailSolid = resolveTrailMainColor(trailColor);
875
896
  let trailPalette = resolveTrailPalette(trailColor);
876
897
  const ariaLabel = options.ariaLabel ?? "Loading";
877
898
  warnIfTrailColorMismatch(trailColor, trailStyle);
878
899
  const viewSize = 100;
879
- const headRadius = options.headRadius ?? 1.5;
880
900
  const svgTrailMinWidth = 0.25;
881
901
  const svgTrailMaxWidth = 1.25;
882
902
  const svgSkeletonStrokeWidth = "0.75";
@@ -1152,6 +1172,10 @@ function createSVGRenderer(options) {
1152
1172
  if (partial.headColor !== void 0) {
1153
1173
  userHeadColor = partial.headColor;
1154
1174
  }
1175
+ if (partial.headRadius !== void 0) {
1176
+ headRadius = partial.headRadius;
1177
+ headCircle.setAttribute("r", String(headRadius));
1178
+ }
1155
1179
  if (userHeadColor === null) {
1156
1180
  headColor = resolveHeadColor(trailColor, trailStyle);
1157
1181
  } else {
@@ -1442,6 +1466,55 @@ var curves = {
1442
1466
  lame,
1443
1467
  };
1444
1468
 
1469
+ // src/catmull-rom.ts
1470
+ var PERIOD = 2 * Math.PI;
1471
+ function catmullRom1D(p0, p1, p2, p3, u) {
1472
+ const u2 = u * u;
1473
+ const u3 = u2 * u;
1474
+ return (
1475
+ 0.5 *
1476
+ (2 * p1 +
1477
+ (-p0 + p2) * u +
1478
+ (2 * p0 - 5 * p1 + 4 * p2 - p3) * u2 +
1479
+ (-p0 + 3 * p1 - 3 * p2 + p3) * u3)
1480
+ );
1481
+ }
1482
+ function evaluateCatmullRom(points, t) {
1483
+ const N = points.length;
1484
+ if (N === 0) {
1485
+ return { x: 0, y: 0 };
1486
+ }
1487
+ if (N === 1) {
1488
+ return { x: points[0][0], y: points[0][1] };
1489
+ }
1490
+ t = ((t % PERIOD) + PERIOD) % PERIOD;
1491
+ const segmentSize = PERIOD / N;
1492
+ let i = Math.floor(t / segmentSize);
1493
+ if (i >= N) {
1494
+ i = N - 1;
1495
+ }
1496
+ let u = (t - i * segmentSize) / segmentSize;
1497
+ u = Math.max(0, Math.min(1, u));
1498
+ const p0 = points[(i - 1 + N) % N];
1499
+ const p1 = points[i];
1500
+ const p2 = points[(i + 1) % N];
1501
+ const p3 = points[(i + 2) % N];
1502
+ return {
1503
+ x: catmullRom1D(p0[0], p1[0], p2[0], p3[0], u),
1504
+ y: catmullRom1D(p0[1], p1[1], p2[1], p3[1], u),
1505
+ };
1506
+ }
1507
+ function drawCurve(points) {
1508
+ if (points.length < 3) {
1509
+ throw new Error(`drawCurve requires at least 3 points, received ${points.length}.`);
1510
+ }
1511
+ return {
1512
+ name: "custom",
1513
+ fn: (t) => evaluateCatmullRom(points, t),
1514
+ period: PERIOD,
1515
+ };
1516
+ }
1517
+
1445
1518
  // src/index.ts
1446
1519
  function createSarmal(canvas, curveDef, options) {
1447
1520
  const { trailLength, ...rendererOpts } = options ?? {};
@@ -1459,8 +1532,10 @@ export {
1459
1532
  createSarmalSVG,
1460
1533
  curves,
1461
1534
  deltoid,
1535
+ drawCurve,
1462
1536
  epicycloid3,
1463
1537
  epitrochoid7,
1538
+ evaluateCatmullRom,
1464
1539
  lame,
1465
1540
  lissajous32,
1466
1541
  lissajous43,