@sarmal/core 0.37.1 → 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.
- package/README.md +4 -4
- package/dist/auto-init.cjs +111 -14
- package/dist/auto-init.cjs.map +1 -1
- package/dist/auto-init.js +111 -14
- package/dist/auto-init.js.map +1 -1
- package/dist/cli.js.map +1 -1
- package/dist/curves/artemis2.d.cts +1 -1
- package/dist/curves/artemis2.d.ts +1 -1
- package/dist/curves/astroid.d.cts +1 -1
- package/dist/curves/astroid.d.ts +1 -1
- package/dist/curves/deltoid.d.cts +1 -1
- package/dist/curves/deltoid.d.ts +1 -1
- package/dist/curves/epicycloid3.d.cts +1 -1
- package/dist/curves/epicycloid3.d.ts +1 -1
- package/dist/curves/epitrochoid7.d.cts +1 -1
- package/dist/curves/epitrochoid7.d.ts +1 -1
- package/dist/curves/index.d.cts +1 -1
- package/dist/curves/index.d.ts +1 -1
- package/dist/curves/lame.d.cts +1 -1
- package/dist/curves/lame.d.ts +1 -1
- package/dist/curves/lissajous32.d.cts +1 -1
- package/dist/curves/lissajous32.d.ts +1 -1
- package/dist/curves/lissajous43.d.cts +1 -1
- package/dist/curves/lissajous43.d.ts +1 -1
- package/dist/curves/rose3.d.cts +1 -1
- package/dist/curves/rose3.d.ts +1 -1
- package/dist/curves/rose5.d.cts +1 -1
- package/dist/curves/rose5.d.ts +1 -1
- package/dist/curves/rose52.d.cts +1 -1
- package/dist/curves/rose52.d.ts +1 -1
- package/dist/curves/star.d.cts +1 -1
- package/dist/curves/star.d.ts +1 -1
- package/dist/curves/star4.d.cts +1 -1
- package/dist/curves/star4.d.ts +1 -1
- package/dist/curves/star7.d.cts +1 -1
- package/dist/curves/star7.d.ts +1 -1
- package/dist/index.cjs +111 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -53
- package/dist/index.d.ts +12 -53
- package/dist/index.js +111 -14
- package/dist/index.js.map +1 -1
- package/dist/{renderer-shared-DWPVHjKZ.d.ts → renderer-shared-2tEwOWJm.d.ts} +1 -1
- package/dist/{renderer-shared-Bcc_1IaT.d.cts → renderer-shared-Bh33A5Av.d.cts} +1 -1
- package/dist/terminal.cjs.map +1 -1
- package/dist/terminal.d.cts +2 -2
- package/dist/terminal.d.ts +2 -2
- package/dist/terminal.js.map +1 -1
- package/dist/{types-B1XeFpuq.d.cts → types-CmPFR9U3.d.cts} +126 -2
- package/dist/{types-B1XeFpuq.d.ts → types-CmPFR9U3.d.ts} +126 -2
- package/package.json +5 -5
- package/skills/core/SKILL.md +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { B as BaseRendererOptions, E as Engine, S as SarmalInstance, C as CurveDef,
|
|
2
|
-
export { d as BaseRuntimeRenderOptions, J as JumpOptions, M as MorphStrategy,
|
|
1
|
+
import { B as BaseRendererOptions, E as Engine, S as SarmalInstance, C as CurveDef, R as RendererOptions, D as DotMatrixSarmalOptions, a as DotMatrixRuntimeRenderOptions, b as ControlPoint, P as Point, c as SarmalOptions } from './types-CmPFR9U3.cjs';
|
|
2
|
+
export { d as BaseDotMatrixOptions, e as BaseInit, f as BaseRuntimeRenderOptions, g as BaseSarmalOptions, h as CanvasInit, i as DotMatrixInit, J as JumpOptions, M as MorphStrategy, j as RuntimeRenderOptions, k as SeekOptions, T as TrailColor, l as TrailStyle } from './types-CmPFR9U3.cjs';
|
|
3
3
|
export { CurveName, curves } from './curves/index.cjs';
|
|
4
|
-
export { B as BoundaryResult, S as SarmalPalette, c as computeBoundaries, p as palettes } from './renderer-shared-
|
|
4
|
+
export { B as BoundaryResult, S as SarmalPalette, c as computeBoundaries, p as palettes } from './renderer-shared-Bh33A5Av.cjs';
|
|
5
5
|
export { artemis2 } from './curves/artemis2.cjs';
|
|
6
6
|
export { astroid } from './curves/astroid.cjs';
|
|
7
7
|
export { deltoid } from './curves/deltoid.cjs';
|
|
@@ -53,47 +53,14 @@ declare function createSVGRenderer(options: SVGRendererOptions): SarmalInstance;
|
|
|
53
53
|
*/
|
|
54
54
|
declare function createSarmalSVG(container: SVGSVGElement, curveDef: CurveDef, options?: SVGSarmalOptions): SarmalInstance;
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
* @default 32
|
|
65
|
-
*/
|
|
66
|
-
rows?: number;
|
|
67
|
-
/**
|
|
68
|
-
* Controls the corner rounding of each dot.
|
|
69
|
-
* `0` renders as a sharp-cornered square,
|
|
70
|
-
* `1` renders as a full circle.
|
|
71
|
-
* Values between `0` and `1` give rounded rectangles.
|
|
72
|
-
* @default 1
|
|
73
|
-
*/
|
|
74
|
-
roundness?: number;
|
|
75
|
-
/**
|
|
76
|
-
* Number of trail points to keep.
|
|
77
|
-
* Larger values mean the trail extends further back from the head.
|
|
78
|
-
* @default cols * 3
|
|
79
|
-
*/
|
|
80
|
-
trailLength?: number;
|
|
81
|
-
/**
|
|
82
|
-
* Color of lit dots. Single color string for solid mode; array of two or more colors for gradient mode.
|
|
83
|
-
* Gradient mode samples a color per dot based on its position in the trail (tail → head).
|
|
84
|
-
* Background dots always use the first color at 5% opacity.
|
|
85
|
-
* @default '#ffffff'
|
|
86
|
-
*/
|
|
87
|
-
trailColor?: TrailColor;
|
|
88
|
-
/**
|
|
89
|
-
* Trail rendering style.
|
|
90
|
-
* - `'default'` — solid color, alpha varies by intensity.
|
|
91
|
-
* - `'gradient-static'` — each dot's color is sampled from the `trailColor` gradient. Requires `trailColor` array.
|
|
92
|
-
* - `'gradient-animated'` — same as `gradient-static` but the gradient phase shifts over time.
|
|
93
|
-
* @default 'default'
|
|
94
|
-
*/
|
|
95
|
-
trailStyle?: TrailStyle;
|
|
96
|
-
}
|
|
56
|
+
declare function createEngine(curveDef: CurveDef, trailLength?: number): Engine;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Creates a Canvas 2D renderer for sarmal animations
|
|
60
|
+
* Renders the skeleton and the trail
|
|
61
|
+
*/
|
|
62
|
+
declare function createRenderer(options: RendererOptions): SarmalInstance;
|
|
63
|
+
|
|
97
64
|
/**
|
|
98
65
|
* Creates a dot matrix renderer for a sarmal animation on a canvas element.
|
|
99
66
|
*
|
|
@@ -129,14 +96,6 @@ interface DotMatrixSarmalOptions extends Pick<BaseRendererOptions, "autoStart" |
|
|
|
129
96
|
*/
|
|
130
97
|
declare function createSarmalDotMatrix(canvas: HTMLCanvasElement, curveDef: CurveDef, options?: DotMatrixSarmalOptions): SarmalInstance<DotMatrixRuntimeRenderOptions>;
|
|
131
98
|
|
|
132
|
-
declare function createEngine(curveDef: CurveDef, trailLength?: number): Engine;
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Creates a Canvas 2D renderer for sarmal animations
|
|
136
|
-
* Renders the skeleton and the trail
|
|
137
|
-
*/
|
|
138
|
-
declare function createRenderer(options: RendererOptions): SarmalInstance;
|
|
139
|
-
|
|
140
99
|
/**
|
|
141
100
|
* Evaluates a closed Catmull-Rom spline through every point in `points`
|
|
142
101
|
*
|
|
@@ -195,4 +154,4 @@ declare function drawCurve(points: Array<ControlPoint>, opts?: {
|
|
|
195
154
|
*/
|
|
196
155
|
declare function createSarmal(canvas: HTMLCanvasElement, curveDef: CurveDef, options?: SarmalOptions): SarmalInstance;
|
|
197
156
|
|
|
198
|
-
export { BaseRendererOptions, CurveDef, DotMatrixRuntimeRenderOptions,
|
|
157
|
+
export { BaseRendererOptions, CurveDef, DotMatrixRuntimeRenderOptions, DotMatrixSarmalOptions, Engine, Point, RendererOptions, type SVGRendererOptions, type SVGSarmalOptions, SarmalInstance, SarmalOptions, createEngine, createRenderer, createSVGRenderer, createSarmal, createSarmalDotMatrix, createSarmalSVG, drawCurve, evaluateCatmullRom };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { B as BaseRendererOptions, E as Engine, S as SarmalInstance, C as CurveDef,
|
|
2
|
-
export { d as BaseRuntimeRenderOptions, J as JumpOptions, M as MorphStrategy,
|
|
1
|
+
import { B as BaseRendererOptions, E as Engine, S as SarmalInstance, C as CurveDef, R as RendererOptions, D as DotMatrixSarmalOptions, a as DotMatrixRuntimeRenderOptions, b as ControlPoint, P as Point, c as SarmalOptions } from './types-CmPFR9U3.js';
|
|
2
|
+
export { d as BaseDotMatrixOptions, e as BaseInit, f as BaseRuntimeRenderOptions, g as BaseSarmalOptions, h as CanvasInit, i as DotMatrixInit, J as JumpOptions, M as MorphStrategy, j as RuntimeRenderOptions, k as SeekOptions, T as TrailColor, l as TrailStyle } from './types-CmPFR9U3.js';
|
|
3
3
|
export { CurveName, curves } from './curves/index.js';
|
|
4
|
-
export { B as BoundaryResult, S as SarmalPalette, c as computeBoundaries, p as palettes } from './renderer-shared-
|
|
4
|
+
export { B as BoundaryResult, S as SarmalPalette, c as computeBoundaries, p as palettes } from './renderer-shared-2tEwOWJm.js';
|
|
5
5
|
export { artemis2 } from './curves/artemis2.js';
|
|
6
6
|
export { astroid } from './curves/astroid.js';
|
|
7
7
|
export { deltoid } from './curves/deltoid.js';
|
|
@@ -53,47 +53,14 @@ declare function createSVGRenderer(options: SVGRendererOptions): SarmalInstance;
|
|
|
53
53
|
*/
|
|
54
54
|
declare function createSarmalSVG(container: SVGSVGElement, curveDef: CurveDef, options?: SVGSarmalOptions): SarmalInstance;
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
* @default 32
|
|
65
|
-
*/
|
|
66
|
-
rows?: number;
|
|
67
|
-
/**
|
|
68
|
-
* Controls the corner rounding of each dot.
|
|
69
|
-
* `0` renders as a sharp-cornered square,
|
|
70
|
-
* `1` renders as a full circle.
|
|
71
|
-
* Values between `0` and `1` give rounded rectangles.
|
|
72
|
-
* @default 1
|
|
73
|
-
*/
|
|
74
|
-
roundness?: number;
|
|
75
|
-
/**
|
|
76
|
-
* Number of trail points to keep.
|
|
77
|
-
* Larger values mean the trail extends further back from the head.
|
|
78
|
-
* @default cols * 3
|
|
79
|
-
*/
|
|
80
|
-
trailLength?: number;
|
|
81
|
-
/**
|
|
82
|
-
* Color of lit dots. Single color string for solid mode; array of two or more colors for gradient mode.
|
|
83
|
-
* Gradient mode samples a color per dot based on its position in the trail (tail → head).
|
|
84
|
-
* Background dots always use the first color at 5% opacity.
|
|
85
|
-
* @default '#ffffff'
|
|
86
|
-
*/
|
|
87
|
-
trailColor?: TrailColor;
|
|
88
|
-
/**
|
|
89
|
-
* Trail rendering style.
|
|
90
|
-
* - `'default'` — solid color, alpha varies by intensity.
|
|
91
|
-
* - `'gradient-static'` — each dot's color is sampled from the `trailColor` gradient. Requires `trailColor` array.
|
|
92
|
-
* - `'gradient-animated'` — same as `gradient-static` but the gradient phase shifts over time.
|
|
93
|
-
* @default 'default'
|
|
94
|
-
*/
|
|
95
|
-
trailStyle?: TrailStyle;
|
|
96
|
-
}
|
|
56
|
+
declare function createEngine(curveDef: CurveDef, trailLength?: number): Engine;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Creates a Canvas 2D renderer for sarmal animations
|
|
60
|
+
* Renders the skeleton and the trail
|
|
61
|
+
*/
|
|
62
|
+
declare function createRenderer(options: RendererOptions): SarmalInstance;
|
|
63
|
+
|
|
97
64
|
/**
|
|
98
65
|
* Creates a dot matrix renderer for a sarmal animation on a canvas element.
|
|
99
66
|
*
|
|
@@ -129,14 +96,6 @@ interface DotMatrixSarmalOptions extends Pick<BaseRendererOptions, "autoStart" |
|
|
|
129
96
|
*/
|
|
130
97
|
declare function createSarmalDotMatrix(canvas: HTMLCanvasElement, curveDef: CurveDef, options?: DotMatrixSarmalOptions): SarmalInstance<DotMatrixRuntimeRenderOptions>;
|
|
131
98
|
|
|
132
|
-
declare function createEngine(curveDef: CurveDef, trailLength?: number): Engine;
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Creates a Canvas 2D renderer for sarmal animations
|
|
136
|
-
* Renders the skeleton and the trail
|
|
137
|
-
*/
|
|
138
|
-
declare function createRenderer(options: RendererOptions): SarmalInstance;
|
|
139
|
-
|
|
140
99
|
/**
|
|
141
100
|
* Evaluates a closed Catmull-Rom spline through every point in `points`
|
|
142
101
|
*
|
|
@@ -195,4 +154,4 @@ declare function drawCurve(points: Array<ControlPoint>, opts?: {
|
|
|
195
154
|
*/
|
|
196
155
|
declare function createSarmal(canvas: HTMLCanvasElement, curveDef: CurveDef, options?: SarmalOptions): SarmalInstance;
|
|
197
156
|
|
|
198
|
-
export { BaseRendererOptions, CurveDef, DotMatrixRuntimeRenderOptions,
|
|
157
|
+
export { BaseRendererOptions, CurveDef, DotMatrixRuntimeRenderOptions, DotMatrixSarmalOptions, Engine, Point, RendererOptions, type SVGRendererOptions, type SVGSarmalOptions, SarmalInstance, SarmalOptions, createEngine, createRenderer, createSVGRenderer, createSarmal, createSarmalDotMatrix, createSarmalSVG, drawCurve, evaluateCatmullRom };
|
package/dist/index.js
CHANGED
|
@@ -362,15 +362,42 @@ function computeBoundaries(pts, logicalWidth, logicalHeight, minPaddingPx = FIT_
|
|
|
362
362
|
offsetY: (logicalHeight - h * scale) / 2 - minY * scale
|
|
363
363
|
};
|
|
364
364
|
}
|
|
365
|
-
|
|
365
|
+
var DESTROYED_ERROR = "[sarmal] Instance has been destroyed and cannot be used again. Call pause() instead of destroy() for temporary suspension.";
|
|
366
|
+
function enginePassthroughs(engine, isDestroyed) {
|
|
367
|
+
function guard() {
|
|
368
|
+
if (isDestroyed()) {
|
|
369
|
+
throw new Error(DESTROYED_ERROR);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
366
372
|
return {
|
|
367
|
-
jump
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
373
|
+
jump(phase, options) {
|
|
374
|
+
guard();
|
|
375
|
+
engine.jump(phase, options);
|
|
376
|
+
},
|
|
377
|
+
seek(phase, options) {
|
|
378
|
+
guard();
|
|
379
|
+
engine.seek(phase, options);
|
|
380
|
+
},
|
|
381
|
+
setSpeed(speed) {
|
|
382
|
+
guard();
|
|
383
|
+
engine.setSpeed(speed);
|
|
384
|
+
},
|
|
385
|
+
getSpeed() {
|
|
386
|
+
guard();
|
|
387
|
+
return engine.getSpeed();
|
|
388
|
+
},
|
|
389
|
+
resetSpeed() {
|
|
390
|
+
guard();
|
|
391
|
+
engine.resetSpeed();
|
|
392
|
+
},
|
|
393
|
+
setSpeedOver(speed, duration) {
|
|
394
|
+
guard();
|
|
395
|
+
return engine.setSpeedOver(speed, duration);
|
|
396
|
+
},
|
|
397
|
+
getSarmalSkeleton() {
|
|
398
|
+
guard();
|
|
399
|
+
return engine.getSarmalSkeleton();
|
|
400
|
+
}
|
|
374
401
|
};
|
|
375
402
|
}
|
|
376
403
|
var palettes = {
|
|
@@ -741,6 +768,7 @@ function createRenderer(options) {
|
|
|
741
768
|
let animationId = null;
|
|
742
769
|
let lastTime = 0;
|
|
743
770
|
let pausedByVisibility = false;
|
|
771
|
+
let destroyed = false;
|
|
744
772
|
let morphResolve = null;
|
|
745
773
|
let morphReject = null;
|
|
746
774
|
let morphDurationMs = DEFAULT_MORPH_DURATION_MS;
|
|
@@ -912,6 +940,9 @@ function createRenderer(options) {
|
|
|
912
940
|
const shouldAutoStart = options.autoStart !== false;
|
|
913
941
|
const instance = {
|
|
914
942
|
play() {
|
|
943
|
+
if (destroyed) {
|
|
944
|
+
throw new Error(DESTROYED_ERROR);
|
|
945
|
+
}
|
|
915
946
|
if (animationId !== null) {
|
|
916
947
|
return;
|
|
917
948
|
}
|
|
@@ -919,6 +950,9 @@ function createRenderer(options) {
|
|
|
919
950
|
loop();
|
|
920
951
|
},
|
|
921
952
|
pause() {
|
|
953
|
+
if (destroyed) {
|
|
954
|
+
throw new Error(DESTROYED_ERROR);
|
|
955
|
+
}
|
|
922
956
|
if (animationId === null) {
|
|
923
957
|
return;
|
|
924
958
|
}
|
|
@@ -927,24 +961,36 @@ function createRenderer(options) {
|
|
|
927
961
|
engine.cancelSpeedTransition();
|
|
928
962
|
},
|
|
929
963
|
reset() {
|
|
964
|
+
if (destroyed) {
|
|
965
|
+
throw new Error(DESTROYED_ERROR);
|
|
966
|
+
}
|
|
930
967
|
engine.reset();
|
|
931
968
|
trail = [];
|
|
932
969
|
head = null;
|
|
933
970
|
},
|
|
934
971
|
destroy() {
|
|
972
|
+
if (destroyed) {
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
destroyed = true;
|
|
935
976
|
if (animationId !== null) {
|
|
936
977
|
cancelAnimationFrame(animationId);
|
|
937
978
|
animationId = null;
|
|
938
979
|
}
|
|
939
980
|
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
981
|
+
engine.cancelSpeedTransition();
|
|
940
982
|
if (morphReject !== null) {
|
|
941
|
-
morphReject(new Error("Instance destroyed during morph"));
|
|
983
|
+
morphReject(new Error("[sarmal] Instance destroyed during morph"));
|
|
942
984
|
morphResolve = null;
|
|
943
985
|
morphReject = null;
|
|
944
986
|
}
|
|
987
|
+
ctx.clearRect(0, 0, logicalWidth, logicalHeight);
|
|
945
988
|
},
|
|
946
|
-
...enginePassthroughs(engine),
|
|
989
|
+
...enginePassthroughs(engine, () => destroyed),
|
|
947
990
|
morphTo(target, options2) {
|
|
991
|
+
if (destroyed) {
|
|
992
|
+
throw new Error(DESTROYED_ERROR);
|
|
993
|
+
}
|
|
948
994
|
if (morphResolve !== null) {
|
|
949
995
|
engine.completeMorph();
|
|
950
996
|
morphResolve();
|
|
@@ -961,6 +1007,9 @@ function createRenderer(options) {
|
|
|
961
1007
|
});
|
|
962
1008
|
},
|
|
963
1009
|
setRenderOptions(partial) {
|
|
1010
|
+
if (destroyed) {
|
|
1011
|
+
throw new Error(DESTROYED_ERROR);
|
|
1012
|
+
}
|
|
964
1013
|
validateRenderOptions(partial);
|
|
965
1014
|
if (partial.trailColor !== void 0) {
|
|
966
1015
|
trailColor = partial.trailColor;
|
|
@@ -1215,6 +1264,7 @@ function createSVGRenderer(options) {
|
|
|
1215
1264
|
let animationId = null;
|
|
1216
1265
|
let lastTime = 0;
|
|
1217
1266
|
let pausedByVisibility = false;
|
|
1267
|
+
let destroyed = false;
|
|
1218
1268
|
const prefersReducedMotion = typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
1219
1269
|
let morphResolve = null;
|
|
1220
1270
|
let morphReject = null;
|
|
@@ -1283,6 +1333,9 @@ function createSVGRenderer(options) {
|
|
|
1283
1333
|
const shouldAutoStart = options.autoStart !== false;
|
|
1284
1334
|
const instance = {
|
|
1285
1335
|
play() {
|
|
1336
|
+
if (destroyed) {
|
|
1337
|
+
throw new Error(DESTROYED_ERROR);
|
|
1338
|
+
}
|
|
1286
1339
|
if (animationId !== null) {
|
|
1287
1340
|
return;
|
|
1288
1341
|
}
|
|
@@ -1290,6 +1343,9 @@ function createSVGRenderer(options) {
|
|
|
1290
1343
|
loop();
|
|
1291
1344
|
},
|
|
1292
1345
|
pause() {
|
|
1346
|
+
if (destroyed) {
|
|
1347
|
+
throw new Error(DESTROYED_ERROR);
|
|
1348
|
+
}
|
|
1293
1349
|
if (animationId === null) {
|
|
1294
1350
|
return;
|
|
1295
1351
|
}
|
|
@@ -1298,23 +1354,34 @@ function createSVGRenderer(options) {
|
|
|
1298
1354
|
engine.cancelSpeedTransition();
|
|
1299
1355
|
},
|
|
1300
1356
|
reset() {
|
|
1357
|
+
if (destroyed) {
|
|
1358
|
+
throw new Error(DESTROYED_ERROR);
|
|
1359
|
+
}
|
|
1301
1360
|
engine.reset();
|
|
1302
1361
|
},
|
|
1303
1362
|
destroy() {
|
|
1363
|
+
if (destroyed) {
|
|
1364
|
+
return;
|
|
1365
|
+
}
|
|
1366
|
+
destroyed = true;
|
|
1304
1367
|
if (animationId !== null) {
|
|
1305
1368
|
cancelAnimationFrame(animationId);
|
|
1306
1369
|
animationId = null;
|
|
1307
1370
|
}
|
|
1308
1371
|
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
1372
|
+
engine.cancelSpeedTransition();
|
|
1309
1373
|
if (morphReject !== null) {
|
|
1310
|
-
morphReject(new Error("Instance destroyed during morph"));
|
|
1374
|
+
morphReject(new Error("[sarmal] Instance destroyed during morph"));
|
|
1311
1375
|
morphResolve = null;
|
|
1312
1376
|
morphReject = null;
|
|
1313
1377
|
}
|
|
1314
1378
|
group.remove();
|
|
1315
1379
|
},
|
|
1316
|
-
...enginePassthroughs(engine),
|
|
1380
|
+
...enginePassthroughs(engine, () => destroyed),
|
|
1317
1381
|
morphTo(target, options2) {
|
|
1382
|
+
if (destroyed) {
|
|
1383
|
+
throw new Error(DESTROYED_ERROR);
|
|
1384
|
+
}
|
|
1318
1385
|
if (morphResolve !== null) {
|
|
1319
1386
|
engine.completeMorph();
|
|
1320
1387
|
morphResolve();
|
|
@@ -1340,6 +1407,9 @@ function createSVGRenderer(options) {
|
|
|
1340
1407
|
});
|
|
1341
1408
|
},
|
|
1342
1409
|
setRenderOptions(partial) {
|
|
1410
|
+
if (destroyed) {
|
|
1411
|
+
throw new Error(DESTROYED_ERROR);
|
|
1412
|
+
}
|
|
1343
1413
|
validateRenderOptions(partial);
|
|
1344
1414
|
const prevTrailStyle = trailStyle;
|
|
1345
1415
|
if (partial.trailColor !== void 0) {
|
|
@@ -1469,6 +1539,7 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1469
1539
|
let animationId = null;
|
|
1470
1540
|
let lastTime = 0;
|
|
1471
1541
|
let pausedByVisibility = false;
|
|
1542
|
+
let destroyed = false;
|
|
1472
1543
|
let morphResolve = null;
|
|
1473
1544
|
let morphReject = null;
|
|
1474
1545
|
let morphDurationMs = DEFAULT_MORPH_DURATION_MS;
|
|
@@ -1722,6 +1793,9 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1722
1793
|
const instance = {
|
|
1723
1794
|
/** Starts the animation loop. Does nothing if already running. */
|
|
1724
1795
|
play() {
|
|
1796
|
+
if (destroyed) {
|
|
1797
|
+
throw new Error(DESTROYED_ERROR);
|
|
1798
|
+
}
|
|
1725
1799
|
if (animationId !== null) {
|
|
1726
1800
|
return;
|
|
1727
1801
|
}
|
|
@@ -1730,6 +1804,9 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1730
1804
|
},
|
|
1731
1805
|
/** Pauses the animation loop. Preserves current trail state. */
|
|
1732
1806
|
pause() {
|
|
1807
|
+
if (destroyed) {
|
|
1808
|
+
throw new Error(DESTROYED_ERROR);
|
|
1809
|
+
}
|
|
1733
1810
|
if (animationId === null) {
|
|
1734
1811
|
return;
|
|
1735
1812
|
}
|
|
@@ -1739,29 +1816,46 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1739
1816
|
},
|
|
1740
1817
|
/** Resets the animation to the start of the curve and clears the grid. */
|
|
1741
1818
|
reset() {
|
|
1819
|
+
if (destroyed) {
|
|
1820
|
+
throw new Error(DESTROYED_ERROR);
|
|
1821
|
+
}
|
|
1742
1822
|
engine.reset();
|
|
1743
1823
|
grid.fill(0);
|
|
1744
1824
|
},
|
|
1745
|
-
/**
|
|
1825
|
+
/**
|
|
1826
|
+
* Permanently stops the animation and clears the visual output.
|
|
1827
|
+
* Calling any method on a destroyed instance throws an error.
|
|
1828
|
+
* `destroy()` is idempotent — calling it multiple times is safe.
|
|
1829
|
+
*/
|
|
1746
1830
|
destroy() {
|
|
1831
|
+
if (destroyed) {
|
|
1832
|
+
return;
|
|
1833
|
+
}
|
|
1834
|
+
destroyed = true;
|
|
1747
1835
|
if (animationId !== null) {
|
|
1748
1836
|
cancelAnimationFrame(animationId);
|
|
1749
1837
|
animationId = null;
|
|
1750
1838
|
}
|
|
1751
1839
|
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
1840
|
+
engine.cancelSpeedTransition();
|
|
1752
1841
|
if (morphReject !== null) {
|
|
1753
1842
|
morphReject(new Error("[sarmal] Instance destroyed during morph"));
|
|
1754
1843
|
morphResolve = null;
|
|
1755
1844
|
morphReject = null;
|
|
1756
1845
|
}
|
|
1846
|
+
grid.fill(0);
|
|
1847
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
1757
1848
|
},
|
|
1758
|
-
...enginePassthroughs(engine),
|
|
1849
|
+
...enginePassthroughs(engine, () => destroyed),
|
|
1759
1850
|
/**
|
|
1760
1851
|
* Smoothly transitions from the current curve to `target`.
|
|
1761
1852
|
* If a morph is already in progress, it is snapped to completion before the new one starts.
|
|
1762
1853
|
* @returns A Promise that resolves when the transition finishes.
|
|
1763
1854
|
*/
|
|
1764
1855
|
morphTo(target, opts) {
|
|
1856
|
+
if (destroyed) {
|
|
1857
|
+
throw new Error(DESTROYED_ERROR);
|
|
1858
|
+
}
|
|
1765
1859
|
if (morphResolve !== null) {
|
|
1766
1860
|
completeMorphNow();
|
|
1767
1861
|
}
|
|
@@ -1781,6 +1875,9 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1781
1875
|
* ! Validation fails the entire call if any field is invalid, leaving options unchanged.
|
|
1782
1876
|
*/
|
|
1783
1877
|
setRenderOptions(partial) {
|
|
1878
|
+
if (destroyed) {
|
|
1879
|
+
throw new Error(DESTROYED_ERROR);
|
|
1880
|
+
}
|
|
1784
1881
|
validateBaseRenderOptions(partial);
|
|
1785
1882
|
let needsRebuildBg = false;
|
|
1786
1883
|
if (partial.trailColor !== void 0) {
|