@nmmty/lazycanvas 0.6.5 → 1.0.0-dev.3

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 (80) hide show
  1. package/ReadMe.md +1 -1
  2. package/biome.json +41 -0
  3. package/dist/core/Interpolation.d.ts +30 -0
  4. package/dist/core/Interpolation.js +200 -0
  5. package/dist/core/Scene.d.ts +96 -0
  6. package/dist/core/Scene.js +172 -0
  7. package/dist/core/Signal.d.ts +133 -0
  8. package/dist/core/Signal.js +255 -0
  9. package/dist/core/SignalUtils.d.ts +133 -0
  10. package/dist/core/SignalUtils.js +333 -0
  11. package/dist/core/ThreadScheduler.d.ts +38 -0
  12. package/dist/core/ThreadScheduler.js +74 -0
  13. package/dist/helpers/Filters.js +1 -1
  14. package/dist/helpers/FontsList.js +18 -18
  15. package/dist/helpers/Utlis.d.ts +3 -3
  16. package/dist/helpers/Utlis.js +15 -18
  17. package/dist/helpers/index.d.ts +3 -3
  18. package/dist/index.d.ts +10 -0
  19. package/dist/index.js +10 -0
  20. package/dist/jsx-runtime.d.ts +17 -0
  21. package/dist/jsx-runtime.js +111 -0
  22. package/dist/structures/LazyCanvas.d.ts +3 -45
  23. package/dist/structures/LazyCanvas.js +11 -74
  24. package/dist/structures/components/BaseLayer.d.ts +34 -12
  25. package/dist/structures/components/BaseLayer.js +68 -35
  26. package/dist/structures/components/BezierLayer.d.ts +16 -37
  27. package/dist/structures/components/BezierLayer.js +83 -46
  28. package/dist/structures/components/{Group.d.ts → Div.d.ts} +22 -16
  29. package/dist/structures/components/{Group.js → Div.js} +38 -39
  30. package/dist/structures/components/ImageLayer.d.ts +1 -1
  31. package/dist/structures/components/ImageLayer.js +24 -25
  32. package/dist/structures/components/LineLayer.d.ts +11 -37
  33. package/dist/structures/components/LineLayer.js +42 -42
  34. package/dist/structures/components/MorphLayer.d.ts +3 -32
  35. package/dist/structures/components/MorphLayer.js +32 -46
  36. package/dist/structures/components/Path2DLayer.d.ts +4 -32
  37. package/dist/structures/components/Path2DLayer.js +28 -33
  38. package/dist/structures/components/PolygonLayer.d.ts +2 -31
  39. package/dist/structures/components/PolygonLayer.js +35 -38
  40. package/dist/structures/components/QuadraticLayer.d.ts +16 -33
  41. package/dist/structures/components/QuadraticLayer.js +80 -42
  42. package/dist/structures/components/TextLayer.d.ts +4 -33
  43. package/dist/structures/components/TextLayer.js +60 -62
  44. package/dist/structures/components/index.d.ts +10 -11
  45. package/dist/structures/components/index.js +1 -2
  46. package/dist/structures/helpers/Exporter.d.ts +13 -4
  47. package/dist/structures/helpers/Exporter.js +79 -42
  48. package/dist/structures/helpers/Font.js +1 -17
  49. package/dist/structures/helpers/Gradient.js +32 -45
  50. package/dist/structures/helpers/Link.js +2 -14
  51. package/dist/structures/helpers/Pattern.js +9 -17
  52. package/dist/structures/helpers/index.d.ts +7 -7
  53. package/dist/structures/helpers/readers/JSONReader.d.ts +4 -4
  54. package/dist/structures/helpers/readers/JSONReader.js +32 -40
  55. package/dist/structures/helpers/readers/YAMLReader.js +5 -5
  56. package/dist/structures/managers/FontsManager.js +9 -18
  57. package/dist/structures/managers/LayersManager.d.ts +18 -28
  58. package/dist/structures/managers/LayersManager.js +14 -36
  59. package/dist/structures/managers/RenderManager.d.ts +1 -15
  60. package/dist/structures/managers/RenderManager.js +17 -110
  61. package/dist/structures/managers/index.d.ts +3 -5
  62. package/dist/structures/managers/index.js +0 -2
  63. package/dist/types/enum.d.ts +1 -2
  64. package/dist/types/enum.js +1 -2
  65. package/dist/types/index.d.ts +1 -1
  66. package/dist/utils/APNGEncoder.d.ts +67 -0
  67. package/dist/utils/APNGEncoder.js +205 -0
  68. package/dist/utils/DrawUtils.d.ts +9 -0
  69. package/dist/utils/DrawUtils.js +42 -0
  70. package/dist/utils/LazyUtil.js +1 -2
  71. package/dist/utils/utils.d.ts +4 -7
  72. package/dist/utils/utils.js +133 -76
  73. package/package.json +62 -59
  74. package/dist/structures/components/ClearLayer.d.ts +0 -147
  75. package/dist/structures/components/ClearLayer.js +0 -158
  76. package/dist/structures/managers/AnimationManager.d.ts +0 -120
  77. package/dist/structures/managers/AnimationManager.js +0 -99
  78. package/dist/structures/managers/PluginManager.d.ts +0 -230
  79. package/dist/structures/managers/PluginManager.js +0 -182
  80. package/dist/types/types.d.ts +0 -107
package/ReadMe.md CHANGED
@@ -1,4 +1,4 @@
1
- ![Logo](./resources/logo.svg)
1
+ ![Logo](https://raw.githubusercontent.com/NMMTY/LazyCanvas/refs/heads/main/packages/lazycanvas/resources/logo.svg)
2
2
 
3
3
  [![npm version](https://badge.fury.io/js/%40nmmty%2Flazycanvas.svg)](https://www.npmjs.com/package/@nmmty/lazycanvas)
4
4
  [![downloads](https://img.shields.io/npm/dm/%40nmmty%2Flazycanvas.svg)](https://www.npmjs.com/package/@nmmty/lazycanvas)
package/biome.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
3
+ "vcs": {
4
+ "enabled": false,
5
+ "clientKind": "git",
6
+ "useIgnoreFile": false
7
+ },
8
+ "files": {
9
+ "ignoreUnknown": false,
10
+ "ignore": [
11
+ "node_modules/",
12
+ "dist/",
13
+ "biome.json",
14
+ ".biome/",
15
+ ".git/",
16
+ ".hg/",
17
+ ".svn/",
18
+ "public/",
19
+ "docs/",
20
+ "resources/"
21
+ ]
22
+ },
23
+ "formatter": {
24
+ "enabled": true,
25
+ "indentStyle": "space",
26
+ "indentWidth": 2,
27
+ "lineWidth": 100
28
+ },
29
+ "organizeImports": {
30
+ "enabled": true
31
+ },
32
+ "linter": {
33
+ "enabled": true,
34
+ "rules": { "recommended": true }
35
+ },
36
+ "javascript": {
37
+ "formatter": {
38
+ "quoteStyle": "double"
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,30 @@
1
+ export type Interpolator<T> = (from: T, to: T, progress: number) => T;
2
+ /**
3
+ * Linear interpolation for numbers
4
+ */
5
+ export declare function lerpNumber(from: number, to: number, progress: number): number;
6
+ /**
7
+ * Interpolate colors in RGB space
8
+ */
9
+ export declare function lerpColorRGB(from: string, to: string, progress: number): string;
10
+ /**
11
+ * Interpolate colors in HSL space (smoother for hue transitions)
12
+ */
13
+ export declare function lerpColorHSL(from: string, to: string, progress: number): string;
14
+ /**
15
+ * Interpolate 2D vectors/points
16
+ */
17
+ export declare function lerpVector(from: {
18
+ x: number;
19
+ y: number;
20
+ }, to: {
21
+ x: number;
22
+ y: number;
23
+ }, progress: number): {
24
+ x: number;
25
+ y: number;
26
+ };
27
+ /**
28
+ * Auto-detect interpolator based on value type
29
+ */
30
+ export declare function getInterpolator<T>(from: T, to: T): Interpolator<T>;
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.lerpNumber = lerpNumber;
4
+ exports.lerpColorRGB = lerpColorRGB;
5
+ exports.lerpColorHSL = lerpColorHSL;
6
+ exports.lerpVector = lerpVector;
7
+ exports.getInterpolator = getInterpolator;
8
+ /**
9
+ * Linear interpolation for numbers
10
+ */
11
+ function lerpNumber(from, to, progress) {
12
+ return from + (to - from) * progress;
13
+ }
14
+ /**
15
+ * Parse color string to RGBA components
16
+ */
17
+ function parseColor(color) {
18
+ // Handle hex colors
19
+ if (color.startsWith("#")) {
20
+ const hex = color.slice(1);
21
+ let r, g, b, a = 1;
22
+ if (hex.length === 3 || hex.length === 4) {
23
+ r = parseInt(hex[0] + hex[0], 16);
24
+ g = parseInt(hex[1] + hex[1], 16);
25
+ b = parseInt(hex[2] + hex[2], 16);
26
+ a = hex.length === 4 ? parseInt(hex[3] + hex[3], 16) / 255 : 1;
27
+ }
28
+ else if (hex.length === 6 || hex.length === 8) {
29
+ r = parseInt(hex.slice(0, 2), 16);
30
+ g = parseInt(hex.slice(2, 4), 16);
31
+ b = parseInt(hex.slice(4, 6), 16);
32
+ a = hex.length === 8 ? parseInt(hex.slice(6, 8), 16) / 255 : 1;
33
+ }
34
+ else {
35
+ return null;
36
+ }
37
+ return { r, g, b, a };
38
+ }
39
+ // Handle rgb/rgba
40
+ const rgbaMatch = color.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
41
+ if (rgbaMatch) {
42
+ return {
43
+ r: parseInt(rgbaMatch[1]),
44
+ g: parseInt(rgbaMatch[2]),
45
+ b: parseInt(rgbaMatch[3]),
46
+ a: rgbaMatch[4] ? parseFloat(rgbaMatch[4]) : 1,
47
+ };
48
+ }
49
+ // Handle hsl/hsla
50
+ const hslaMatch = color.match(/hsla?\((\d+),\s*(\d+)%,\s*(\d+)%(?:,\s*([\d.]+))?\)/);
51
+ if (hslaMatch) {
52
+ const h = parseInt(hslaMatch[1]) / 360;
53
+ const s = parseInt(hslaMatch[2]) / 100;
54
+ const l = parseInt(hslaMatch[3]) / 100;
55
+ const a = hslaMatch[4] ? parseFloat(hslaMatch[4]) : 1;
56
+ // Convert HSL to RGB
57
+ const { r, g, b } = hslToRgb(h, s, l);
58
+ return { r, g, b, a };
59
+ }
60
+ return null;
61
+ }
62
+ /**
63
+ * Convert HSL to RGB
64
+ */
65
+ function hslToRgb(h, s, l) {
66
+ let r, g, b;
67
+ if (s === 0) {
68
+ r = g = b = l;
69
+ }
70
+ else {
71
+ const hue2rgb = (p, q, t) => {
72
+ if (t < 0)
73
+ t += 1;
74
+ if (t > 1)
75
+ t -= 1;
76
+ if (t < 1 / 6)
77
+ return p + (q - p) * 6 * t;
78
+ if (t < 1 / 2)
79
+ return q;
80
+ if (t < 2 / 3)
81
+ return p + (q - p) * (2 / 3 - t) * 6;
82
+ return p;
83
+ };
84
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
85
+ const p = 2 * l - q;
86
+ r = hue2rgb(p, q, h + 1 / 3);
87
+ g = hue2rgb(p, q, h);
88
+ b = hue2rgb(p, q, h - 1 / 3);
89
+ }
90
+ return {
91
+ r: Math.round(r * 255),
92
+ g: Math.round(g * 255),
93
+ b: Math.round(b * 255),
94
+ };
95
+ }
96
+ /**
97
+ * Convert RGB to HSL
98
+ */
99
+ function rgbToHsl(r, g, b) {
100
+ r /= 255;
101
+ g /= 255;
102
+ b /= 255;
103
+ const max = Math.max(r, g, b);
104
+ const min = Math.min(r, g, b);
105
+ let h = 0, s = 0;
106
+ const l = (max + min) / 2;
107
+ if (max !== min) {
108
+ const d = max - min;
109
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
110
+ switch (max) {
111
+ case r:
112
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
113
+ break;
114
+ case g:
115
+ h = ((b - r) / d + 2) / 6;
116
+ break;
117
+ case b:
118
+ h = ((r - g) / d + 4) / 6;
119
+ break;
120
+ }
121
+ }
122
+ return { h, s, l };
123
+ }
124
+ /**
125
+ * Interpolate colors in RGB space
126
+ */
127
+ function lerpColorRGB(from, to, progress) {
128
+ const fromColor = parseColor(from);
129
+ const toColor = parseColor(to);
130
+ if (!fromColor || !toColor) {
131
+ return progress < 0.5 ? from : to;
132
+ }
133
+ const r = Math.round(lerpNumber(fromColor.r, toColor.r, progress));
134
+ const g = Math.round(lerpNumber(fromColor.g, toColor.g, progress));
135
+ const b = Math.round(lerpNumber(fromColor.b, toColor.b, progress));
136
+ const a = lerpNumber(fromColor.a, toColor.a, progress);
137
+ return `rgba(${r}, ${g}, ${b}, ${a})`;
138
+ }
139
+ /**
140
+ * Interpolate colors in HSL space (smoother for hue transitions)
141
+ */
142
+ function lerpColorHSL(from, to, progress) {
143
+ const fromColor = parseColor(from);
144
+ const toColor = parseColor(to);
145
+ if (!fromColor || !toColor) {
146
+ return progress < 0.5 ? from : to;
147
+ }
148
+ const fromHSL = rgbToHsl(fromColor.r, fromColor.g, fromColor.b);
149
+ const toHSL = rgbToHsl(toColor.r, toColor.g, toColor.b);
150
+ // Interpolate hue with shortest path
151
+ let deltaH = toHSL.h - fromHSL.h;
152
+ if (deltaH > 0.5)
153
+ deltaH -= 1;
154
+ if (deltaH < -0.5)
155
+ deltaH += 1;
156
+ const h = fromHSL.h + deltaH * progress;
157
+ const s = lerpNumber(fromHSL.s, toHSL.s, progress);
158
+ const l = lerpNumber(fromHSL.l, toHSL.l, progress);
159
+ const a = lerpNumber(fromColor.a, toColor.a, progress);
160
+ const { r, g, b } = hslToRgb(h, s, l);
161
+ return `rgba(${r}, ${g}, ${b}, ${a})`;
162
+ }
163
+ /**
164
+ * Interpolate 2D vectors/points
165
+ */
166
+ function lerpVector(from, to, progress) {
167
+ return {
168
+ x: lerpNumber(from.x, to.x, progress),
169
+ y: lerpNumber(from.y, to.y, progress),
170
+ };
171
+ }
172
+ /**
173
+ * Auto-detect interpolator based on value type
174
+ */
175
+ function getInterpolator(from, to) {
176
+ // Number
177
+ if (typeof from === "number" && typeof to === "number") {
178
+ return lerpNumber;
179
+ }
180
+ // String (assume color)
181
+ if (typeof from === "string" && typeof to === "string") {
182
+ // Try to detect if it's a color
183
+ if (from.startsWith("#") || from.startsWith("rgb") || from.startsWith("hsl")) {
184
+ return lerpColorRGB;
185
+ }
186
+ }
187
+ // Vector/Point
188
+ if (typeof from === "object" &&
189
+ from !== null &&
190
+ typeof to === "object" &&
191
+ to !== null &&
192
+ "x" in from &&
193
+ "y" in from &&
194
+ "x" in to &&
195
+ "y" in to) {
196
+ return lerpVector;
197
+ }
198
+ // Default: snap to end value
199
+ return ((from, to, progress) => (progress < 1 ? from : to));
200
+ }
@@ -0,0 +1,96 @@
1
+ import { Div } from "../structures/components";
2
+ import { AnyLayer } from "../types";
3
+ import { ThreadGenerator, Signal } from "./Signal";
4
+ import { LazyCanvas } from "../structures/LazyCanvas";
5
+ import { Canvas } from "@napi-rs/canvas";
6
+ /**
7
+ * Scene class - manages canvas, context, layers, and animation timeline
8
+ */
9
+ export declare class Scene {
10
+ readonly lazyCanvas: LazyCanvas;
11
+ private allLayers;
12
+ private scheduler;
13
+ private lastFrameTime;
14
+ /**
15
+ * Create a new Scene
16
+ * @param width - Canvas width in pixels
17
+ * @param height - Canvas height in pixels
18
+ */
19
+ constructor(width: number, height: number);
20
+ /**
21
+ * Load a layer tree created via JSX
22
+ * Registers all layers with IDs into the manager
23
+ * @param tree - Root layer or group
24
+ */
25
+ load(tree: AnyLayer | Div): void;
26
+ /**
27
+ * Render a single frame at the given time
28
+ * @param time - Time in seconds
29
+ */
30
+ renderFrame(time: number): Promise<void>;
31
+ renderFirstFrame(): Promise<Canvas>;
32
+ /**
33
+ * Get current frame as ImageData (Uint8ClampedArray)
34
+ * Much faster than encoding to PNG
35
+ */
36
+ getImageData(): Uint8ClampedArray;
37
+ /**
38
+ * Get canvas width
39
+ */
40
+ get width(): number;
41
+ /**
42
+ * Get canvas height
43
+ */
44
+ get height(): number;
45
+ /**
46
+ * Update state for all layers that have signals
47
+ * @param time - Current time in seconds
48
+ */
49
+ private updateAllStates;
50
+ /**
51
+ * Draw a layer or group
52
+ * @param layer - Layer to draw
53
+ */
54
+ private drawLayer;
55
+ /**
56
+ * Render multiple frames and return as animation
57
+ * @param startTime - Start time in seconds
58
+ * @param endTime - End time in seconds
59
+ * @param fps - Frames per second (default: 30)
60
+ * @returns Array of PNG buffers for each frame
61
+ */
62
+ renderAnimation(startTime: number, endTime: number, fps?: number): Promise<Buffer[]>;
63
+ /**
64
+ * Render multiple frames and return as ImageData array (much faster)
65
+ * @param startTime - Start time in seconds
66
+ * @param endTime - End time in seconds
67
+ * @param fps - Frames per second (default: 30)
68
+ * @returns Array of Uint8ClampedArray for each frame
69
+ */
70
+ renderAnimationData(startTime: number, endTime: number, fps?: number): Promise<Uint8ClampedArray[]>;
71
+ /**
72
+ * Get a layer by ID from the manager
73
+ * @param id - Layer ID
74
+ * @returns Layer or undefined
75
+ */
76
+ getLayer(id: string): AnyLayer | Div | undefined;
77
+ /**
78
+ * Add animation generator to scheduler
79
+ * @param generator - Animation generator to run
80
+ */
81
+ addAnimation(generator: ThreadGenerator): void;
82
+ /**
83
+ * Play animation on a signal
84
+ * @param signal - Signal to animate
85
+ * @param generator - Animation generator
86
+ */
87
+ playAnimation<T>(signal: Signal<T>, generator: ThreadGenerator): void;
88
+ /**
89
+ * Clear all animations
90
+ */
91
+ clearAnimations(): void;
92
+ /**
93
+ * Reset scene timeline
94
+ */
95
+ resetTimeline(): void;
96
+ }
@@ -0,0 +1,172 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Scene = void 0;
4
+ const ThreadScheduler_1 = require("./ThreadScheduler");
5
+ const LazyCanvas_1 = require("../structures/LazyCanvas");
6
+ /**
7
+ * Scene class - manages canvas, context, layers, and animation timeline
8
+ */
9
+ class Scene {
10
+ /**
11
+ * Create a new Scene
12
+ * @param width - Canvas width in pixels
13
+ * @param height - Canvas height in pixels
14
+ */
15
+ constructor(width, height) {
16
+ this.allLayers = [];
17
+ this.scheduler = new ThreadScheduler_1.ThreadScheduler();
18
+ this.lastFrameTime = 0;
19
+ this.lazyCanvas = new LazyCanvas_1.LazyCanvas().create(width, height);
20
+ }
21
+ /**
22
+ * Load a layer tree created via JSX
23
+ * Registers all layers with IDs into the manager
24
+ * @param tree - Root layer or group
25
+ */
26
+ load(tree) {
27
+ this.lazyCanvas.manager.layers.add(tree);
28
+ this.allLayers = this.lazyCanvas.manager.layers.toArray();
29
+ }
30
+ /**
31
+ * Render a single frame at the given time
32
+ * @param time - Time in seconds
33
+ */
34
+ async renderFrame(time) {
35
+ if (this.lazyCanvas.manager.layers.size() === 0) {
36
+ throw new Error("Scene: No root layer loaded. Call scene.load(tree) first.");
37
+ }
38
+ // 1. Update scheduler with current time
39
+ this.scheduler.update(time);
40
+ // 2. Clear canvas
41
+ this.lazyCanvas.ctx.clearRect(0, 0, this.lazyCanvas.canvas.width, this.lazyCanvas.canvas.height);
42
+ // 3. PHASE 1: Update all layer states from signals
43
+ this.updateAllStates(time);
44
+ // 4. PHASE 2: Draw the layer tree
45
+ await this.drawLayer(this.lazyCanvas.manager.layers.toArray()[0]);
46
+ this.lastFrameTime = time;
47
+ }
48
+ async renderFirstFrame() {
49
+ await this.renderFrame(0);
50
+ return this.lazyCanvas.canvas;
51
+ }
52
+ /**
53
+ * Get current frame as ImageData (Uint8ClampedArray)
54
+ * Much faster than encoding to PNG
55
+ */
56
+ getImageData() {
57
+ const imageData = this.lazyCanvas.ctx.getImageData(0, 0, this.width, this.height);
58
+ return imageData.data;
59
+ }
60
+ /**
61
+ * Get canvas width
62
+ */
63
+ get width() {
64
+ return this.lazyCanvas.canvas.width;
65
+ }
66
+ /**
67
+ * Get canvas height
68
+ */
69
+ get height() {
70
+ return this.lazyCanvas.canvas.height;
71
+ }
72
+ /**
73
+ * Update state for all layers that have signals
74
+ * @param time - Current time in seconds
75
+ */
76
+ updateAllStates(time) {
77
+ for (const layer of this.allLayers) {
78
+ // Check if layer has updateState method (added by BaseLayer)
79
+ if ("updateState" in layer && typeof layer.updateState === "function") {
80
+ layer.updateState(time);
81
+ }
82
+ }
83
+ }
84
+ /**
85
+ * Draw a layer or group
86
+ * @param layer - Layer to draw
87
+ */
88
+ async drawLayer(layer) {
89
+ if (!layer.visible)
90
+ return;
91
+ // Set global composite operation if present
92
+ if ("props" in layer && layer.props?.globalComposite) {
93
+ this.lazyCanvas.ctx.globalCompositeOperation = layer.props.globalComposite;
94
+ }
95
+ // Draw the layer
96
+ if ("draw" in layer && typeof layer.draw === "function") {
97
+ await layer.draw(this.lazyCanvas.ctx, this.lazyCanvas.canvas, this.lazyCanvas.manager.layers, false);
98
+ }
99
+ // Reset shadow after drawing
100
+ this.lazyCanvas.ctx.shadowColor = "transparent";
101
+ }
102
+ /**
103
+ * Render multiple frames and return as animation
104
+ * @param startTime - Start time in seconds
105
+ * @param endTime - End time in seconds
106
+ * @param fps - Frames per second (default: 30)
107
+ * @returns Array of PNG buffers for each frame
108
+ */
109
+ async renderAnimation(startTime, endTime, fps = 30) {
110
+ const frames = [];
111
+ const frameDuration = 1 / fps;
112
+ for (let time = startTime; time <= endTime; time += frameDuration) {
113
+ await this.renderFrame(time);
114
+ frames.push(await this.lazyCanvas.canvas.encode("png"));
115
+ }
116
+ return frames;
117
+ }
118
+ /**
119
+ * Render multiple frames and return as ImageData array (much faster)
120
+ * @param startTime - Start time in seconds
121
+ * @param endTime - End time in seconds
122
+ * @param fps - Frames per second (default: 30)
123
+ * @returns Array of Uint8ClampedArray for each frame
124
+ */
125
+ async renderAnimationData(startTime, endTime, fps = 30) {
126
+ const frames = [];
127
+ const frameDuration = 1 / fps;
128
+ for (let time = startTime; time <= endTime; time += frameDuration) {
129
+ await this.renderFrame(time);
130
+ frames.push(this.getImageData());
131
+ }
132
+ return frames;
133
+ }
134
+ /**
135
+ * Get a layer by ID from the manager
136
+ * @param id - Layer ID
137
+ * @returns Layer or undefined
138
+ */
139
+ getLayer(id) {
140
+ return this.lazyCanvas.manager.layers.get(id, true);
141
+ }
142
+ /**
143
+ * Add animation generator to scheduler
144
+ * @param generator - Animation generator to run
145
+ */
146
+ addAnimation(generator) {
147
+ this.scheduler.add(generator);
148
+ }
149
+ /**
150
+ * Play animation on a signal
151
+ * @param signal - Signal to animate
152
+ * @param generator - Animation generator
153
+ */
154
+ playAnimation(signal, generator) {
155
+ signal.run(generator);
156
+ this.scheduler.add(generator);
157
+ }
158
+ /**
159
+ * Clear all animations
160
+ */
161
+ clearAnimations() {
162
+ this.scheduler.clear();
163
+ }
164
+ /**
165
+ * Reset scene timeline
166
+ */
167
+ resetTimeline() {
168
+ this.scheduler.reset();
169
+ this.lastFrameTime = 0;
170
+ }
171
+ }
172
+ exports.Scene = Scene;
@@ -0,0 +1,133 @@
1
+ import { Interpolator } from "./Interpolation";
2
+ /**
3
+ * Easing function type
4
+ */
5
+ export type EasingFunction = (t: number) => number;
6
+ /**
7
+ * Standard easing functions
8
+ */
9
+ export declare const Easing: {
10
+ linear: (t: number) => number;
11
+ easeIn: (t: number) => number;
12
+ easeOut: (t: number) => number;
13
+ easeInOut: (t: number) => number;
14
+ easeInCubic: (t: number) => number;
15
+ easeOutCubic: (t: number) => number;
16
+ easeInOutCubic: (t: number) => number;
17
+ easeInQuart: (t: number) => number;
18
+ easeOutQuart: (t: number) => number;
19
+ easeInOutQuart: (t: number) => number;
20
+ easeInQuint: (t: number) => number;
21
+ easeOutQuint: (t: number) => number;
22
+ easeInOutQuint: (t: number) => number;
23
+ easeInSine: (t: number) => number;
24
+ easeOutSine: (t: number) => number;
25
+ easeInOutSine: (t: number) => number;
26
+ easeInExpo: (t: number) => number;
27
+ easeOutExpo: (t: number) => number;
28
+ easeInOutExpo: (t: number) => number;
29
+ easeInCirc: (t: number) => number;
30
+ easeOutCirc: (t: number) => number;
31
+ easeInOutCirc: (t: number) => number;
32
+ easeInBack: (t: number) => number;
33
+ easeOutBack: (t: number) => number;
34
+ easeInOutBack: (t: number) => number;
35
+ easeInElastic: (t: number) => number;
36
+ easeOutElastic: (t: number) => number;
37
+ easeInOutElastic: (t: number) => number;
38
+ easeInBounce: (t: number) => number;
39
+ easeOutBounce: (t: number) => number;
40
+ easeInOutBounce: (t: number) => number;
41
+ };
42
+ /**
43
+ * Thread generator type - the core of animation system
44
+ */
45
+ export type ThreadGenerator = Generator<void | number, void, number | void>;
46
+ /**
47
+ * Tween configuration
48
+ */
49
+ export interface TweenConfig<T> {
50
+ to: T;
51
+ duration: number;
52
+ easing?: EasingFunction;
53
+ interpolator?: Interpolator<T>;
54
+ colorSpace?: "rgb" | "hsl";
55
+ }
56
+ /**
57
+ * Signal options
58
+ */
59
+ export interface SignalOptions<T> {
60
+ interpolator?: Interpolator<T>;
61
+ colorSpace?: "rgb" | "hsl";
62
+ }
63
+ /**
64
+ * Signal class - reactive value that can be animated
65
+ */
66
+ export declare class Signal<T = number> {
67
+ private _value;
68
+ private _initialValue;
69
+ private _currentThread;
70
+ private _interpolator;
71
+ private _colorSpace;
72
+ constructor(initial: T, options?: SignalOptions<T>);
73
+ /**
74
+ * Get current value at specific time (backward compatibility)
75
+ */
76
+ get(time: number): T;
77
+ /**
78
+ * Get current value (sync)
79
+ */
80
+ value(): T;
81
+ /**
82
+ * Set value directly
83
+ */
84
+ set(value: T): void;
85
+ /**
86
+ * Reset to initial value
87
+ */
88
+ reset(): void;
89
+ /**
90
+ * Animate to a new value - returns a generator
91
+ */
92
+ to(value: T, duration: number, config?: Partial<TweenConfig<T>> & {
93
+ easing?: EasingFunction;
94
+ }): ThreadGenerator;
95
+ /**
96
+ * Wait for a duration without changing value
97
+ */
98
+ wait(duration: number): ThreadGenerator;
99
+ /**
100
+ * Run animation from generator
101
+ */
102
+ run(generator: ThreadGenerator): this;
103
+ /**
104
+ * Update signal (called by scheduler)
105
+ */
106
+ update(delta: number): boolean;
107
+ /**
108
+ * Check if signal has active animation
109
+ */
110
+ isAnimating(): boolean;
111
+ /**
112
+ * Internal: get interpolator for values
113
+ */
114
+ private _getInterpolator;
115
+ }
116
+ /**
117
+ * Create a new signal
118
+ */
119
+ export declare function createSignal<T = number>(initial: T, options?: SignalOptions<T>): Signal<T>;
120
+ /**
121
+ * Type guard for signals
122
+ */
123
+ export declare function isSignal<T>(value: any): value is Signal<T>;
124
+ /**
125
+ * Unwrap signal or return value
126
+ */
127
+ export declare function unwrap<T>(value: T | Signal<T>): T extends Signal<infer U> ? U : T;
128
+ /**
129
+ * Reset multiple signals to their initial values
130
+ */
131
+ export declare function resetSignals(...signals: Signal<any>[]): void;
132
+ export type SignalValue<T> = T | Signal<T>;
133
+ export default Signal;