- 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>
83 lines
2.0 KiB
TypeScript
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("")}}`
|
|
}
|