X Tutup

Phantom Katana Summoning

VFX Spritesheet — horizontal strip — 4 frames — 30 FPS
// 1. Load the spritesheet (horizontal strip)
const fxImage = new Image();
fxImage.src = './Phantom Katana Summoning_Sheet.png';

// 2. Spritesheet config
const TOTAL_FRAMES = 4;
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('./Phantom Katana Summoning_Sheet.png');
    background-size: 400% 100%;
    animation: vfx-play 0.13s steps(1) infinite;
}

@keyframes vfx-play {
    0.00% { background-position: 0.00% 0%; }
    25.00% { background-position: 33.33% 0%; }
    50.00% { background-position: 66.67% 0%; }
    75.00% { background-position: 100.00% 0%; }
}

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

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

X Tutup