Pixel Loop is a local-first pixel animation studio built with React. Draw frame-by-frame pixel art, import images, preview the animation, and export the result as an animated GIF—all in the browser.
- 16×16, 32×32, and 64×64 pixel canvases
- Pencil, eraser, eyedropper, color picker, and clear-canvas tools
- Mouse, touch, and Apple Pencil support through Pointer Events
- Stroke-based undo and redo history
- Optional pixel grid and integer zoom levels
- Image import through the upload button or drag and drop
- PNG, JPG, WebP, and the first frame of GIF files supported
- Aspect-ratio-preserving, nearest-neighbor image conversion
- AI-agent-friendly
pixel-loop/v1animation JSON import - Live JSON validation with frame, row, and column error messages
- Snapshot-based animation workflow
- Frame editing, duplication, deletion, and drag-to-reorder
- Animation preview with adjustable playback speed from 1–24 FPS
- GIF export at 1×, 2×, 4×, or 8× scale
- Transparent or custom-color GIF backgrounds
- Automatic IndexedDB saving with no account or backend
- Complete project reset with confirmation
- Node.js 22 or later recommended
- npm
git clone git@github.com:milkmidi/pixel-loop.git
cd pixel-loop
npm install
npm run devOpen the local URL printed by Vite, usually http://localhost:5173.
- Choose a canvas resolution.
- Select the Pencil tool and a color.
- Draw directly on the canvas.
- Use Snapshot to save the current canvas as an animation frame.
- Keep editing the retained canvas to create the next frame.
Use either method:
- Select Upload image in the header.
- Drag an image directly onto the canvas.
The image is centered, scaled to fit the current canvas without changing its aspect ratio, and converted into editable pixels. Importing over painted content requires confirmation and can be undone.
- Give the agent instructions to Codex, Claude Code, or another AI agent.
- Ask it to generate an animation and return only
pixel-loop/v1JSON. - Select Import JSON in Pixel Loop.
- Paste the generated JSON and review the live validation summary.
- Select Import animation to replace the current project.
The format uses compact palette symbols and fixed-width rows, making it readable, token-efficient, and easy to validate. See the complete format specification and JSON Schema.
- Select a frame thumbnail to edit it.
- Use Update Frame to save changes back to the selected frame.
- Drag frames to reorder them.
- Duplicate or delete frames from the timeline.
- Up to 100 frames are supported; a performance warning appears at 80 frames.
- Choose the FPS, output scale, and background behavior.
- Select Export GIF.
- If the canvas has unsaved changes, choose whether to append it as the final exported frame.
GIFs use nearest-neighbor scaling, preserve crisp pixel edges, and loop forever.
| Shortcut | Action |
|---|---|
P |
Pencil |
E |
Eraser |
I |
Eyedropper |
Space |
Create a snapshot |
Arrow keys |
Move all canvas pixels by one cell |
Cmd/Ctrl + Z |
Undo |
Cmd/Ctrl + Shift + Z |
Redo |
Shortcuts are disabled while an input, select, or button has focus.
Pixel Loop is local-first:
- Images and project data are not uploaded to a server.
- The current project is automatically stored in IndexedDB.
- Reloading the page restores the saved canvas, frames, and settings.
- Reset entire project clears the canvas, frames, history, and settings after confirmation.
# Run the development server
npm run dev
# Run the test suite
npm test
# Type-check the project
npm run lint
# Create a production build
npm run build- React 19
- TypeScript
- Vite
- Tailwind CSS
- gifenc
- dnd-kit
- Lucide React
- Vitest
src/
├── components/ UI, canvas, preview, timeline, and dialogs
├── hooks/ Reusable pixel history state
├── lib/ Pixel, image import, GIF export, and storage logic
├── App.tsx Application state and workflows
├── styles.css Tailwind entrypoint and shared visual styles
└── types.ts Project and animation types
docs/
├── PIXEL_LOOP_AGENT_INSTRUCTIONS.md
├── pixel-loop-format.md
└── pixel-loop.schema.json