X Tutup

Runebound Mace Conjure

VFX Spritesheet — horizontal strip — 15 frames — 30 FPS
// 1. Load the spritesheet (horizontal strip)
const fxImage = new Image();
fxImage.src = './Runebound Mace Conjure_Sheet.png';

// 2. Spritesheet config
const TOTAL_FRAMES = 15;
const SIZE         = 256;
let   FRAME_W, FRAME_H;

fxImage.onload = () => {
    FRAME_W = fxImage.width  / TOTAL_FRAMES; // single horizontal row
    FRAME_H = fxImage.height;
};
// 3. Effect class (renders at 256x256)
class VFX {
    constructor(x, y) {
        this.x = x; this.y = y;
        this.frame = 0;
        this.done  = false;
        this.last  = 0;
        this.fps   = 1000 / 30;
    }
    update(now) {
        if (now - this.last > this.fps) {
            this.frame++;
            this.last = now;
            if (this.frame >= TOTAL_FRAMES)
                this.done = true;
        }
    }
    draw(ctx) {
        if (this.done) return;
        ctx.save();
        ctx.globalCompositeOperation = 'lighter';
        ctx.drawImage(fxImage,
            this.frame * FRAME_W, 0, FRAME_W, FRAME_H, // source: Nth slot in strip
            this.x - SIZE/2, this.y - SIZE/2,
            SIZE, SIZE);
        ctx.restore();
    }
}

// 4. Game loop
const effects = [];
function loop(now) {
    ctx.clearRect(0,0,canvas.width,canvas.height);
    for (let i = effects.length-1; i>=0; i--)
        if (effects[i].done) effects.splice(i,1);
    effects.forEach(e => { e.update(now); e.draw(ctx); });
    requestAnimationFrame(loop);
}
requestAnimationFrame(loop);

// 5. Spawn on click
canvas.addEventListener('mousedown', e => {
    const r = canvas.getBoundingClientRect();
    const x = (e.clientX - r.left) * (canvas.width / r.width);
    const y = (e.clientY - r.top) * (canvas.height / r.height);
    effects.push(new VFX(x, y));
});
/* Pure CSS Solution (horizontal strip) */

.vfx-sprite {
    width: 256px;
    height: 256px;
    background-image: url('./Runebound Mace Conjure_Sheet.png');
    background-size: 1500% 100%;
    animation: vfx-play 0.50s steps(1) infinite;
}

@keyframes vfx-play {
    0.00% { background-position: 0.00% 0%; }
    6.67% { background-position: 7.14% 0%; }
    13.33% { background-position: 14.29% 0%; }
    20.00% { background-position: 21.43% 0%; }
    26.67% { background-position: 28.57% 0%; }
    33.33% { background-position: 35.71% 0%; }
    40.00% { background-position: 42.86% 0%; }
    46.67% { background-position: 50.00% 0%; }
    53.33% { background-position: 57.14% 0%; }
    60.00% { background-position: 64.29% 0%; }
    66.67% { background-position: 71.43% 0%; }
    73.33% { background-position: 78.57% 0%; }
    80.00% { background-position: 85.71% 0%; }
    86.67% { background-position: 92.86% 0%; }
    93.33% { background-position: 100.00% 0%; }
}

/* One-shot variant (plays once then hides) */
.vfx-sprite.once {
    animation: vfx-play 0.50s steps(1) forwards;
}

<!-- HTML usage -->
<div class="vfx-sprite"></div>
CSS Demo (live)

X Tutup