mason-sprite 0.1.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/LICENSE +21 -0
- package/README.md +134 -0
- package/dist/index.cjs +273 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +84 -0
- package/dist/index.d.ts +84 -0
- package/dist/index.js +242 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.cjs +353 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.cts +61 -0
- package/dist/react/index.d.ts +61 -0
- package/dist/react/index.js +325 -0
- package/dist/react/index.js.map +1 -0
- package/dist/svelte/Sprite.svelte +88 -0
- package/dist/svelte/Sprite.svelte.d.ts +14 -0
- package/dist/svelte/Sprite.svelte.d.ts.map +1 -0
- package/dist/svelte/index.d.ts +2 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +1 -0
- package/dist/vue/Sprite.vue.d.ts +28 -0
- package/dist/vue/Sprite.vue.d.ts.map +1 -0
- package/dist/vue/index.cjs +1 -0
- package/dist/vue/index.d.ts +2 -0
- package/dist/vue/index.d.ts.map +1 -0
- package/dist/vue/index.js +205 -0
- package/package.json +125 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
// src/core/constants.ts
|
|
2
|
+
var SPRITE_ANIMATION_DEFAULTS = {
|
|
3
|
+
fps: 12,
|
|
4
|
+
loop: true,
|
|
5
|
+
width: 128,
|
|
6
|
+
height: 128,
|
|
7
|
+
autoPlay: true,
|
|
8
|
+
renderer: "css"
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// src/core/utils.ts
|
|
12
|
+
function getTotalFrames(rows, cols) {
|
|
13
|
+
return rows * cols;
|
|
14
|
+
}
|
|
15
|
+
function getFramePosition(frameIndex, cols) {
|
|
16
|
+
return {
|
|
17
|
+
row: Math.floor(frameIndex / cols),
|
|
18
|
+
col: frameIndex % cols
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
function getBackgroundPositionPercent(frameIndex, rows, cols) {
|
|
22
|
+
const { row, col } = getFramePosition(frameIndex, cols);
|
|
23
|
+
const x = cols <= 1 ? 0 : col / (cols - 1) * 100;
|
|
24
|
+
const y = rows <= 1 ? 0 : row / (rows - 1) * 100;
|
|
25
|
+
return { x, y };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/core/canvas-renderer.ts
|
|
29
|
+
function drawCanvasFrame(canvas, image, frameIndex, rows, cols, width, height) {
|
|
30
|
+
const ctx = canvas.getContext("2d");
|
|
31
|
+
if (!ctx) return;
|
|
32
|
+
const frameWidth = image.naturalWidth / cols;
|
|
33
|
+
const frameHeight = image.naturalHeight / rows;
|
|
34
|
+
const { row, col } = getFramePosition(frameIndex, cols);
|
|
35
|
+
canvas.width = width;
|
|
36
|
+
canvas.height = height;
|
|
37
|
+
ctx.clearRect(0, 0, width, height);
|
|
38
|
+
ctx.drawImage(
|
|
39
|
+
image,
|
|
40
|
+
col * frameWidth,
|
|
41
|
+
row * frameHeight,
|
|
42
|
+
frameWidth,
|
|
43
|
+
frameHeight,
|
|
44
|
+
0,
|
|
45
|
+
0,
|
|
46
|
+
width,
|
|
47
|
+
height
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/core/css-renderer.ts
|
|
52
|
+
function applyCssFrame(target, src, frameIndex, rows, cols, width, height) {
|
|
53
|
+
const { x, y } = getBackgroundPositionPercent(frameIndex, rows, cols);
|
|
54
|
+
target.style.backgroundImage = `url("${src}")`;
|
|
55
|
+
target.style.backgroundRepeat = "no-repeat";
|
|
56
|
+
target.style.backgroundSize = `${cols * 100}% ${rows * 100}%`;
|
|
57
|
+
target.style.backgroundPosition = `${x}% ${y}%`;
|
|
58
|
+
target.style.width = `${width}px`;
|
|
59
|
+
target.style.height = `${height}px`;
|
|
60
|
+
target.style.display = "inline-block";
|
|
61
|
+
}
|
|
62
|
+
function resetCssRenderer(target) {
|
|
63
|
+
target.style.backgroundImage = "";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// src/core/sprite-animator.ts
|
|
67
|
+
var SpriteAnimator = class {
|
|
68
|
+
constructor(options) {
|
|
69
|
+
this.currentFrame = 0;
|
|
70
|
+
this.isPlaying = false;
|
|
71
|
+
this.isLoaded = false;
|
|
72
|
+
this.rafId = null;
|
|
73
|
+
this.lastTimestamp = 0;
|
|
74
|
+
this.accumulatedTime = 0;
|
|
75
|
+
this.image = null;
|
|
76
|
+
this.target = null;
|
|
77
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
78
|
+
this.destroyed = false;
|
|
79
|
+
this.tick = (timestamp) => {
|
|
80
|
+
if (!this.isPlaying || this.destroyed) return;
|
|
81
|
+
if (this.lastTimestamp === 0) {
|
|
82
|
+
this.lastTimestamp = timestamp;
|
|
83
|
+
}
|
|
84
|
+
const delta = timestamp - this.lastTimestamp;
|
|
85
|
+
this.lastTimestamp = timestamp;
|
|
86
|
+
this.accumulatedTime += delta;
|
|
87
|
+
const frameDuration = 1e3 / this.options.fps;
|
|
88
|
+
while (this.accumulatedTime >= frameDuration) {
|
|
89
|
+
this.accumulatedTime -= frameDuration;
|
|
90
|
+
this.advanceFrame();
|
|
91
|
+
}
|
|
92
|
+
this.rafId = requestAnimationFrame(this.tick);
|
|
93
|
+
};
|
|
94
|
+
this.options = {
|
|
95
|
+
...SPRITE_ANIMATION_DEFAULTS,
|
|
96
|
+
...options
|
|
97
|
+
};
|
|
98
|
+
this.loadImage();
|
|
99
|
+
}
|
|
100
|
+
attach(target) {
|
|
101
|
+
this.target = target;
|
|
102
|
+
if (this.isLoaded) {
|
|
103
|
+
this.render();
|
|
104
|
+
}
|
|
105
|
+
if (this.options.autoPlay) {
|
|
106
|
+
this.play();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
play() {
|
|
110
|
+
if (this.destroyed || this.isPlaying) return;
|
|
111
|
+
this.isPlaying = true;
|
|
112
|
+
this.lastTimestamp = 0;
|
|
113
|
+
this.accumulatedTime = 0;
|
|
114
|
+
this.rafId = requestAnimationFrame(this.tick);
|
|
115
|
+
this.notify();
|
|
116
|
+
}
|
|
117
|
+
pause() {
|
|
118
|
+
if (!this.isPlaying) return;
|
|
119
|
+
this.isPlaying = false;
|
|
120
|
+
if (this.rafId !== null) {
|
|
121
|
+
cancelAnimationFrame(this.rafId);
|
|
122
|
+
this.rafId = null;
|
|
123
|
+
}
|
|
124
|
+
this.notify();
|
|
125
|
+
}
|
|
126
|
+
stop() {
|
|
127
|
+
this.pause();
|
|
128
|
+
this.currentFrame = 0;
|
|
129
|
+
this.render();
|
|
130
|
+
this.notify();
|
|
131
|
+
}
|
|
132
|
+
goToFrame(frame) {
|
|
133
|
+
const total = this.getTotalFrames();
|
|
134
|
+
this.currentFrame = Math.max(0, Math.min(frame, total - 1));
|
|
135
|
+
this.render();
|
|
136
|
+
this.options.onFrameChange?.(this.currentFrame);
|
|
137
|
+
this.notify();
|
|
138
|
+
}
|
|
139
|
+
getState() {
|
|
140
|
+
return {
|
|
141
|
+
currentFrame: this.currentFrame,
|
|
142
|
+
totalFrames: this.getTotalFrames(),
|
|
143
|
+
isPlaying: this.isPlaying,
|
|
144
|
+
isLoaded: this.isLoaded
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
subscribe(listener) {
|
|
148
|
+
this.listeners.add(listener);
|
|
149
|
+
listener(this.getState());
|
|
150
|
+
return () => this.listeners.delete(listener);
|
|
151
|
+
}
|
|
152
|
+
updateOptions(partial) {
|
|
153
|
+
const prevSrc = this.options.src;
|
|
154
|
+
const prevFps = this.options.fps;
|
|
155
|
+
this.options = { ...this.options, ...partial };
|
|
156
|
+
if (partial.src !== void 0 && partial.src !== prevSrc) {
|
|
157
|
+
this.loadImage();
|
|
158
|
+
} else if (this.isLoaded) {
|
|
159
|
+
this.render();
|
|
160
|
+
}
|
|
161
|
+
if (partial.fps !== void 0 && partial.fps !== prevFps) {
|
|
162
|
+
this.accumulatedTime = 0;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
destroy() {
|
|
166
|
+
this.destroyed = true;
|
|
167
|
+
this.pause();
|
|
168
|
+
this.listeners.clear();
|
|
169
|
+
if (this.target && this.options.renderer === "css") {
|
|
170
|
+
resetCssRenderer(this.target);
|
|
171
|
+
}
|
|
172
|
+
this.target = null;
|
|
173
|
+
this.image = null;
|
|
174
|
+
}
|
|
175
|
+
getTotalFrames() {
|
|
176
|
+
return getTotalFrames(this.options.rows, this.options.cols);
|
|
177
|
+
}
|
|
178
|
+
loadImage() {
|
|
179
|
+
this.isLoaded = false;
|
|
180
|
+
const img = new Image();
|
|
181
|
+
img.crossOrigin = "anonymous";
|
|
182
|
+
img.onload = () => {
|
|
183
|
+
if (this.destroyed) return;
|
|
184
|
+
this.image = img;
|
|
185
|
+
this.isLoaded = true;
|
|
186
|
+
if (!this.options.width || !this.options.height) {
|
|
187
|
+
const frameWidth = img.naturalWidth / this.options.cols;
|
|
188
|
+
const frameHeight = img.naturalHeight / this.options.rows;
|
|
189
|
+
this.options.width = frameWidth;
|
|
190
|
+
this.options.height = frameHeight;
|
|
191
|
+
}
|
|
192
|
+
this.render();
|
|
193
|
+
this.notify();
|
|
194
|
+
if (this.options.autoPlay && this.target) {
|
|
195
|
+
this.play();
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
img.onerror = () => {
|
|
199
|
+
console.error(`[SpriteAnimator] Failed to load image: ${this.options.src}`);
|
|
200
|
+
};
|
|
201
|
+
img.src = this.options.src;
|
|
202
|
+
}
|
|
203
|
+
advanceFrame() {
|
|
204
|
+
const total = this.getTotalFrames();
|
|
205
|
+
const next = this.currentFrame + 1;
|
|
206
|
+
if (next >= total) {
|
|
207
|
+
if (this.options.loop) {
|
|
208
|
+
this.currentFrame = 0;
|
|
209
|
+
} else {
|
|
210
|
+
this.currentFrame = total - 1;
|
|
211
|
+
this.pause();
|
|
212
|
+
this.options.onComplete?.();
|
|
213
|
+
}
|
|
214
|
+
} else {
|
|
215
|
+
this.currentFrame = next;
|
|
216
|
+
}
|
|
217
|
+
this.render();
|
|
218
|
+
this.options.onFrameChange?.(this.currentFrame);
|
|
219
|
+
this.notify();
|
|
220
|
+
}
|
|
221
|
+
render() {
|
|
222
|
+
if (!this.target || !this.isLoaded) return;
|
|
223
|
+
const { src, rows, cols, width, height, renderer } = this.options;
|
|
224
|
+
if (renderer === "canvas" && this.target instanceof HTMLCanvasElement && this.image) {
|
|
225
|
+
drawCanvasFrame(this.target, this.image, this.currentFrame, rows, cols, width, height);
|
|
226
|
+
} else if (renderer === "css" && this.target instanceof HTMLElement) {
|
|
227
|
+
applyCssFrame(this.target, src, this.currentFrame, rows, cols, width, height);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
notify() {
|
|
231
|
+
const state = this.getState();
|
|
232
|
+
this.listeners.forEach((listener) => listener(state));
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
export {
|
|
236
|
+
SPRITE_ANIMATION_DEFAULTS,
|
|
237
|
+
SpriteAnimator,
|
|
238
|
+
getBackgroundPositionPercent,
|
|
239
|
+
getFramePosition,
|
|
240
|
+
getTotalFrames
|
|
241
|
+
};
|
|
242
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/constants.ts","../src/core/utils.ts","../src/core/canvas-renderer.ts","../src/core/css-renderer.ts","../src/core/sprite-animator.ts"],"sourcesContent":["import type { RendererMode } from './types.js';\n\nexport const SPRITE_ANIMATION_DEFAULTS = {\n fps: 12,\n loop: true,\n width: 128,\n height: 128,\n autoPlay: true,\n renderer: 'css' as RendererMode,\n} as const;\n","import type { FramePosition } from './types.js';\n\nexport function getTotalFrames(rows: number, cols: number): number {\n return rows * cols;\n}\n\nexport function getFramePosition(frameIndex: number, cols: number): FramePosition {\n return {\n row: Math.floor(frameIndex / cols),\n col: frameIndex % cols,\n };\n}\n\nexport function getBackgroundPositionPercent(\n frameIndex: number,\n rows: number,\n cols: number,\n): { x: number; y: number } {\n const { row, col } = getFramePosition(frameIndex, cols);\n const x = cols <= 1 ? 0 : (col / (cols - 1)) * 100;\n const y = rows <= 1 ? 0 : (row / (rows - 1)) * 100;\n return { x, y };\n}\n","import { getFramePosition } from './utils.js';\n\nexport function drawCanvasFrame(\n canvas: HTMLCanvasElement,\n image: HTMLImageElement,\n frameIndex: number,\n rows: number,\n cols: number,\n width: number,\n height: number,\n): void {\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const frameWidth = image.naturalWidth / cols;\n const frameHeight = image.naturalHeight / rows;\n const { row, col } = getFramePosition(frameIndex, cols);\n\n canvas.width = width;\n canvas.height = height;\n\n ctx.clearRect(0, 0, width, height);\n ctx.drawImage(\n image,\n col * frameWidth,\n row * frameHeight,\n frameWidth,\n frameHeight,\n 0,\n 0,\n width,\n height,\n );\n}\n","import { getBackgroundPositionPercent } from './utils.js';\n\nexport interface CssRendererTarget {\n style: CSSStyleDeclaration;\n}\n\nexport function applyCssFrame(\n target: CssRendererTarget,\n src: string,\n frameIndex: number,\n rows: number,\n cols: number,\n width: number,\n height: number,\n): void {\n const { x, y } = getBackgroundPositionPercent(frameIndex, rows, cols);\n\n target.style.backgroundImage = `url(\"${src}\")`;\n target.style.backgroundRepeat = 'no-repeat';\n target.style.backgroundSize = `${cols * 100}% ${rows * 100}%`;\n target.style.backgroundPosition = `${x}% ${y}%`;\n target.style.width = `${width}px`;\n target.style.height = `${height}px`;\n target.style.display = 'inline-block';\n}\n\nexport function resetCssRenderer(target: CssRendererTarget): void {\n target.style.backgroundImage = '';\n}\n","import { SPRITE_ANIMATION_DEFAULTS } from './constants.js';\nimport { drawCanvasFrame } from './canvas-renderer.js';\nimport { applyCssFrame, resetCssRenderer } from './css-renderer.js';\nimport type { SpriteAnimationOptions, SpriteAnimationState } from './types.js';\nimport { getTotalFrames } from './utils.js';\n\ntype StateListener = (state: SpriteAnimationState) => void;\n\ntype ResolvedSpriteAnimationOptions = Required<\n Pick<SpriteAnimationOptions, 'src' | 'rows' | 'cols'>\n> &\n Required<Pick<SpriteAnimationOptions, 'fps' | 'loop' | 'width' | 'height' | 'autoPlay' | 'renderer'>> &\n Pick<SpriteAnimationOptions, 'onComplete' | 'onFrameChange'>;\n\nexport class SpriteAnimator {\n private options: ResolvedSpriteAnimationOptions;\n private currentFrame = 0;\n private isPlaying = false;\n private isLoaded = false;\n private rafId: number | null = null;\n private lastTimestamp = 0;\n private accumulatedTime = 0;\n private image: HTMLImageElement | null = null;\n private target: HTMLElement | HTMLCanvasElement | null = null;\n private listeners = new Set<StateListener>();\n private destroyed = false;\n\n constructor(options: SpriteAnimationOptions) {\n this.options = {\n ...SPRITE_ANIMATION_DEFAULTS,\n ...options,\n };\n this.loadImage();\n }\n\n attach(target: HTMLElement | HTMLCanvasElement): void {\n this.target = target;\n if (this.isLoaded) {\n this.render();\n }\n if (this.options.autoPlay) {\n this.play();\n }\n }\n\n play(): void {\n if (this.destroyed || this.isPlaying) return;\n this.isPlaying = true;\n this.lastTimestamp = 0;\n this.accumulatedTime = 0;\n this.rafId = requestAnimationFrame(this.tick);\n this.notify();\n }\n\n pause(): void {\n if (!this.isPlaying) return;\n this.isPlaying = false;\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n this.notify();\n }\n\n stop(): void {\n this.pause();\n this.currentFrame = 0;\n this.render();\n this.notify();\n }\n\n goToFrame(frame: number): void {\n const total = this.getTotalFrames();\n this.currentFrame = Math.max(0, Math.min(frame, total - 1));\n this.render();\n this.options.onFrameChange?.(this.currentFrame);\n this.notify();\n }\n\n getState(): SpriteAnimationState {\n return {\n currentFrame: this.currentFrame,\n totalFrames: this.getTotalFrames(),\n isPlaying: this.isPlaying,\n isLoaded: this.isLoaded,\n };\n }\n\n subscribe(listener: StateListener): () => void {\n this.listeners.add(listener);\n listener(this.getState());\n return () => this.listeners.delete(listener);\n }\n\n updateOptions(partial: Partial<SpriteAnimationOptions>): void {\n const prevSrc = this.options.src;\n const prevFps = this.options.fps;\n this.options = { ...this.options, ...partial };\n\n if (partial.src !== undefined && partial.src !== prevSrc) {\n this.loadImage();\n } else if (this.isLoaded) {\n this.render();\n }\n\n if (partial.fps !== undefined && partial.fps !== prevFps) {\n this.accumulatedTime = 0;\n }\n }\n\n destroy(): void {\n this.destroyed = true;\n this.pause();\n this.listeners.clear();\n if (this.target && this.options.renderer === 'css') {\n resetCssRenderer(this.target);\n }\n this.target = null;\n this.image = null;\n }\n\n private getTotalFrames(): number {\n return getTotalFrames(this.options.rows, this.options.cols);\n }\n\n private loadImage(): void {\n this.isLoaded = false;\n const img = new Image();\n img.crossOrigin = 'anonymous';\n img.onload = () => {\n if (this.destroyed) return;\n this.image = img;\n this.isLoaded = true;\n\n if (!this.options.width || !this.options.height) {\n const frameWidth = img.naturalWidth / this.options.cols;\n const frameHeight = img.naturalHeight / this.options.rows;\n this.options.width = frameWidth;\n this.options.height = frameHeight;\n }\n\n this.render();\n this.notify();\n\n if (this.options.autoPlay && this.target) {\n this.play();\n }\n };\n img.onerror = () => {\n console.error(`[SpriteAnimator] Failed to load image: ${this.options.src}`);\n };\n img.src = this.options.src;\n }\n\n private tick = (timestamp: number): void => {\n if (!this.isPlaying || this.destroyed) return;\n\n if (this.lastTimestamp === 0) {\n this.lastTimestamp = timestamp;\n }\n\n const delta = timestamp - this.lastTimestamp;\n this.lastTimestamp = timestamp;\n this.accumulatedTime += delta;\n\n const frameDuration = 1000 / this.options.fps;\n while (this.accumulatedTime >= frameDuration) {\n this.accumulatedTime -= frameDuration;\n this.advanceFrame();\n }\n\n this.rafId = requestAnimationFrame(this.tick);\n };\n\n private advanceFrame(): void {\n const total = this.getTotalFrames();\n const next = this.currentFrame + 1;\n\n if (next >= total) {\n if (this.options.loop) {\n this.currentFrame = 0;\n } else {\n this.currentFrame = total - 1;\n this.pause();\n this.options.onComplete?.();\n }\n } else {\n this.currentFrame = next;\n }\n\n this.render();\n this.options.onFrameChange?.(this.currentFrame);\n this.notify();\n }\n\n private render(): void {\n if (!this.target || !this.isLoaded) return;\n\n const { src, rows, cols, width, height, renderer } = this.options;\n\n if (renderer === 'canvas' && this.target instanceof HTMLCanvasElement && this.image) {\n drawCanvasFrame(this.target, this.image, this.currentFrame, rows, cols, width, height);\n } else if (renderer === 'css' && this.target instanceof HTMLElement) {\n applyCssFrame(this.target, src, this.currentFrame, rows, cols, width, height);\n }\n }\n\n private notify(): void {\n const state = this.getState();\n this.listeners.forEach((listener) => listener(state));\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/react/index.ts
|
|
21
|
+
var react_exports = {};
|
|
22
|
+
__export(react_exports, {
|
|
23
|
+
Sprite: () => Sprite,
|
|
24
|
+
useSprite: () => useSprite
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(react_exports);
|
|
27
|
+
|
|
28
|
+
// src/react/Sprite.tsx
|
|
29
|
+
var import_react2 = require("react");
|
|
30
|
+
|
|
31
|
+
// src/core/constants.ts
|
|
32
|
+
var SPRITE_ANIMATION_DEFAULTS = {
|
|
33
|
+
fps: 12,
|
|
34
|
+
loop: true,
|
|
35
|
+
width: 128,
|
|
36
|
+
height: 128,
|
|
37
|
+
autoPlay: true,
|
|
38
|
+
renderer: "css"
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
// src/core/utils.ts
|
|
42
|
+
function getTotalFrames(rows, cols) {
|
|
43
|
+
return rows * cols;
|
|
44
|
+
}
|
|
45
|
+
function getFramePosition(frameIndex, cols) {
|
|
46
|
+
return {
|
|
47
|
+
row: Math.floor(frameIndex / cols),
|
|
48
|
+
col: frameIndex % cols
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function getBackgroundPositionPercent(frameIndex, rows, cols) {
|
|
52
|
+
const { row, col } = getFramePosition(frameIndex, cols);
|
|
53
|
+
const x = cols <= 1 ? 0 : col / (cols - 1) * 100;
|
|
54
|
+
const y = rows <= 1 ? 0 : row / (rows - 1) * 100;
|
|
55
|
+
return { x, y };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/core/canvas-renderer.ts
|
|
59
|
+
function drawCanvasFrame(canvas, image, frameIndex, rows, cols, width, height) {
|
|
60
|
+
const ctx = canvas.getContext("2d");
|
|
61
|
+
if (!ctx) return;
|
|
62
|
+
const frameWidth = image.naturalWidth / cols;
|
|
63
|
+
const frameHeight = image.naturalHeight / rows;
|
|
64
|
+
const { row, col } = getFramePosition(frameIndex, cols);
|
|
65
|
+
canvas.width = width;
|
|
66
|
+
canvas.height = height;
|
|
67
|
+
ctx.clearRect(0, 0, width, height);
|
|
68
|
+
ctx.drawImage(
|
|
69
|
+
image,
|
|
70
|
+
col * frameWidth,
|
|
71
|
+
row * frameHeight,
|
|
72
|
+
frameWidth,
|
|
73
|
+
frameHeight,
|
|
74
|
+
0,
|
|
75
|
+
0,
|
|
76
|
+
width,
|
|
77
|
+
height
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/core/css-renderer.ts
|
|
82
|
+
function applyCssFrame(target, src, frameIndex, rows, cols, width, height) {
|
|
83
|
+
const { x, y } = getBackgroundPositionPercent(frameIndex, rows, cols);
|
|
84
|
+
target.style.backgroundImage = `url("${src}")`;
|
|
85
|
+
target.style.backgroundRepeat = "no-repeat";
|
|
86
|
+
target.style.backgroundSize = `${cols * 100}% ${rows * 100}%`;
|
|
87
|
+
target.style.backgroundPosition = `${x}% ${y}%`;
|
|
88
|
+
target.style.width = `${width}px`;
|
|
89
|
+
target.style.height = `${height}px`;
|
|
90
|
+
target.style.display = "inline-block";
|
|
91
|
+
}
|
|
92
|
+
function resetCssRenderer(target) {
|
|
93
|
+
target.style.backgroundImage = "";
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// src/core/sprite-animator.ts
|
|
97
|
+
var SpriteAnimator = class {
|
|
98
|
+
constructor(options) {
|
|
99
|
+
this.currentFrame = 0;
|
|
100
|
+
this.isPlaying = false;
|
|
101
|
+
this.isLoaded = false;
|
|
102
|
+
this.rafId = null;
|
|
103
|
+
this.lastTimestamp = 0;
|
|
104
|
+
this.accumulatedTime = 0;
|
|
105
|
+
this.image = null;
|
|
106
|
+
this.target = null;
|
|
107
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
108
|
+
this.destroyed = false;
|
|
109
|
+
this.tick = (timestamp) => {
|
|
110
|
+
if (!this.isPlaying || this.destroyed) return;
|
|
111
|
+
if (this.lastTimestamp === 0) {
|
|
112
|
+
this.lastTimestamp = timestamp;
|
|
113
|
+
}
|
|
114
|
+
const delta = timestamp - this.lastTimestamp;
|
|
115
|
+
this.lastTimestamp = timestamp;
|
|
116
|
+
this.accumulatedTime += delta;
|
|
117
|
+
const frameDuration = 1e3 / this.options.fps;
|
|
118
|
+
while (this.accumulatedTime >= frameDuration) {
|
|
119
|
+
this.accumulatedTime -= frameDuration;
|
|
120
|
+
this.advanceFrame();
|
|
121
|
+
}
|
|
122
|
+
this.rafId = requestAnimationFrame(this.tick);
|
|
123
|
+
};
|
|
124
|
+
this.options = {
|
|
125
|
+
...SPRITE_ANIMATION_DEFAULTS,
|
|
126
|
+
...options
|
|
127
|
+
};
|
|
128
|
+
this.loadImage();
|
|
129
|
+
}
|
|
130
|
+
attach(target) {
|
|
131
|
+
this.target = target;
|
|
132
|
+
if (this.isLoaded) {
|
|
133
|
+
this.render();
|
|
134
|
+
}
|
|
135
|
+
if (this.options.autoPlay) {
|
|
136
|
+
this.play();
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
play() {
|
|
140
|
+
if (this.destroyed || this.isPlaying) return;
|
|
141
|
+
this.isPlaying = true;
|
|
142
|
+
this.lastTimestamp = 0;
|
|
143
|
+
this.accumulatedTime = 0;
|
|
144
|
+
this.rafId = requestAnimationFrame(this.tick);
|
|
145
|
+
this.notify();
|
|
146
|
+
}
|
|
147
|
+
pause() {
|
|
148
|
+
if (!this.isPlaying) return;
|
|
149
|
+
this.isPlaying = false;
|
|
150
|
+
if (this.rafId !== null) {
|
|
151
|
+
cancelAnimationFrame(this.rafId);
|
|
152
|
+
this.rafId = null;
|
|
153
|
+
}
|
|
154
|
+
this.notify();
|
|
155
|
+
}
|
|
156
|
+
stop() {
|
|
157
|
+
this.pause();
|
|
158
|
+
this.currentFrame = 0;
|
|
159
|
+
this.render();
|
|
160
|
+
this.notify();
|
|
161
|
+
}
|
|
162
|
+
goToFrame(frame) {
|
|
163
|
+
const total = this.getTotalFrames();
|
|
164
|
+
this.currentFrame = Math.max(0, Math.min(frame, total - 1));
|
|
165
|
+
this.render();
|
|
166
|
+
this.options.onFrameChange?.(this.currentFrame);
|
|
167
|
+
this.notify();
|
|
168
|
+
}
|
|
169
|
+
getState() {
|
|
170
|
+
return {
|
|
171
|
+
currentFrame: this.currentFrame,
|
|
172
|
+
totalFrames: this.getTotalFrames(),
|
|
173
|
+
isPlaying: this.isPlaying,
|
|
174
|
+
isLoaded: this.isLoaded
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
subscribe(listener) {
|
|
178
|
+
this.listeners.add(listener);
|
|
179
|
+
listener(this.getState());
|
|
180
|
+
return () => this.listeners.delete(listener);
|
|
181
|
+
}
|
|
182
|
+
updateOptions(partial) {
|
|
183
|
+
const prevSrc = this.options.src;
|
|
184
|
+
const prevFps = this.options.fps;
|
|
185
|
+
this.options = { ...this.options, ...partial };
|
|
186
|
+
if (partial.src !== void 0 && partial.src !== prevSrc) {
|
|
187
|
+
this.loadImage();
|
|
188
|
+
} else if (this.isLoaded) {
|
|
189
|
+
this.render();
|
|
190
|
+
}
|
|
191
|
+
if (partial.fps !== void 0 && partial.fps !== prevFps) {
|
|
192
|
+
this.accumulatedTime = 0;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
destroy() {
|
|
196
|
+
this.destroyed = true;
|
|
197
|
+
this.pause();
|
|
198
|
+
this.listeners.clear();
|
|
199
|
+
if (this.target && this.options.renderer === "css") {
|
|
200
|
+
resetCssRenderer(this.target);
|
|
201
|
+
}
|
|
202
|
+
this.target = null;
|
|
203
|
+
this.image = null;
|
|
204
|
+
}
|
|
205
|
+
getTotalFrames() {
|
|
206
|
+
return getTotalFrames(this.options.rows, this.options.cols);
|
|
207
|
+
}
|
|
208
|
+
loadImage() {
|
|
209
|
+
this.isLoaded = false;
|
|
210
|
+
const img = new Image();
|
|
211
|
+
img.crossOrigin = "anonymous";
|
|
212
|
+
img.onload = () => {
|
|
213
|
+
if (this.destroyed) return;
|
|
214
|
+
this.image = img;
|
|
215
|
+
this.isLoaded = true;
|
|
216
|
+
if (!this.options.width || !this.options.height) {
|
|
217
|
+
const frameWidth = img.naturalWidth / this.options.cols;
|
|
218
|
+
const frameHeight = img.naturalHeight / this.options.rows;
|
|
219
|
+
this.options.width = frameWidth;
|
|
220
|
+
this.options.height = frameHeight;
|
|
221
|
+
}
|
|
222
|
+
this.render();
|
|
223
|
+
this.notify();
|
|
224
|
+
if (this.options.autoPlay && this.target) {
|
|
225
|
+
this.play();
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
img.onerror = () => {
|
|
229
|
+
console.error(`[SpriteAnimator] Failed to load image: ${this.options.src}`);
|
|
230
|
+
};
|
|
231
|
+
img.src = this.options.src;
|
|
232
|
+
}
|
|
233
|
+
advanceFrame() {
|
|
234
|
+
const total = this.getTotalFrames();
|
|
235
|
+
const next = this.currentFrame + 1;
|
|
236
|
+
if (next >= total) {
|
|
237
|
+
if (this.options.loop) {
|
|
238
|
+
this.currentFrame = 0;
|
|
239
|
+
} else {
|
|
240
|
+
this.currentFrame = total - 1;
|
|
241
|
+
this.pause();
|
|
242
|
+
this.options.onComplete?.();
|
|
243
|
+
}
|
|
244
|
+
} else {
|
|
245
|
+
this.currentFrame = next;
|
|
246
|
+
}
|
|
247
|
+
this.render();
|
|
248
|
+
this.options.onFrameChange?.(this.currentFrame);
|
|
249
|
+
this.notify();
|
|
250
|
+
}
|
|
251
|
+
render() {
|
|
252
|
+
if (!this.target || !this.isLoaded) return;
|
|
253
|
+
const { src, rows, cols, width, height, renderer } = this.options;
|
|
254
|
+
if (renderer === "canvas" && this.target instanceof HTMLCanvasElement && this.image) {
|
|
255
|
+
drawCanvasFrame(this.target, this.image, this.currentFrame, rows, cols, width, height);
|
|
256
|
+
} else if (renderer === "css" && this.target instanceof HTMLElement) {
|
|
257
|
+
applyCssFrame(this.target, src, this.currentFrame, rows, cols, width, height);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
notify() {
|
|
261
|
+
const state = this.getState();
|
|
262
|
+
this.listeners.forEach((listener) => listener(state));
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
|
|
266
|
+
// src/react/useSprite.ts
|
|
267
|
+
var import_react = require("react");
|
|
268
|
+
function useSprite(options) {
|
|
269
|
+
const ref = (0, import_react.useRef)(null);
|
|
270
|
+
const animatorRef = (0, import_react.useRef)(null);
|
|
271
|
+
const [state, setState] = (0, import_react.useState)({
|
|
272
|
+
currentFrame: 0,
|
|
273
|
+
totalFrames: options.rows * options.cols,
|
|
274
|
+
isPlaying: false,
|
|
275
|
+
isLoaded: false
|
|
276
|
+
});
|
|
277
|
+
const { enabled = true, ...animatorOptions } = options;
|
|
278
|
+
(0, import_react.useEffect)(() => {
|
|
279
|
+
if (!enabled) return;
|
|
280
|
+
const animator = new SpriteAnimator(animatorOptions);
|
|
281
|
+
animatorRef.current = animator;
|
|
282
|
+
const unsubscribe = animator.subscribe(setState);
|
|
283
|
+
queueMicrotask(() => {
|
|
284
|
+
if (ref.current) {
|
|
285
|
+
animator.attach(ref.current);
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
return () => {
|
|
289
|
+
unsubscribe();
|
|
290
|
+
animator.destroy();
|
|
291
|
+
animatorRef.current = null;
|
|
292
|
+
};
|
|
293
|
+
}, [enabled]);
|
|
294
|
+
(0, import_react.useEffect)(() => {
|
|
295
|
+
animatorRef.current?.updateOptions(animatorOptions);
|
|
296
|
+
}, [
|
|
297
|
+
animatorOptions.src,
|
|
298
|
+
animatorOptions.rows,
|
|
299
|
+
animatorOptions.cols,
|
|
300
|
+
animatorOptions.fps,
|
|
301
|
+
animatorOptions.loop,
|
|
302
|
+
animatorOptions.width,
|
|
303
|
+
animatorOptions.height,
|
|
304
|
+
animatorOptions.autoPlay,
|
|
305
|
+
animatorOptions.renderer
|
|
306
|
+
]);
|
|
307
|
+
return {
|
|
308
|
+
ref,
|
|
309
|
+
state,
|
|
310
|
+
play: () => animatorRef.current?.play(),
|
|
311
|
+
pause: () => animatorRef.current?.pause(),
|
|
312
|
+
stop: () => animatorRef.current?.stop(),
|
|
313
|
+
goToFrame: (frame) => animatorRef.current?.goToFrame(frame)
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// src/react/Sprite.tsx
|
|
318
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
319
|
+
var Sprite = (0, import_react2.forwardRef)(function Sprite2({ className, style, ...options }, ref) {
|
|
320
|
+
const { ref: targetRef, play, pause, stop, goToFrame } = useSprite(options);
|
|
321
|
+
(0, import_react2.useImperativeHandle)(ref, () => ({ play, pause, stop, goToFrame }), [
|
|
322
|
+
play,
|
|
323
|
+
pause,
|
|
324
|
+
stop,
|
|
325
|
+
goToFrame
|
|
326
|
+
]);
|
|
327
|
+
if (options.renderer === "canvas") {
|
|
328
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
329
|
+
"canvas",
|
|
330
|
+
{
|
|
331
|
+
ref: targetRef,
|
|
332
|
+
className,
|
|
333
|
+
style
|
|
334
|
+
}
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
338
|
+
"div",
|
|
339
|
+
{
|
|
340
|
+
ref: targetRef,
|
|
341
|
+
className,
|
|
342
|
+
style,
|
|
343
|
+
role: "img",
|
|
344
|
+
"aria-label": "Sprite animation"
|
|
345
|
+
}
|
|
346
|
+
);
|
|
347
|
+
});
|
|
348
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
349
|
+
0 && (module.exports = {
|
|
350
|
+
Sprite,
|
|
351
|
+
useSprite
|
|
352
|
+
});
|
|
353
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/react/index.ts","../../src/react/Sprite.tsx","../../src/core/constants.ts","../../src/core/utils.ts","../../src/core/canvas-renderer.ts","../../src/core/css-renderer.ts","../../src/core/sprite-animator.ts","../../src/react/useSprite.ts"],"sourcesContent":["export { Sprite } from './Sprite.js';\nexport type { SpriteHandle, SpriteProps } from './Sprite.js';\nexport { useSprite } from './useSprite.js';\nexport type { UseSpriteOptions, UseSpriteReturn } from './useSprite.js';\n","import type { SpriteAnimationOptions } from '../core/types.js';\nimport { forwardRef, useImperativeHandle } from 'react';\nimport { useSprite } from './useSprite.js';\n\nexport interface SpriteProps extends SpriteAnimationOptions {\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport interface SpriteHandle {\n play: () => void;\n pause: () => void;\n stop: () => void;\n goToFrame: (frame: number) => void;\n}\n\nexport const Sprite = forwardRef<SpriteHandle, SpriteProps>(function Sprite(\n { className, style, ...options },\n ref,\n) {\n const { ref: targetRef, play, pause, stop, goToFrame } = useSprite(options);\n\n useImperativeHandle(ref, () => ({ play, pause, stop, goToFrame }), [\n play,\n pause,\n stop,\n goToFrame,\n ]);\n\n if (options.renderer === 'canvas') {\n return (\n <canvas\n ref={targetRef as React.RefObject<HTMLCanvasElement>}\n className={className}\n style={style}\n />\n );\n }\n\n return (\n <div\n ref={targetRef as React.RefObject<HTMLDivElement>}\n className={className}\n style={style}\n role=\"img\"\n aria-label=\"Sprite animation\"\n />\n );\n});\n","import type { RendererMode } from './types.js';\n\nexport const SPRITE_ANIMATION_DEFAULTS = {\n fps: 12,\n loop: true,\n width: 128,\n height: 128,\n autoPlay: true,\n renderer: 'css' as RendererMode,\n} as const;\n","import type { FramePosition } from './types.js';\n\nexport function getTotalFrames(rows: number, cols: number): number {\n return rows * cols;\n}\n\nexport function getFramePosition(frameIndex: number, cols: number): FramePosition {\n return {\n row: Math.floor(frameIndex / cols),\n col: frameIndex % cols,\n };\n}\n\nexport function getBackgroundPositionPercent(\n frameIndex: number,\n rows: number,\n cols: number,\n): { x: number; y: number } {\n const { row, col } = getFramePosition(frameIndex, cols);\n const x = cols <= 1 ? 0 : (col / (cols - 1)) * 100;\n const y = rows <= 1 ? 0 : (row / (rows - 1)) * 100;\n return { x, y };\n}\n","import { getFramePosition } from './utils.js';\n\nexport function drawCanvasFrame(\n canvas: HTMLCanvasElement,\n image: HTMLImageElement,\n frameIndex: number,\n rows: number,\n cols: number,\n width: number,\n height: number,\n): void {\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const frameWidth = image.naturalWidth / cols;\n const frameHeight = image.naturalHeight / rows;\n const { row, col } = getFramePosition(frameIndex, cols);\n\n canvas.width = width;\n canvas.height = height;\n\n ctx.clearRect(0, 0, width, height);\n ctx.drawImage(\n image,\n col * frameWidth,\n row * frameHeight,\n frameWidth,\n frameHeight,\n 0,\n 0,\n width,\n height,\n );\n}\n","import { getBackgroundPositionPercent } from './utils.js';\n\nexport interface CssRendererTarget {\n style: CSSStyleDeclaration;\n}\n\nexport function applyCssFrame(\n target: CssRendererTarget,\n src: string,\n frameIndex: number,\n rows: number,\n cols: number,\n width: number,\n height: number,\n): void {\n const { x, y } = getBackgroundPositionPercent(frameIndex, rows, cols);\n\n target.style.backgroundImage = `url(\"${src}\")`;\n target.style.backgroundRepeat = 'no-repeat';\n target.style.backgroundSize = `${cols * 100}% ${rows * 100}%`;\n target.style.backgroundPosition = `${x}% ${y}%`;\n target.style.width = `${width}px`;\n target.style.height = `${height}px`;\n target.style.display = 'inline-block';\n}\n\nexport function resetCssRenderer(target: CssRendererTarget): void {\n target.style.backgroundImage = '';\n}\n","import { SPRITE_ANIMATION_DEFAULTS } from './constants.js';\nimport { drawCanvasFrame } from './canvas-renderer.js';\nimport { applyCssFrame, resetCssRenderer } from './css-renderer.js';\nimport type { SpriteAnimationOptions, SpriteAnimationState } from './types.js';\nimport { getTotalFrames } from './utils.js';\n\ntype StateListener = (state: SpriteAnimationState) => void;\n\ntype ResolvedSpriteAnimationOptions = Required<\n Pick<SpriteAnimationOptions, 'src' | 'rows' | 'cols'>\n> &\n Required<Pick<SpriteAnimationOptions, 'fps' | 'loop' | 'width' | 'height' | 'autoPlay' | 'renderer'>> &\n Pick<SpriteAnimationOptions, 'onComplete' | 'onFrameChange'>;\n\nexport class SpriteAnimator {\n private options: ResolvedSpriteAnimationOptions;\n private currentFrame = 0;\n private isPlaying = false;\n private isLoaded = false;\n private rafId: number | null = null;\n private lastTimestamp = 0;\n private accumulatedTime = 0;\n private image: HTMLImageElement | null = null;\n private target: HTMLElement | HTMLCanvasElement | null = null;\n private listeners = new Set<StateListener>();\n private destroyed = false;\n\n constructor(options: SpriteAnimationOptions) {\n this.options = {\n ...SPRITE_ANIMATION_DEFAULTS,\n ...options,\n };\n this.loadImage();\n }\n\n attach(target: HTMLElement | HTMLCanvasElement): void {\n this.target = target;\n if (this.isLoaded) {\n this.render();\n }\n if (this.options.autoPlay) {\n this.play();\n }\n }\n\n play(): void {\n if (this.destroyed || this.isPlaying) return;\n this.isPlaying = true;\n this.lastTimestamp = 0;\n this.accumulatedTime = 0;\n this.rafId = requestAnimationFrame(this.tick);\n this.notify();\n }\n\n pause(): void {\n if (!this.isPlaying) return;\n this.isPlaying = false;\n if (this.rafId !== null) {\n cancelAnimationFrame(this.rafId);\n this.rafId = null;\n }\n this.notify();\n }\n\n stop(): void {\n this.pause();\n this.currentFrame = 0;\n this.render();\n this.notify();\n }\n\n goToFrame(frame: number): void {\n const total = this.getTotalFrames();\n this.currentFrame = Math.max(0, Math.min(frame, total - 1));\n this.render();\n this.options.onFrameChange?.(this.currentFrame);\n this.notify();\n }\n\n getState(): SpriteAnimationState {\n return {\n currentFrame: this.currentFrame,\n totalFrames: this.getTotalFrames(),\n isPlaying: this.isPlaying,\n isLoaded: this.isLoaded,\n };\n }\n\n subscribe(listener: StateListener): () => void {\n this.listeners.add(listener);\n listener(this.getState());\n return () => this.listeners.delete(listener);\n }\n\n updateOptions(partial: Partial<SpriteAnimationOptions>): void {\n const prevSrc = this.options.src;\n const prevFps = this.options.fps;\n this.options = { ...this.options, ...partial };\n\n if (partial.src !== undefined && partial.src !== prevSrc) {\n this.loadImage();\n } else if (this.isLoaded) {\n this.render();\n }\n\n if (partial.fps !== undefined && partial.fps !== prevFps) {\n this.accumulatedTime = 0;\n }\n }\n\n destroy(): void {\n this.destroyed = true;\n this.pause();\n this.listeners.clear();\n if (this.target && this.options.renderer === 'css') {\n resetCssRenderer(this.target);\n }\n this.target = null;\n this.image = null;\n }\n\n private getTotalFrames(): number {\n return getTotalFrames(this.options.rows, this.options.cols);\n }\n\n private loadImage(): void {\n this.isLoaded = false;\n const img = new Image();\n img.crossOrigin = 'anonymous';\n img.onload = () => {\n if (this.destroyed) return;\n this.image = img;\n this.isLoaded = true;\n\n if (!this.options.width || !this.options.height) {\n const frameWidth = img.naturalWidth / this.options.cols;\n const frameHeight = img.naturalHeight / this.options.rows;\n this.options.width = frameWidth;\n this.options.height = frameHeight;\n }\n\n this.render();\n this.notify();\n\n if (this.options.autoPlay && this.target) {\n this.play();\n }\n };\n img.onerror = () => {\n console.error(`[SpriteAnimator] Failed to load image: ${this.options.src}`);\n };\n img.src = this.options.src;\n }\n\n private tick = (timestamp: number): void => {\n if (!this.isPlaying || this.destroyed) return;\n\n if (this.lastTimestamp === 0) {\n this.lastTimestamp = timestamp;\n }\n\n const delta = timestamp - this.lastTimestamp;\n this.lastTimestamp = timestamp;\n this.accumulatedTime += delta;\n\n const frameDuration = 1000 / this.options.fps;\n while (this.accumulatedTime >= frameDuration) {\n this.accumulatedTime -= frameDuration;\n this.advanceFrame();\n }\n\n this.rafId = requestAnimationFrame(this.tick);\n };\n\n private advanceFrame(): void {\n const total = this.getTotalFrames();\n const next = this.currentFrame + 1;\n\n if (next >= total) {\n if (this.options.loop) {\n this.currentFrame = 0;\n } else {\n this.currentFrame = total - 1;\n this.pause();\n this.options.onComplete?.();\n }\n } else {\n this.currentFrame = next;\n }\n\n this.render();\n this.options.onFrameChange?.(this.currentFrame);\n this.notify();\n }\n\n private render(): void {\n if (!this.target || !this.isLoaded) return;\n\n const { src, rows, cols, width, height, renderer } = this.options;\n\n if (renderer === 'canvas' && this.target instanceof HTMLCanvasElement && this.image) {\n drawCanvasFrame(this.target, this.image, this.currentFrame, rows, cols, width, height);\n } else if (renderer === 'css' && this.target instanceof HTMLElement) {\n applyCssFrame(this.target, src, this.currentFrame, rows, cols, width, height);\n }\n }\n\n private notify(): void {\n const state = this.getState();\n this.listeners.forEach((listener) => listener(state));\n }\n}\n","import {\n SpriteAnimator,\n type SpriteAnimationOptions,\n type SpriteAnimationState,\n} from '../core/index.js';\nimport { useEffect, useRef, useState } from 'react';\n\nexport interface UseSpriteOptions extends SpriteAnimationOptions {\n /** Skip auto-attach; useful when controlling the target manually */\n enabled?: boolean;\n}\n\nexport interface UseSpriteReturn {\n ref: React.RefObject<HTMLElement | HTMLCanvasElement | null>;\n state: SpriteAnimationState;\n play: () => void;\n pause: () => void;\n stop: () => void;\n goToFrame: (frame: number) => void;\n}\n\nexport function useSprite(options: UseSpriteOptions): UseSpriteReturn {\n const ref = useRef<HTMLElement | HTMLCanvasElement | null>(null);\n const animatorRef = useRef<SpriteAnimator | null>(null);\n const [state, setState] = useState<SpriteAnimationState>({\n currentFrame: 0,\n totalFrames: options.rows * options.cols,\n isPlaying: false,\n isLoaded: false,\n });\n\n const { enabled = true, ...animatorOptions } = options;\n\n useEffect(() => {\n if (!enabled) return;\n\n const animator = new SpriteAnimator(animatorOptions);\n animatorRef.current = animator;\n\n const unsubscribe = animator.subscribe(setState);\n\n queueMicrotask(() => {\n if (ref.current) {\n animator.attach(ref.current);\n }\n });\n\n return () => {\n unsubscribe();\n animator.destroy();\n animatorRef.current = null;\n };\n }, [enabled]);\n\n useEffect(() => {\n animatorRef.current?.updateOptions(animatorOptions);\n }, [\n animatorOptions.src,\n animatorOptions.rows,\n animatorOptions.cols,\n animatorOptions.fps,\n animatorOptions.loop,\n animatorOptions.width,\n animatorOptions.height,\n animatorOptions.autoPlay,\n animatorOptions.renderer,\n ]);\n\n return {\n ref,\n state,\n play: () => animatorRef.current?.play(),\n pause: () => animatorRef.current?.pause(),\n stop: () => animatorRef.current?.stop(),\n goToFrame: (frame) => animatorRef.current?.goToFrame(frame),\n };\n}\n"],"mappings":"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","names":["import_react","Sprite"]}
|