@sarmal/core 0.37.4 → 0.38.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 (50) hide show
  1. package/dist/auto-init.cjs +111 -14
  2. package/dist/auto-init.cjs.map +1 -1
  3. package/dist/auto-init.js +111 -14
  4. package/dist/auto-init.js.map +1 -1
  5. package/dist/cli.js.map +1 -1
  6. package/dist/curves/artemis2.d.cts +1 -1
  7. package/dist/curves/artemis2.d.ts +1 -1
  8. package/dist/curves/astroid.d.cts +1 -1
  9. package/dist/curves/astroid.d.ts +1 -1
  10. package/dist/curves/deltoid.d.cts +1 -1
  11. package/dist/curves/deltoid.d.ts +1 -1
  12. package/dist/curves/epicycloid3.d.cts +1 -1
  13. package/dist/curves/epicycloid3.d.ts +1 -1
  14. package/dist/curves/epitrochoid7.d.cts +1 -1
  15. package/dist/curves/epitrochoid7.d.ts +1 -1
  16. package/dist/curves/index.d.cts +1 -1
  17. package/dist/curves/index.d.ts +1 -1
  18. package/dist/curves/lame.d.cts +1 -1
  19. package/dist/curves/lame.d.ts +1 -1
  20. package/dist/curves/lissajous32.d.cts +1 -1
  21. package/dist/curves/lissajous32.d.ts +1 -1
  22. package/dist/curves/lissajous43.d.cts +1 -1
  23. package/dist/curves/lissajous43.d.ts +1 -1
  24. package/dist/curves/rose3.d.cts +1 -1
  25. package/dist/curves/rose3.d.ts +1 -1
  26. package/dist/curves/rose5.d.cts +1 -1
  27. package/dist/curves/rose5.d.ts +1 -1
  28. package/dist/curves/rose52.d.cts +1 -1
  29. package/dist/curves/rose52.d.ts +1 -1
  30. package/dist/curves/star.d.cts +1 -1
  31. package/dist/curves/star.d.ts +1 -1
  32. package/dist/curves/star4.d.cts +1 -1
  33. package/dist/curves/star4.d.ts +1 -1
  34. package/dist/curves/star7.d.cts +1 -1
  35. package/dist/curves/star7.d.ts +1 -1
  36. package/dist/index.cjs +111 -14
  37. package/dist/index.cjs.map +1 -1
  38. package/dist/index.d.cts +3 -3
  39. package/dist/index.d.ts +3 -3
  40. package/dist/index.js +111 -14
  41. package/dist/index.js.map +1 -1
  42. package/dist/{renderer-shared-DElz98PT.d.ts → renderer-shared-2tEwOWJm.d.ts} +1 -1
  43. package/dist/{renderer-shared-9Xf6sIlx.d.cts → renderer-shared-Bh33A5Av.d.cts} +1 -1
  44. package/dist/terminal.cjs.map +1 -1
  45. package/dist/terminal.d.cts +2 -2
  46. package/dist/terminal.d.ts +2 -2
  47. package/dist/terminal.js.map +1 -1
  48. package/dist/{types-D_ERoVvi.d.cts → types-CmPFR9U3.d.cts} +5 -1
  49. package/dist/{types-D_ERoVvi.d.ts → types-CmPFR9U3.d.ts} +5 -1
  50. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { C as CurveDef } from '../types-D_ERoVvi.cjs';
1
+ import { C as CurveDef } from '../types-CmPFR9U3.cjs';
2
2
 
3
3
  /**
4
4
  * Lissajous curve with frequency ratio 3:2
@@ -1,4 +1,4 @@
1
- import { C as CurveDef } from '../types-D_ERoVvi.js';
1
+ import { C as CurveDef } from '../types-CmPFR9U3.js';
2
2
 
3
3
  /**
4
4
  * Lissajous curve with frequency ratio 3:2
@@ -1,4 +1,4 @@
1
- import { C as CurveDef } from '../types-D_ERoVvi.cjs';
1
+ import { C as CurveDef } from '../types-CmPFR9U3.cjs';
2
2
 
3
3
  /**
4
4
  * Lissajous curve with frequency ratio 4:3
@@ -1,4 +1,4 @@
1
- import { C as CurveDef } from '../types-D_ERoVvi.js';
1
+ import { C as CurveDef } from '../types-CmPFR9U3.js';
2
2
 
3
3
  /**
4
4
  * Lissajous curve with frequency ratio 4:3
@@ -1,4 +1,4 @@
1
- import { C as CurveDef } from '../types-D_ERoVvi.cjs';
1
+ import { C as CurveDef } from '../types-CmPFR9U3.cjs';
2
2
 
3
3
  /**
4
4
  * Rose curve with 3 petals
@@ -1,4 +1,4 @@
1
- import { C as CurveDef } from '../types-D_ERoVvi.js';
1
+ import { C as CurveDef } from '../types-CmPFR9U3.js';
2
2
 
3
3
  /**
4
4
  * Rose curve with 3 petals
@@ -1,4 +1,4 @@
1
- import { C as CurveDef } from '../types-D_ERoVvi.cjs';
1
+ import { C as CurveDef } from '../types-CmPFR9U3.cjs';
2
2
 
3
3
  /**
4
4
  * Rose curve with 5 petals
@@ -1,4 +1,4 @@
1
- import { C as CurveDef } from '../types-D_ERoVvi.js';
1
+ import { C as CurveDef } from '../types-CmPFR9U3.js';
2
2
 
3
3
  /**
4
4
  * Rose curve with 5 petals
@@ -1,4 +1,4 @@
1
- import { C as CurveDef } from '../types-D_ERoVvi.cjs';
1
+ import { C as CurveDef } from '../types-CmPFR9U3.cjs';
2
2
 
3
3
  /**
4
4
  * Rose curve with n=5/2 that traces 5 petals over two full revolutions
@@ -1,4 +1,4 @@
1
- import { C as CurveDef } from '../types-D_ERoVvi.js';
1
+ import { C as CurveDef } from '../types-CmPFR9U3.js';
2
2
 
3
3
  /**
4
4
  * Rose curve with n=5/2 that traces 5 petals over two full revolutions
@@ -1,4 +1,4 @@
1
- import { C as CurveDef } from '../types-D_ERoVvi.cjs';
1
+ import { C as CurveDef } from '../types-CmPFR9U3.cjs';
2
2
 
3
3
  /**
4
4
  * 5-pointed star based on Fourier harmonics.
@@ -1,4 +1,4 @@
1
- import { C as CurveDef } from '../types-D_ERoVvi.js';
1
+ import { C as CurveDef } from '../types-CmPFR9U3.js';
2
2
 
3
3
  /**
4
4
  * 5-pointed star based on Fourier harmonics.
@@ -1,4 +1,4 @@
1
- import { C as CurveDef } from '../types-D_ERoVvi.cjs';
1
+ import { C as CurveDef } from '../types-CmPFR9U3.cjs';
2
2
 
3
3
  /**
4
4
  * 4-pointed star based on Fourier harmonics.
@@ -1,4 +1,4 @@
1
- import { C as CurveDef } from '../types-D_ERoVvi.js';
1
+ import { C as CurveDef } from '../types-CmPFR9U3.js';
2
2
 
3
3
  /**
4
4
  * 4-pointed star based on Fourier harmonics.
@@ -1,4 +1,4 @@
1
- import { C as CurveDef } from '../types-D_ERoVvi.cjs';
1
+ import { C as CurveDef } from '../types-CmPFR9U3.cjs';
2
2
 
3
3
  /**
4
4
  * 7-pointed star based on Fourier harmonics.
@@ -1,4 +1,4 @@
1
- import { C as CurveDef } from '../types-D_ERoVvi.js';
1
+ import { C as CurveDef } from '../types-CmPFR9U3.js';
2
2
 
3
3
  /**
4
4
  * 7-pointed star based on Fourier harmonics.
package/dist/index.cjs CHANGED
@@ -364,15 +364,42 @@ function computeBoundaries(pts, logicalWidth, logicalHeight, minPaddingPx = FIT_
364
364
  offsetY: (logicalHeight - h * scale) / 2 - minY * scale
365
365
  };
366
366
  }
367
- function enginePassthroughs(engine) {
367
+ var DESTROYED_ERROR = "[sarmal] Instance has been destroyed and cannot be used again. Call pause() instead of destroy() for temporary suspension.";
368
+ function enginePassthroughs(engine, isDestroyed) {
369
+ function guard() {
370
+ if (isDestroyed()) {
371
+ throw new Error(DESTROYED_ERROR);
372
+ }
373
+ }
368
374
  return {
369
- jump: engine.jump,
370
- seek: engine.seek,
371
- setSpeed: engine.setSpeed,
372
- getSpeed: engine.getSpeed,
373
- resetSpeed: engine.resetSpeed,
374
- setSpeedOver: engine.setSpeedOver,
375
- getSarmalSkeleton: engine.getSarmalSkeleton
375
+ jump(phase, options) {
376
+ guard();
377
+ engine.jump(phase, options);
378
+ },
379
+ seek(phase, options) {
380
+ guard();
381
+ engine.seek(phase, options);
382
+ },
383
+ setSpeed(speed) {
384
+ guard();
385
+ engine.setSpeed(speed);
386
+ },
387
+ getSpeed() {
388
+ guard();
389
+ return engine.getSpeed();
390
+ },
391
+ resetSpeed() {
392
+ guard();
393
+ engine.resetSpeed();
394
+ },
395
+ setSpeedOver(speed, duration) {
396
+ guard();
397
+ return engine.setSpeedOver(speed, duration);
398
+ },
399
+ getSarmalSkeleton() {
400
+ guard();
401
+ return engine.getSarmalSkeleton();
402
+ }
376
403
  };
377
404
  }
378
405
  var palettes = {
@@ -743,6 +770,7 @@ function createRenderer(options) {
743
770
  let animationId = null;
744
771
  let lastTime = 0;
745
772
  let pausedByVisibility = false;
773
+ let destroyed = false;
746
774
  let morphResolve = null;
747
775
  let morphReject = null;
748
776
  let morphDurationMs = DEFAULT_MORPH_DURATION_MS;
@@ -914,6 +942,9 @@ function createRenderer(options) {
914
942
  const shouldAutoStart = options.autoStart !== false;
915
943
  const instance = {
916
944
  play() {
945
+ if (destroyed) {
946
+ throw new Error(DESTROYED_ERROR);
947
+ }
917
948
  if (animationId !== null) {
918
949
  return;
919
950
  }
@@ -921,6 +952,9 @@ function createRenderer(options) {
921
952
  loop();
922
953
  },
923
954
  pause() {
955
+ if (destroyed) {
956
+ throw new Error(DESTROYED_ERROR);
957
+ }
924
958
  if (animationId === null) {
925
959
  return;
926
960
  }
@@ -929,24 +963,36 @@ function createRenderer(options) {
929
963
  engine.cancelSpeedTransition();
930
964
  },
931
965
  reset() {
966
+ if (destroyed) {
967
+ throw new Error(DESTROYED_ERROR);
968
+ }
932
969
  engine.reset();
933
970
  trail = [];
934
971
  head = null;
935
972
  },
936
973
  destroy() {
974
+ if (destroyed) {
975
+ return;
976
+ }
977
+ destroyed = true;
937
978
  if (animationId !== null) {
938
979
  cancelAnimationFrame(animationId);
939
980
  animationId = null;
940
981
  }
941
982
  document.removeEventListener("visibilitychange", handleVisibilityChange);
983
+ engine.cancelSpeedTransition();
942
984
  if (morphReject !== null) {
943
- morphReject(new Error("Instance destroyed during morph"));
985
+ morphReject(new Error("[sarmal] Instance destroyed during morph"));
944
986
  morphResolve = null;
945
987
  morphReject = null;
946
988
  }
989
+ ctx.clearRect(0, 0, logicalWidth, logicalHeight);
947
990
  },
948
- ...enginePassthroughs(engine),
991
+ ...enginePassthroughs(engine, () => destroyed),
949
992
  morphTo(target, options2) {
993
+ if (destroyed) {
994
+ throw new Error(DESTROYED_ERROR);
995
+ }
950
996
  if (morphResolve !== null) {
951
997
  engine.completeMorph();
952
998
  morphResolve();
@@ -963,6 +1009,9 @@ function createRenderer(options) {
963
1009
  });
964
1010
  },
965
1011
  setRenderOptions(partial) {
1012
+ if (destroyed) {
1013
+ throw new Error(DESTROYED_ERROR);
1014
+ }
966
1015
  validateRenderOptions(partial);
967
1016
  if (partial.trailColor !== void 0) {
968
1017
  trailColor = partial.trailColor;
@@ -1217,6 +1266,7 @@ function createSVGRenderer(options) {
1217
1266
  let animationId = null;
1218
1267
  let lastTime = 0;
1219
1268
  let pausedByVisibility = false;
1269
+ let destroyed = false;
1220
1270
  const prefersReducedMotion = typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
1221
1271
  let morphResolve = null;
1222
1272
  let morphReject = null;
@@ -1285,6 +1335,9 @@ function createSVGRenderer(options) {
1285
1335
  const shouldAutoStart = options.autoStart !== false;
1286
1336
  const instance = {
1287
1337
  play() {
1338
+ if (destroyed) {
1339
+ throw new Error(DESTROYED_ERROR);
1340
+ }
1288
1341
  if (animationId !== null) {
1289
1342
  return;
1290
1343
  }
@@ -1292,6 +1345,9 @@ function createSVGRenderer(options) {
1292
1345
  loop();
1293
1346
  },
1294
1347
  pause() {
1348
+ if (destroyed) {
1349
+ throw new Error(DESTROYED_ERROR);
1350
+ }
1295
1351
  if (animationId === null) {
1296
1352
  return;
1297
1353
  }
@@ -1300,23 +1356,34 @@ function createSVGRenderer(options) {
1300
1356
  engine.cancelSpeedTransition();
1301
1357
  },
1302
1358
  reset() {
1359
+ if (destroyed) {
1360
+ throw new Error(DESTROYED_ERROR);
1361
+ }
1303
1362
  engine.reset();
1304
1363
  },
1305
1364
  destroy() {
1365
+ if (destroyed) {
1366
+ return;
1367
+ }
1368
+ destroyed = true;
1306
1369
  if (animationId !== null) {
1307
1370
  cancelAnimationFrame(animationId);
1308
1371
  animationId = null;
1309
1372
  }
1310
1373
  document.removeEventListener("visibilitychange", handleVisibilityChange);
1374
+ engine.cancelSpeedTransition();
1311
1375
  if (morphReject !== null) {
1312
- morphReject(new Error("Instance destroyed during morph"));
1376
+ morphReject(new Error("[sarmal] Instance destroyed during morph"));
1313
1377
  morphResolve = null;
1314
1378
  morphReject = null;
1315
1379
  }
1316
1380
  group.remove();
1317
1381
  },
1318
- ...enginePassthroughs(engine),
1382
+ ...enginePassthroughs(engine, () => destroyed),
1319
1383
  morphTo(target, options2) {
1384
+ if (destroyed) {
1385
+ throw new Error(DESTROYED_ERROR);
1386
+ }
1320
1387
  if (morphResolve !== null) {
1321
1388
  engine.completeMorph();
1322
1389
  morphResolve();
@@ -1342,6 +1409,9 @@ function createSVGRenderer(options) {
1342
1409
  });
1343
1410
  },
1344
1411
  setRenderOptions(partial) {
1412
+ if (destroyed) {
1413
+ throw new Error(DESTROYED_ERROR);
1414
+ }
1345
1415
  validateRenderOptions(partial);
1346
1416
  const prevTrailStyle = trailStyle;
1347
1417
  if (partial.trailColor !== void 0) {
@@ -1471,6 +1541,7 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
1471
1541
  let animationId = null;
1472
1542
  let lastTime = 0;
1473
1543
  let pausedByVisibility = false;
1544
+ let destroyed = false;
1474
1545
  let morphResolve = null;
1475
1546
  let morphReject = null;
1476
1547
  let morphDurationMs = DEFAULT_MORPH_DURATION_MS;
@@ -1724,6 +1795,9 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
1724
1795
  const instance = {
1725
1796
  /** Starts the animation loop. Does nothing if already running. */
1726
1797
  play() {
1798
+ if (destroyed) {
1799
+ throw new Error(DESTROYED_ERROR);
1800
+ }
1727
1801
  if (animationId !== null) {
1728
1802
  return;
1729
1803
  }
@@ -1732,6 +1806,9 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
1732
1806
  },
1733
1807
  /** Pauses the animation loop. Preserves current trail state. */
1734
1808
  pause() {
1809
+ if (destroyed) {
1810
+ throw new Error(DESTROYED_ERROR);
1811
+ }
1735
1812
  if (animationId === null) {
1736
1813
  return;
1737
1814
  }
@@ -1741,29 +1818,46 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
1741
1818
  },
1742
1819
  /** Resets the animation to the start of the curve and clears the grid. */
1743
1820
  reset() {
1821
+ if (destroyed) {
1822
+ throw new Error(DESTROYED_ERROR);
1823
+ }
1744
1824
  engine.reset();
1745
1825
  grid.fill(0);
1746
1826
  },
1747
- /** Stops the animation and removes all event listeners. */
1827
+ /**
1828
+ * Permanently stops the animation and clears the visual output.
1829
+ * Calling any method on a destroyed instance throws an error.
1830
+ * `destroy()` is idempotent — calling it multiple times is safe.
1831
+ */
1748
1832
  destroy() {
1833
+ if (destroyed) {
1834
+ return;
1835
+ }
1836
+ destroyed = true;
1749
1837
  if (animationId !== null) {
1750
1838
  cancelAnimationFrame(animationId);
1751
1839
  animationId = null;
1752
1840
  }
1753
1841
  document.removeEventListener("visibilitychange", handleVisibilityChange);
1842
+ engine.cancelSpeedTransition();
1754
1843
  if (morphReject !== null) {
1755
1844
  morphReject(new Error("[sarmal] Instance destroyed during morph"));
1756
1845
  morphResolve = null;
1757
1846
  morphReject = null;
1758
1847
  }
1848
+ grid.fill(0);
1849
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
1759
1850
  },
1760
- ...enginePassthroughs(engine),
1851
+ ...enginePassthroughs(engine, () => destroyed),
1761
1852
  /**
1762
1853
  * Smoothly transitions from the current curve to `target`.
1763
1854
  * If a morph is already in progress, it is snapped to completion before the new one starts.
1764
1855
  * @returns A Promise that resolves when the transition finishes.
1765
1856
  */
1766
1857
  morphTo(target, opts) {
1858
+ if (destroyed) {
1859
+ throw new Error(DESTROYED_ERROR);
1860
+ }
1767
1861
  if (morphResolve !== null) {
1768
1862
  completeMorphNow();
1769
1863
  }
@@ -1783,6 +1877,9 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
1783
1877
  * ! Validation fails the entire call if any field is invalid, leaving options unchanged.
1784
1878
  */
1785
1879
  setRenderOptions(partial) {
1880
+ if (destroyed) {
1881
+ throw new Error(DESTROYED_ERROR);
1882
+ }
1786
1883
  validateBaseRenderOptions(partial);
1787
1884
  let needsRebuildBg = false;
1788
1885
  if (partial.trailColor !== void 0) {