@sprite-motion/react 0.1.1 → 0.1.2

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 ADDED
@@ -0,0 +1,85 @@
1
+ # @sprite-motion/react
2
+
3
+ React component and hook for sprite sheet animation.
4
+
5
+ Part of [Sprite Motion](https://github.com/FE-HyunSu/sprite-motion) — play PNG/WebP sprite sheets with `rows`, `cols`, and `fps`. No Lottie required.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @sprite-motion/react
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ```tsx
16
+ import { SpriteAnimation } from '@sprite-motion/react';
17
+
18
+ <SpriteAnimation
19
+ src="/sprite.png"
20
+ rows={4}
21
+ cols={4}
22
+ fps={12}
23
+ loop
24
+ width={128}
25
+ height={128}
26
+ />
27
+ ```
28
+
29
+ ## Playback Controls
30
+
31
+ ```tsx
32
+ import { useRef } from 'react';
33
+ import { SpriteAnimation, type SpriteAnimationHandle } from '@sprite-motion/react';
34
+
35
+ const ref = useRef<SpriteAnimationHandle>(null);
36
+
37
+ ref.current?.play();
38
+ ref.current?.pause();
39
+ ref.current?.stop();
40
+ ref.current?.goToFrame(3);
41
+ ```
42
+
43
+ ## Hook
44
+
45
+ ```tsx
46
+ import { useSpriteAnimation } from '@sprite-motion/react';
47
+
48
+ const { ref, state, play, pause, stop, goToFrame } = useSpriteAnimation({
49
+ src: '/sprite.png',
50
+ rows: 4,
51
+ cols: 4,
52
+ fps: 12,
53
+ });
54
+ ```
55
+
56
+ ## Props
57
+
58
+ | Prop | Type | Default | Description |
59
+ |------|------|---------|-------------|
60
+ | `src` | `string` | — | Sprite sheet image URL |
61
+ | `rows` | `number` | — | Number of rows |
62
+ | `cols` | `number` | — | Number of columns |
63
+ | `fps` | `number` | `12` | Frames per second |
64
+ | `loop` | `boolean` | `true` | Loop animation |
65
+ | `width` | `number` | `128` | Display width (px) |
66
+ | `height` | `number` | `128` | Display height (px) |
67
+ | `autoPlay` | `boolean` | `true` | Start on mount |
68
+ | `renderer` | `'css' \| 'canvas'` | `'css'` | Rendering mode |
69
+ | `onComplete` | `() => void` | — | Called when a non-looping animation finishes |
70
+ | `onFrameChange` | `(frame: number) => void` | — | Called on each frame change |
71
+
72
+ ## Renderers
73
+
74
+ - **CSS (default)** — lightweight, uses `background-position`
75
+ - **Canvas** — uses `drawImage`, good for custom drawing
76
+
77
+ ## Related Packages
78
+
79
+ - [`@sprite-motion/core`](https://www.npmjs.com/package/@sprite-motion/core) — framework-agnostic engine
80
+ - [`@sprite-motion/vue`](https://www.npmjs.com/package/@sprite-motion/vue)
81
+ - [`@sprite-motion/svelte`](https://www.npmjs.com/package/@sprite-motion/svelte)
82
+
83
+ ## License
84
+
85
+ MIT
package/dist/index.cjs CHANGED
@@ -83,41 +83,15 @@ function useSpriteAnimation(options) {
83
83
  // src/SpriteAnimation.tsx
84
84
  var import_jsx_runtime = require("react/jsx-runtime");
85
85
  var SpriteAnimation = (0, import_react2.forwardRef)(
86
- function SpriteAnimation2({
87
- src,
88
- rows,
89
- cols,
90
- fps = 12,
91
- loop = true,
92
- width = 128,
93
- height = 128,
94
- autoPlay = true,
95
- renderer = "css",
96
- onComplete,
97
- onFrameChange,
98
- className,
99
- style
100
- }, ref) {
101
- const { ref: targetRef, play, pause, stop, goToFrame } = useSpriteAnimation({
102
- src,
103
- rows,
104
- cols,
105
- fps,
106
- loop,
107
- width,
108
- height,
109
- autoPlay,
110
- renderer,
111
- onComplete,
112
- onFrameChange
113
- });
86
+ function SpriteAnimation2({ className, style, ...options }, ref) {
87
+ const { ref: targetRef, play, pause, stop, goToFrame } = useSpriteAnimation(options);
114
88
  (0, import_react2.useImperativeHandle)(ref, () => ({ play, pause, stop, goToFrame }), [
115
89
  play,
116
90
  pause,
117
91
  stop,
118
92
  goToFrame
119
93
  ]);
120
- if (renderer === "canvas") {
94
+ if (options.renderer === "canvas") {
121
95
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
122
96
  "canvas",
123
97
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/SpriteAnimation.tsx","../src/useSpriteAnimation.ts"],"sourcesContent":["export { SpriteAnimation } from './SpriteAnimation.js';\nexport type { SpriteAnimationHandle, SpriteAnimationProps } from './SpriteAnimation.js';\nexport { useSpriteAnimation } from './useSpriteAnimation.js';\nexport type { UseSpriteAnimationOptions, UseSpriteAnimationReturn } from './useSpriteAnimation.js';\n","import type { SpriteAnimationOptions } from '@sprite-motion/core';\nimport { forwardRef, useImperativeHandle } from 'react';\nimport { useSpriteAnimation } from './useSpriteAnimation.js';\n\nexport interface SpriteAnimationProps extends SpriteAnimationOptions {\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport interface SpriteAnimationHandle {\n play: () => void;\n pause: () => void;\n stop: () => void;\n goToFrame: (frame: number) => void;\n}\n\nexport const SpriteAnimation = forwardRef<SpriteAnimationHandle, SpriteAnimationProps>(\n function SpriteAnimation(\n {\n src,\n rows,\n cols,\n fps = 12,\n loop = true,\n width = 128,\n height = 128,\n autoPlay = true,\n renderer = 'css',\n onComplete,\n onFrameChange,\n className,\n style,\n },\n ref,\n ) {\n const { ref: targetRef, play, pause, stop, goToFrame } = useSpriteAnimation({\n src,\n rows,\n cols,\n fps,\n loop,\n width,\n height,\n autoPlay,\n renderer,\n onComplete,\n onFrameChange,\n });\n\n useImperativeHandle(ref, () => ({ play, pause, stop, goToFrame }), [\n play,\n pause,\n stop,\n goToFrame,\n ]);\n\n if (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);\n","import { SpriteAnimator, type SpriteAnimationOptions, type SpriteAnimationState } from '@sprite-motion/core';\nimport { useEffect, useRef, useState } from 'react';\n\nexport interface UseSpriteAnimationOptions extends SpriteAnimationOptions {\n /** Skip auto-attach; useful when controlling the target manually */\n enabled?: boolean;\n}\n\nexport interface UseSpriteAnimationReturn {\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 useSpriteAnimation(options: UseSpriteAnimationOptions): UseSpriteAnimationReturn {\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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,IAAAA,gBAAgD;;;ACDhD,kBAAuF;AACvF,mBAA4C;AAgBrC,SAAS,mBAAmB,SAA8D;AAC/F,QAAM,UAAM,qBAA+C,IAAI;AAC/D,QAAM,kBAAc,qBAA8B,IAAI;AACtD,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAA+B;AAAA,IACvD,cAAc;AAAA,IACd,aAAa,QAAQ,OAAO,QAAQ;AAAA,IACpC,WAAW;AAAA,IACX,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,EAAE,UAAU,MAAM,GAAG,gBAAgB,IAAI;AAE/C,8BAAU,MAAM;AACd,QAAI,CAAC,QAAS;AAEd,UAAM,WAAW,IAAI,2BAAe,eAAe;AACnD,gBAAY,UAAU;AAEtB,UAAM,cAAc,SAAS,UAAU,QAAQ;AAE/C,mBAAe,MAAM;AACnB,UAAI,IAAI,SAAS;AACf,iBAAS,OAAO,IAAI,OAAO;AAAA,MAC7B;AAAA,IACF,CAAC;AAED,WAAO,MAAM;AACX,kBAAY;AACZ,eAAS,QAAQ;AACjB,kBAAY,UAAU;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,8BAAU,MAAM;AACd,gBAAY,SAAS,cAAc,eAAe;AAAA,EACpD,GAAG;AAAA,IACD,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,EAClB,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,MAAM,MAAM,YAAY,SAAS,KAAK;AAAA,IACtC,OAAO,MAAM,YAAY,SAAS,MAAM;AAAA,IACxC,MAAM,MAAM,YAAY,SAAS,KAAK;AAAA,IACtC,WAAW,CAAC,UAAU,YAAY,SAAS,UAAU,KAAK;AAAA,EAC5D;AACF;;;ADdQ;AA1CD,IAAM,sBAAkB;AAAA,EAC7B,SAASC,iBACP;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,WAAW;AAAA,IACX,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GACA,KACA;AACA,UAAM,EAAE,KAAK,WAAW,MAAM,OAAO,MAAM,UAAU,IAAI,mBAAmB;AAAA,MAC1E;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,2CAAoB,KAAK,OAAO,EAAE,MAAM,OAAO,MAAM,UAAU,IAAI;AAAA,MACjE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,QAAI,aAAa,UAAU;AACzB,aACE;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL;AAAA,UACA;AAAA;AAAA,MACF;AAAA,IAEJ;AAEA,WACE;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL;AAAA,QACA;AAAA,QACA,MAAK;AAAA,QACL,cAAW;AAAA;AAAA,IACb;AAAA,EAEJ;AACF;","names":["import_react","SpriteAnimation"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/SpriteAnimation.tsx","../src/useSpriteAnimation.ts"],"sourcesContent":["export { SpriteAnimation } from './SpriteAnimation.js';\nexport type { SpriteAnimationHandle, SpriteAnimationProps } from './SpriteAnimation.js';\nexport { useSpriteAnimation } from './useSpriteAnimation.js';\nexport type { UseSpriteAnimationOptions, UseSpriteAnimationReturn } from './useSpriteAnimation.js';\n","import type { SpriteAnimationOptions } from '@sprite-motion/core';\nimport { forwardRef, useImperativeHandle } from 'react';\nimport { useSpriteAnimation } from './useSpriteAnimation.js';\n\nexport interface SpriteAnimationProps extends SpriteAnimationOptions {\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport interface SpriteAnimationHandle {\n play: () => void;\n pause: () => void;\n stop: () => void;\n goToFrame: (frame: number) => void;\n}\n\nexport const SpriteAnimation = forwardRef<SpriteAnimationHandle, SpriteAnimationProps>(\n function SpriteAnimation({ className, style, ...options }, ref) {\n const { ref: targetRef, play, pause, stop, goToFrame } = useSpriteAnimation(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);\n","import { SpriteAnimator, type SpriteAnimationOptions, type SpriteAnimationState } from '@sprite-motion/core';\nimport { useEffect, useRef, useState } from 'react';\n\nexport interface UseSpriteAnimationOptions extends SpriteAnimationOptions {\n /** Skip auto-attach; useful when controlling the target manually */\n enabled?: boolean;\n}\n\nexport interface UseSpriteAnimationReturn {\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 useSpriteAnimation(options: UseSpriteAnimationOptions): UseSpriteAnimationReturn {\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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCA,IAAAA,gBAAgD;;;ACDhD,kBAAuF;AACvF,mBAA4C;AAgBrC,SAAS,mBAAmB,SAA8D;AAC/F,QAAM,UAAM,qBAA+C,IAAI;AAC/D,QAAM,kBAAc,qBAA8B,IAAI;AACtD,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAA+B;AAAA,IACvD,cAAc;AAAA,IACd,aAAa,QAAQ,OAAO,QAAQ;AAAA,IACpC,WAAW;AAAA,IACX,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,EAAE,UAAU,MAAM,GAAG,gBAAgB,IAAI;AAE/C,8BAAU,MAAM;AACd,QAAI,CAAC,QAAS;AAEd,UAAM,WAAW,IAAI,2BAAe,eAAe;AACnD,gBAAY,UAAU;AAEtB,UAAM,cAAc,SAAS,UAAU,QAAQ;AAE/C,mBAAe,MAAM;AACnB,UAAI,IAAI,SAAS;AACf,iBAAS,OAAO,IAAI,OAAO;AAAA,MAC7B;AAAA,IACF,CAAC;AAED,WAAO,MAAM;AACX,kBAAY;AACZ,eAAS,QAAQ;AACjB,kBAAY,UAAU;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,8BAAU,MAAM;AACd,gBAAY,SAAS,cAAc,eAAe;AAAA,EACpD,GAAG;AAAA,IACD,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,EAClB,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,MAAM,MAAM,YAAY,SAAS,KAAK;AAAA,IACtC,OAAO,MAAM,YAAY,SAAS,MAAM;AAAA,IACxC,MAAM,MAAM,YAAY,SAAS,KAAK;AAAA,IACtC,WAAW,CAAC,UAAU,YAAY,SAAS,UAAU,KAAK;AAAA,EAC5D;AACF;;;AD3CQ;AAbD,IAAM,sBAAkB;AAAA,EAC7B,SAASC,iBAAgB,EAAE,WAAW,OAAO,GAAG,QAAQ,GAAG,KAAK;AAC9D,UAAM,EAAE,KAAK,WAAW,MAAM,OAAO,MAAM,UAAU,IAAI,mBAAmB,OAAO;AAEnF,2CAAoB,KAAK,OAAO,EAAE,MAAM,OAAO,MAAM,UAAU,IAAI;AAAA,MACjE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,QAAI,QAAQ,aAAa,UAAU;AACjC,aACE;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL;AAAA,UACA;AAAA;AAAA,MACF;AAAA,IAEJ;AAEA,WACE;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL;AAAA,QACA;AAAA,QACA,MAAK;AAAA,QACL,cAAW;AAAA;AAAA,IACb;AAAA,EAEJ;AACF;","names":["import_react","SpriteAnimation"]}
package/dist/index.js CHANGED
@@ -56,41 +56,15 @@ function useSpriteAnimation(options) {
56
56
  // src/SpriteAnimation.tsx
57
57
  import { jsx } from "react/jsx-runtime";
58
58
  var SpriteAnimation = forwardRef(
59
- function SpriteAnimation2({
60
- src,
61
- rows,
62
- cols,
63
- fps = 12,
64
- loop = true,
65
- width = 128,
66
- height = 128,
67
- autoPlay = true,
68
- renderer = "css",
69
- onComplete,
70
- onFrameChange,
71
- className,
72
- style
73
- }, ref) {
74
- const { ref: targetRef, play, pause, stop, goToFrame } = useSpriteAnimation({
75
- src,
76
- rows,
77
- cols,
78
- fps,
79
- loop,
80
- width,
81
- height,
82
- autoPlay,
83
- renderer,
84
- onComplete,
85
- onFrameChange
86
- });
59
+ function SpriteAnimation2({ className, style, ...options }, ref) {
60
+ const { ref: targetRef, play, pause, stop, goToFrame } = useSpriteAnimation(options);
87
61
  useImperativeHandle(ref, () => ({ play, pause, stop, goToFrame }), [
88
62
  play,
89
63
  pause,
90
64
  stop,
91
65
  goToFrame
92
66
  ]);
93
- if (renderer === "canvas") {
67
+ if (options.renderer === "canvas") {
94
68
  return /* @__PURE__ */ jsx(
95
69
  "canvas",
96
70
  {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/SpriteAnimation.tsx","../src/useSpriteAnimation.ts"],"sourcesContent":["import type { SpriteAnimationOptions } from '@sprite-motion/core';\nimport { forwardRef, useImperativeHandle } from 'react';\nimport { useSpriteAnimation } from './useSpriteAnimation.js';\n\nexport interface SpriteAnimationProps extends SpriteAnimationOptions {\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport interface SpriteAnimationHandle {\n play: () => void;\n pause: () => void;\n stop: () => void;\n goToFrame: (frame: number) => void;\n}\n\nexport const SpriteAnimation = forwardRef<SpriteAnimationHandle, SpriteAnimationProps>(\n function SpriteAnimation(\n {\n src,\n rows,\n cols,\n fps = 12,\n loop = true,\n width = 128,\n height = 128,\n autoPlay = true,\n renderer = 'css',\n onComplete,\n onFrameChange,\n className,\n style,\n },\n ref,\n ) {\n const { ref: targetRef, play, pause, stop, goToFrame } = useSpriteAnimation({\n src,\n rows,\n cols,\n fps,\n loop,\n width,\n height,\n autoPlay,\n renderer,\n onComplete,\n onFrameChange,\n });\n\n useImperativeHandle(ref, () => ({ play, pause, stop, goToFrame }), [\n play,\n pause,\n stop,\n goToFrame,\n ]);\n\n if (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);\n","import { SpriteAnimator, type SpriteAnimationOptions, type SpriteAnimationState } from '@sprite-motion/core';\nimport { useEffect, useRef, useState } from 'react';\n\nexport interface UseSpriteAnimationOptions extends SpriteAnimationOptions {\n /** Skip auto-attach; useful when controlling the target manually */\n enabled?: boolean;\n}\n\nexport interface UseSpriteAnimationReturn {\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 useSpriteAnimation(options: UseSpriteAnimationOptions): UseSpriteAnimationReturn {\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":";AACA,SAAS,YAAY,2BAA2B;;;ACDhD,SAAS,sBAA8E;AACvF,SAAS,WAAW,QAAQ,gBAAgB;AAgBrC,SAAS,mBAAmB,SAA8D;AAC/F,QAAM,MAAM,OAA+C,IAAI;AAC/D,QAAM,cAAc,OAA8B,IAAI;AACtD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAA+B;AAAA,IACvD,cAAc;AAAA,IACd,aAAa,QAAQ,OAAO,QAAQ;AAAA,IACpC,WAAW;AAAA,IACX,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,EAAE,UAAU,MAAM,GAAG,gBAAgB,IAAI;AAE/C,YAAU,MAAM;AACd,QAAI,CAAC,QAAS;AAEd,UAAM,WAAW,IAAI,eAAe,eAAe;AACnD,gBAAY,UAAU;AAEtB,UAAM,cAAc,SAAS,UAAU,QAAQ;AAE/C,mBAAe,MAAM;AACnB,UAAI,IAAI,SAAS;AACf,iBAAS,OAAO,IAAI,OAAO;AAAA,MAC7B;AAAA,IACF,CAAC;AAED,WAAO,MAAM;AACX,kBAAY;AACZ,eAAS,QAAQ;AACjB,kBAAY,UAAU;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,YAAU,MAAM;AACd,gBAAY,SAAS,cAAc,eAAe;AAAA,EACpD,GAAG;AAAA,IACD,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,EAClB,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,MAAM,MAAM,YAAY,SAAS,KAAK;AAAA,IACtC,OAAO,MAAM,YAAY,SAAS,MAAM;AAAA,IACxC,MAAM,MAAM,YAAY,SAAS,KAAK;AAAA,IACtC,WAAW,CAAC,UAAU,YAAY,SAAS,UAAU,KAAK;AAAA,EAC5D;AACF;;;ADdQ;AA1CD,IAAM,kBAAkB;AAAA,EAC7B,SAASA,iBACP;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,WAAW;AAAA,IACX,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,GACA,KACA;AACA,UAAM,EAAE,KAAK,WAAW,MAAM,OAAO,MAAM,UAAU,IAAI,mBAAmB;AAAA,MAC1E;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,wBAAoB,KAAK,OAAO,EAAE,MAAM,OAAO,MAAM,UAAU,IAAI;AAAA,MACjE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,QAAI,aAAa,UAAU;AACzB,aACE;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL;AAAA,UACA;AAAA;AAAA,MACF;AAAA,IAEJ;AAEA,WACE;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL;AAAA,QACA;AAAA,QACA,MAAK;AAAA,QACL,cAAW;AAAA;AAAA,IACb;AAAA,EAEJ;AACF;","names":["SpriteAnimation"]}
1
+ {"version":3,"sources":["../src/SpriteAnimation.tsx","../src/useSpriteAnimation.ts"],"sourcesContent":["import type { SpriteAnimationOptions } from '@sprite-motion/core';\nimport { forwardRef, useImperativeHandle } from 'react';\nimport { useSpriteAnimation } from './useSpriteAnimation.js';\n\nexport interface SpriteAnimationProps extends SpriteAnimationOptions {\n className?: string;\n style?: React.CSSProperties;\n}\n\nexport interface SpriteAnimationHandle {\n play: () => void;\n pause: () => void;\n stop: () => void;\n goToFrame: (frame: number) => void;\n}\n\nexport const SpriteAnimation = forwardRef<SpriteAnimationHandle, SpriteAnimationProps>(\n function SpriteAnimation({ className, style, ...options }, ref) {\n const { ref: targetRef, play, pause, stop, goToFrame } = useSpriteAnimation(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);\n","import { SpriteAnimator, type SpriteAnimationOptions, type SpriteAnimationState } from '@sprite-motion/core';\nimport { useEffect, useRef, useState } from 'react';\n\nexport interface UseSpriteAnimationOptions extends SpriteAnimationOptions {\n /** Skip auto-attach; useful when controlling the target manually */\n enabled?: boolean;\n}\n\nexport interface UseSpriteAnimationReturn {\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 useSpriteAnimation(options: UseSpriteAnimationOptions): UseSpriteAnimationReturn {\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":";AACA,SAAS,YAAY,2BAA2B;;;ACDhD,SAAS,sBAA8E;AACvF,SAAS,WAAW,QAAQ,gBAAgB;AAgBrC,SAAS,mBAAmB,SAA8D;AAC/F,QAAM,MAAM,OAA+C,IAAI;AAC/D,QAAM,cAAc,OAA8B,IAAI;AACtD,QAAM,CAAC,OAAO,QAAQ,IAAI,SAA+B;AAAA,IACvD,cAAc;AAAA,IACd,aAAa,QAAQ,OAAO,QAAQ;AAAA,IACpC,WAAW;AAAA,IACX,UAAU;AAAA,EACZ,CAAC;AAED,QAAM,EAAE,UAAU,MAAM,GAAG,gBAAgB,IAAI;AAE/C,YAAU,MAAM;AACd,QAAI,CAAC,QAAS;AAEd,UAAM,WAAW,IAAI,eAAe,eAAe;AACnD,gBAAY,UAAU;AAEtB,UAAM,cAAc,SAAS,UAAU,QAAQ;AAE/C,mBAAe,MAAM;AACnB,UAAI,IAAI,SAAS;AACf,iBAAS,OAAO,IAAI,OAAO;AAAA,MAC7B;AAAA,IACF,CAAC;AAED,WAAO,MAAM;AACX,kBAAY;AACZ,eAAS,QAAQ;AACjB,kBAAY,UAAU;AAAA,IACxB;AAAA,EACF,GAAG,CAAC,OAAO,CAAC;AAEZ,YAAU,MAAM;AACd,gBAAY,SAAS,cAAc,eAAe;AAAA,EACpD,GAAG;AAAA,IACD,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,EAClB,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,MAAM,MAAM,YAAY,SAAS,KAAK;AAAA,IACtC,OAAO,MAAM,YAAY,SAAS,MAAM;AAAA,IACxC,MAAM,MAAM,YAAY,SAAS,KAAK;AAAA,IACtC,WAAW,CAAC,UAAU,YAAY,SAAS,UAAU,KAAK;AAAA,EAC5D;AACF;;;AD3CQ;AAbD,IAAM,kBAAkB;AAAA,EAC7B,SAASA,iBAAgB,EAAE,WAAW,OAAO,GAAG,QAAQ,GAAG,KAAK;AAC9D,UAAM,EAAE,KAAK,WAAW,MAAM,OAAO,MAAM,UAAU,IAAI,mBAAmB,OAAO;AAEnF,wBAAoB,KAAK,OAAO,EAAE,MAAM,OAAO,MAAM,UAAU,IAAI;AAAA,MACjE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,CAAC;AAED,QAAI,QAAQ,aAAa,UAAU;AACjC,aACE;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL;AAAA,UACA;AAAA;AAAA,MACF;AAAA,IAEJ;AAEA,WACE;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL;AAAA,QACA;AAAA,QACA,MAAK;AAAA,QACL,cAAW;AAAA;AAAA,IACb;AAAA,EAEJ;AACF;","names":["SpriteAnimation"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sprite-motion/react",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "React component for sprite sheet animation",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -19,8 +19,18 @@
19
19
  }
20
20
  },
21
21
  "files": [
22
- "dist"
22
+ "dist",
23
+ "README.md"
23
24
  ],
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "git+https://github.com/FE-HyunSu/sprite-motion.git",
28
+ "directory": "packages/react"
29
+ },
30
+ "homepage": "https://github.com/FE-HyunSu/sprite-motion#readme",
31
+ "bugs": {
32
+ "url": "https://github.com/FE-HyunSu/sprite-motion/issues"
33
+ },
24
34
  "scripts": {
25
35
  "build": "tsup",
26
36
  "typecheck": "tsc --noEmit",