png-sequencer
v0.1.3
Published
Highly controllable PNG sequence player for React apps.
Maintainers
Readme
PNG Sequencer
Reusable, controllable PNG sequence player for React. Feed it pre-rendered PNG frames (sprite sheets, 3D renders, loading animations, etc.), then manage playback speed, looping, and scrubbing through a tiny API that works in any React app or via npm.
The repo ships with:
src/lib/— publishable component code (library build)src/App.tsx— interactive playground showcasing the API
Quick start
Install dependencies:
npm installRun the playground:
npm run devUsing the component
Install from npm:
npm install png-sequencerimport { useRef } from 'react'
import { PngSequencer, type PngSequencerHandle } from 'png-sequencer'
const frames = ['/sprites/frame-01.png', '/sprites/frame-02.png', /* ... */]
export function LoadingAnimation() {
const sequencerRef = useRef<PngSequencerHandle>(null)
return (
<>
<PngSequencer
ref={sequencerRef}
frames={frames}
fps={18}
loop
onFrameChange={(frame) => console.log('frame', frame)}
onStateChange={(state) => console.log('state', state)}
/>
<button onClick={() => sequencerRef.current?.pause()}>Pause</button>
<button onClick={() => sequencerRef.current?.play({ stopAtFrame: 48 })}>
Play to frame 48
</button>
</>
)
}Loading an entire folder of PNGs
If your toolchain supports glob imports (Vite, Astro, SvelteKit, etc.), you can turn a folder full of PNG frames into a sorted array with the bundled helper collectFramesFromGlob:
import { useMemo } from 'react'
import { collectFramesFromGlob } from 'png-sequencer'
const modules = import.meta.glob('../assets/filter_1/*.png', {
eager: true,
import: 'default',
}) as Record<string, string>
const frames = useMemo(() => collectFramesFromGlob(modules), [])The helper sorts keys using natural (numeric) ordering, so files like frame_0001.png → frame_0148.png keep their expected order. For bundlers without a glob feature, you can still generate URLs manually (for example with new URL('frame_0001.png', import.meta.url).href) and pass the resulting string array to the frames prop.
Key props
frames(required) — ordered list of PNG URLsfpsorduration— choose frame rate or total timeline durationloop(true) — loop playback when it reaches the endautoPlay(true) — start automaticallypreload(true) — eager-load frames to avoid flickerspreloadStrategy('all' | 'visible' | 'none', default'all') — choose how aggressively frames are prefetchedpreloadBatchSize— when preloading'all', how many frames to load per batch (helps limit bursts)initialFrame— starting indeximageProps— forwarded to the rendered<img>onFrameChange/onStateChange— hook into playback updates
Imperative API
Attach a ref for advanced scenarios.
type PngSequencerHandle = {
play: (options?: { stopAtFrame?: number }) => void
pause: () => void
stop: () => void
restart: () => void
goToFrame: (frameIndex: number, options?: { autoPause?: boolean }) => void
getCurrentFrame: () => number
getPlaybackState: () => 'idle' | 'playing' | 'paused' | 'stopped'
}Building & publishing
The build pipeline outputs both JS bundles and type declarations.
npm run buildThis produces:
dist/png-sequencer.mjs— ESM bundle (default import)dist/png-sequencer.cjs— CommonJS bundledist/types/—.d.tsfiles for TypeScript consumers
Publish straight from the repo root (only dist/ is included thanks to the files field):
npm publishScripts
npm run dev— start the playgroundnpm run build— emit type declarations + bundlesnpm run preview— preview the built playgroundnpm run lint— run ESLint
License
MIT
