Probably Playable
Back to Codons

Animation Editor

Beta

Fix AI-generated spritesheets and turn messy frames into clean animations

by Probably Playable — v1.0.0

Description

The problem

You ask your AI to generate a spritesheet — an explosion, a walk cycle, an attack animation. What you get back is almost right: the frames exist, but they're misaligned, badly cropped, inconsistently scaled. The AI doesn't know how to center sprites consistently across frames. You can't use this raw spritesheet in your game — each frame wobbles, shifts, or clips.

The solution

The Animation Editor lets you visually fix AI-generated spritesheets without leaving your game. Load any spritesheet, then:

  • Adjust each frame — reposition, rescale, crop bounding boxes with drag handles
  • Auto-fit — one-click pixel detection that finds sprite boundaries and centers them
  • Reorder & time — drag frames in the timeline, set per-frame duration
  • Preview live — real-time playback with onion skinning to compare frames
  • Bake & export — bake all fixes into a new clean spritesheet PNG

Your AI generates the raw material. This tool turns it into a usable animation.

Keyboard shortcuts

KeyAction
SpacePlay / Pause
ArrowsNavigate frames, adjust offset
Ctrl + ArrowsResize bounding box
Cmd/Ctrl + DDuplicate frame
DeleteRemove frame
ESCExit (prompts to bake if unsaved)
Dependencies
  • Phaser 3.60+
Phaser
Technical Details
Version
1.0.0
Status
Beta
License
MIT
Size
30 KB
Author
Probably Playable
Updated
2025-04-04
animationspritesheetpixel-artsprite-editorframe-editorbake
AI Integration Skill

Drop into .claude/skills/ — your AI handles the rest.

AI Skill codon.skill.md

Animation Editor — Integration Skill

Use this skill when the user asks to "add animation editor", "sprite animation tool",

"preview animations", "edit spritesheet frames", "crop sprites", or "bake spritesheet".

WHAT IT DOES

A full spritesheet animation editor built as a Phaser 3 scene. Load any spritesheet,

define frame sequences with per-frame timing, crop bounding boxes with pixel-perfect

precision, preview with onion skinning, and bake optimized sprite strips.

REQUIREMENTS

  • Framework: Phaser 3.60+
  • Language: TypeScript (strict mode)
  • Dependencies: None (self-contained, no EventBus needed)
  • Storage: Uses localStorage for persistence (key: rfd_anim_defs)
  • Files: 5 TypeScript files (~2,300 LOC total)

FILE STRUCTURE


animation-editor/
  AnimationPreviewScene.ts   — Main scene entry point, keyboard shortcuts, playback loop
  AnimPreviewState.ts        — Shared mutable state interface
  SourcePanel.ts             — Left panel: spritesheet grid, bbox handles, pixel analysis
  PreviewPanel.ts            — Right panel: live preview, onion skin, bake & export
  AnimToolbar.ts             — Bottom: timeline, frame props, sheet props, sidebar
  layoutConstants.ts         — Shared geometry constants (panel sizes, offsets)

INSTALL

  1. Copy the animation-editor/ folder into your project's src/scenes/ directory.
    1. Register the scene in your Phaser game config:
    2. 
      import { AnimationPreviewScene } from './scenes/animation-editor/AnimationPreviewScene';
      
      const config: Phaser.Types.Core.GameConfig = {
        // ... your existing config
        scene: [
          // ... your existing scenes
          AnimationPreviewScene,
        ],
      };
      
      1. To use saved animations at boot time, call the registration helper:
      2. 
        // In your BootScene.create() or preload completion:
        import { registerSavedAnimations } from './scenes/animation-editor/AnimationPreviewScene';
        
        registerSavedAnimations(this); // 'this' is the current Phaser.Scene
        

        INTEGRATION

        Launch the editor from any scene:

        
        // Open the animation editor
        this.scene.start('AnimationPreviewScene');
        
        // Or launch as overlay (keeps current scene running underneath):
        this.scene.launch('AnimationPreviewScene');
        

        Use saved animation definitions:

        
        import { loadAnimDefs } from './scenes/animation-editor/AnimationPreviewScene';
        import type { AnimDef } from './scenes/animation-editor/AnimationPreviewScene';
        
        // Load all saved animation definitions
        const allDefs: Record<string, AnimDef> = loadAnimDefs();
        
        // Each AnimDef contains:
        // {
        //   frameWidth: number,
        //   frameHeight: number,
        //   frameOrder: number[],        // indices into spritesheet
        //   frames: AnimFrameDef[],      // per-frame: duration, offsetX/Y, scaleX/Y, bbox
        //   archived: boolean
        // }
        

        Bake server endpoint (optional):

        If you want the bake-and-save feature, add this API endpoint to your dev server:

        
        // POST /api/save-spritesheet
        // Body: { filename: string, archiveFile: string, dataUrl: string }
        // Response: { savedAs: string, archivedAs: string | null }
        

        Without this endpoint, the editor still works — it just can't export baked PNGs to disk.

        CONFIGURATION

        ConstantFileDefaultDescription
        SIDEBAR_WlayoutConstants.ts200Left sidebar width (spritesheet list)
        TIMELINE_HlayoutConstants.ts160Bottom timeline height
        dragDistanceThresholdAnimationPreviewScene.ts10Min px to distinguish drag from click
        Alpha thresholdSourcePanel.ts10Min alpha value for pixel detection (0-255)

        STATE INTERFACE

        
        interface AnimPreviewState {
          sheetKeys: string[];              // discovered spritesheet keys
          selectedSheet: string;            // current sheet being edited
          frameCount: number;               // total frames in current sheet
          selectedFrame: number;            // -1 = all frames / play mode
          animDef: AnimDef;                 // current animation definition
          allDefs: Record<string, AnimDef>; // all saved definitions
          playing: boolean;                 // playback active
          onionEnabled: boolean;            // show prev/next frame overlay
          crosshairEnabled: boolean;        // show center crosshair
        }
        

        KEY METHODS

        AnimationPreviewScene

        • create() — Initialize all panels, discover spritesheets, build UI
        • update(time, delta) — Handle playback timer

        SourcePanel

        • autoFitFrames() — Flood-fill pixel analysis for automatic bounding box detection
        • refreshSheetView() — Redraw grid overlay and frame numbers
        • drawBboxOverlay(frameIdx) — Create draggable bbox corner handles

        PreviewPanel

        • showFrame(idx) — Render frame with onion skins and bbox
        • bakeAndSave() — Batch-bake all frames to PNG, POST to server
        • hasPendingAdjustments() — Check if unsaved changes exist

        AnimToolbar

        • buildTimeline() — Frame thumbnails with drag-to-reorder
        • buildFrameProps() — Duration, offset, scale, bbox spinners

        EVENTS

        This codon does NOT use an EventBus. All communication is via:

        • Shared AnimPreviewState object (passed to all sub-panels)
        • Direct callback references (AnimToolbarCallbacks interface)
        
        interface AnimToolbarCallbacks {
          autoSave(): void;
          selectSheet(key: string): void;
          startPlayback(): void;
          stopPlayback(): void;
          showFrame(idx: number): void;
          reSliceTexture(): void;
        }
        

        GOTCHAS

        1. Spritesheets must be preloaded — The editor discovers sheets via this.textures.list. Load your spritesheets in a preload scene before launching the editor.
          1. Only sheets with frameTotal > 2 are shown — Single-frame images are filtered out.
            1. localStorage key collision — Uses rfd_anim_defs. If you have multiple projects on localhost, they'll share definitions. Change the key if needed.
              1. Bake endpoint is optional — Without /api/save-spritesheet, the editor works for previewing and defining animations, but can't export PNGs to disk.
                1. ESC exits — Pressing Escape will leave the editor scene. If there are unsaved bake changes, it prompts first.
                  1. Canvas size matters — Layout constants assume a game canvas of ~1200x800. Adjust layoutConstants.ts for different resolutions.

This codon is provided "as is" without warranty of any kind, express or implied. Probably Playable assumes no responsibility for any damages, data loss, security vulnerabilities, or defects arising from its use. You are solely responsible for reviewing, testing, and validating this code before integrating it into your project. Use at your own risk.