Skip to content

Instantly share code, notes, and snippets.

@brol1dev
Created June 9, 2025 22:23
Show Gist options
  • Save brol1dev/14bff398e486afbaea138fb9b11bcdfa to your computer and use it in GitHub Desktop.
Save brol1dev/14bff398e486afbaea138fb9b11bcdfa to your computer and use it in GitHub Desktop.
<div
class="my-4 transition-transform"
data-controller="sprite-animation"
data-sprite-animation-base-url-value="https://musa-public-cdn.s3.us-east-2.amazonaws.com/assets/test/fly_png"
data-sprite-animation-frame-count-value="121"
data-sprite-animation-frame-padding-value="5"
data-sprite-animation-frame-prefix-value="mussy-"
data-sprite-animation-frame-suffix-value=".png"
data-sprite-animation-frame-rate-value="30"
data-sprite-animation-loop-value="false"
>
<h2 class="text-center text-lg font-bold">Sprite Animation Test</h2>
<div class="flex justify-center mt-2">
<img data-sprite-animation-target="image" src="https://musa-public-cdn.s3.us-east-2.amazonaws.com/assets/test/fly_png/mussy-00000.png" alt="Sprite Animation" />
</div>
</div>
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["image"]
static values = {
baseUrl: String,
frameCount: Number,
framePrefix: String,
frameSuffix: String,
framePadding: Number,
frameRate: { type: Number, default: 30 },
loop: { type: Boolean, default: true },
}
connect() {
this.imageUrls = []
this.currentFrame = 0
this.preloadImages().then(() => {
this.startAnimation()
})
}
disconnect() {
this.stopAnimation()
}
preloadImages() {
for (let i = 0; i < this.frameCountValue; i++) {
const frameNumber = String(i).padStart(this.framePaddingValue, '0');
const imageName = `${this.framePrefixValue}${frameNumber}${this.frameSuffixValue}`;
this.imageUrls.push(`${this.baseUrlValue}/${imageName}`);
}
const promises = this.imageUrls.map(url => {
return new Promise((resolve, reject) => {
const img = new Image()
img.src = url
img.onload = resolve
img.onerror = reject
})
})
return Promise.all(promises)
}
startAnimation() {
const interval = 1000 / this.frameRateValue
this.animationInterval = setInterval(() => {
this.imageTarget.src = this.imageUrls[this.currentFrame]
this.currentFrame++
if (this.currentFrame >= this.frameCountValue) {
if (this.loopValue) {
this.currentFrame = 0
} else {
this.stopAnimation()
}
}
}, interval)
}
stopAnimation() {
if (this.animationInterval) {
clearInterval(this.animationInterval)
}
}
}
+ <%= render "musa/common/sprite_animation" %>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment