tiny-sprite/src/sprite.tsx
Corey Johnson fc44f61993 chore: tiny-sprites v1 complete
- Format code with prettier
- Add .gitignore

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 13:18:03 -08:00

83 lines
2.0 KiB
TypeScript

type SpriteProps = {
src: string
width: number
height: number
frames: number
frameDuration: number
columns?: number
class?: string
style?: string
playing?: boolean
}
export const Sprite = (props: SpriteProps) => {
const {
src,
width,
height,
frames,
frameDuration,
columns,
class: className,
style,
playing = true,
} = props
const isGrid = columns !== undefined
const rows = isGrid ? Math.ceil(frames / columns!) : 1
const cols = isGrid ? columns! : frames
const sheetWidth = cols * width
const sheetHeight = rows * height
const totalDuration = frames * frameDuration
const keyframeId = `sprite-${Bun.hash(
`${src}-${width}-${height}-${frames}-${frameDuration}-${columns}`
).toString(36)}`
const keyframes = isGrid
? generateGridKeyframes(keyframeId, width, height, frames, columns!)
: generateStripKeyframes(keyframeId, sheetWidth)
const divStyle = [
`width:${width}px`,
`height:${height}px`,
`background-image:url('${src}')`,
`background-size:${sheetWidth}px ${sheetHeight}px`,
`animation:${keyframeId} ${totalDuration}ms steps(${frames}) infinite`,
playing ? "" : "animation-play-state:paused",
style,
]
.filter(Boolean)
.join(";")
return (
<>
<style>{keyframes}</style>
<div class={className} style={divStyle} />
</>
)
}
const generateStripKeyframes = (id: string, sheetWidth: number): string =>
`@keyframes ${id}{from{background-position:0 0}to{background-position:-${sheetWidth}px 0}}`
const generateGridKeyframes = (
id: string,
width: number,
height: number,
frames: number,
columns: number
): string => {
const steps: string[] = []
for (let i = 0; i < frames; i++) {
const col = i % columns
const row = Math.floor(i / columns)
const x = -col * width
const y = -row * height
const percent = (i / frames) * 100
steps.push(`${percent}%{background-position:${x}px ${y}px}`)
}
return `@keyframes ${id}{${steps.join("")}}`
}