@sarmal/core 0.19.0 → 0.20.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/index.d.cts CHANGED
@@ -4,11 +4,11 @@ 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
9
  } from "./types-frtEoAq6.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,
@@ -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,11 +4,11 @@ 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
9
  } from "./types-frtEoAq6.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,
@@ -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
@@ -1442,6 +1442,55 @@ var curves = {
1442
1442
  lame,
1443
1443
  };
1444
1444
 
1445
+ // src/catmull-rom.ts
1446
+ var PERIOD = 2 * Math.PI;
1447
+ function catmullRom1D(p0, p1, p2, p3, u) {
1448
+ const u2 = u * u;
1449
+ const u3 = u2 * u;
1450
+ return (
1451
+ 0.5 *
1452
+ (2 * p1 +
1453
+ (-p0 + p2) * u +
1454
+ (2 * p0 - 5 * p1 + 4 * p2 - p3) * u2 +
1455
+ (-p0 + 3 * p1 - 3 * p2 + p3) * u3)
1456
+ );
1457
+ }
1458
+ function evaluateCatmullRom(points, t) {
1459
+ const N = points.length;
1460
+ if (N === 0) {
1461
+ return { x: 0, y: 0 };
1462
+ }
1463
+ if (N === 1) {
1464
+ return { x: points[0][0], y: points[0][1] };
1465
+ }
1466
+ t = ((t % PERIOD) + PERIOD) % PERIOD;
1467
+ const segmentSize = PERIOD / N;
1468
+ let i = Math.floor(t / segmentSize);
1469
+ if (i >= N) {
1470
+ i = N - 1;
1471
+ }
1472
+ let u = (t - i * segmentSize) / segmentSize;
1473
+ u = Math.max(0, Math.min(1, u));
1474
+ const p0 = points[(i - 1 + N) % N];
1475
+ const p1 = points[i];
1476
+ const p2 = points[(i + 1) % N];
1477
+ const p3 = points[(i + 2) % N];
1478
+ return {
1479
+ x: catmullRom1D(p0[0], p1[0], p2[0], p3[0], u),
1480
+ y: catmullRom1D(p0[1], p1[1], p2[1], p3[1], u),
1481
+ };
1482
+ }
1483
+ function drawCurve(points) {
1484
+ if (points.length < 3) {
1485
+ throw new Error(`drawCurve requires at least 3 points, received ${points.length}.`);
1486
+ }
1487
+ return {
1488
+ name: "custom",
1489
+ fn: (t) => evaluateCatmullRom(points, t),
1490
+ period: PERIOD,
1491
+ };
1492
+ }
1493
+
1445
1494
  // src/index.ts
1446
1495
  function createSarmal(canvas, curveDef, options) {
1447
1496
  const { trailLength, ...rendererOpts } = options ?? {};
@@ -1459,8 +1508,10 @@ export {
1459
1508
  createSarmalSVG,
1460
1509
  curves,
1461
1510
  deltoid,
1511
+ drawCurve,
1462
1512
  epicycloid3,
1463
1513
  epitrochoid7,
1514
+ evaluateCatmullRom,
1464
1515
  lame,
1465
1516
  lissajous32,
1466
1517
  lissajous43,