A production-grade pipeline for generating, processing, and integrating high-fidelity 60fps (30-frame) 2D sprite sheet VFX.
This skill encapsulates the workflow for creating "butter-smooth" 2D visual effects, explicitly targeting 30-frame sprite sheets (5x6 grid) running at 60fps (500ms duration).
To generate assets that fit this pipeline, use the following generate_image prompt structure:
A high-quality 2D game sprite sheet of [EFFECT_NAME].
Layout: 5 columns, 6 rows (30 frames total).
Style: [PIXEL_ART | HAND_DRAWN], matching [THEME_COLOR] palette.
Background: Solid Black (#000000) [Critical for Chroma Key].
Animation Sequence (Reading left-to-right, top-to-bottom, 30 frames):
- Frames 1-5: Rapid Anticipation (Energy gathering/Telegraph).
- Frames 6-15: High-Impact Action (Explosion/Slash/Eruption).
- Frames 16-22: Peak Hangtime (Slow motion emphasis).
- Frames 23-30: Dissipation (Fade out/Collapse).
Must look like 60fps fluid simulation. Consistency is key.
Before removing the background, we MUST normalize the raw generation using the Smart Projection Analysis (as seen in scripts/smart_vfx_packer.py).
Why? Raw AI generations often have drifting grids or unequal cell sizes. This step guarantees that Frame 1 and Frame 30 are perfectly centered, eliminating "jitter" in the final animation.
Raw AI generations have black backgrounds. We use a Luma-based Chroma Key approach in code (or a preprocessing script) to convert Black to Transparent.
Every VFX should be accompanied by a config entry:
{
"id": "VFX_EXAMPLE_BLAST",
"src": "/assets/vfx/example_blast_v1.png",
"layout": { "cols": 5, "rows": 6, "total": 30 },
"physics": {
"duration": 500, // 1:1 Frame Mapping at 60Hz
"scaleCurve": "squash", // Optional procedural deformation
"blendMode": "lighter"
}
}
To achieve true fluidity without "stuttering", follow these rules:
EaseOut for frame selection. The sprite sheet itself contains the timing curve.globalAlpha = progress / 0.2 for the first 20%.scaleY = 1 + (p/0.2)*0.3 during impact to simulate force.When implementing a renderer (e.g., in TitanSkillRenderer.ts or UniversalVfx.ts):
// Standard 30-Frame Renderer Logic
const totalFrames = 30;
const frameIndex = Math.min(totalFrames - 1, Math.floor(progress * totalFrames));
const col = frameIndex % 5;
const row = Math.floor(frameIndex / 5);
// Render
ctx.drawImage(sheet, col * fw, row * fh, fw, fh, -w/2, -h, w, h);