Sprite Forge β a browser sprite-sheet animator. Loads a built-in sample sheet, lets you set the grid (columns Γ rows), pick a row to play, scrub frames, and tune speed/zoom. Upload, drag-drop, or paste any other sheet to animate it instead; uploaded sheets persist and show up in the gallery.
Live: https://dcm31--a0f721e05e3711f1b6c61607ee4eb77e.web.val.run
- Columns / Rows β match the sheet's grid. Frame size is derived automatically.
- Single row / All frames β play just one row, or every frame left-to-right, top-to-bottom.
- Loop / Ping-pong β ping-pong bounces back through the frames (nice for short cycles).
- Speed / Zoom β fps and nearest-neighbour scale, so pixels stay crisp.
- Upload / drag-drop / paste an image to add a sheet. Click any frame in the strip to play that row.
- Save grid to sheet stores the columns/rows/fps you dialled in for an uploaded sheet.
The bundled sample is a 4Γ4 sheet β rows are down / up / side / side.
The server is static + a small JSON API. The sample sheet is embedded as base64 and
served like any other sheet; uploads live in blob storage. All animation happens
client-side on a <canvas>.
Rendering mermaid diagram...
| Route | Does |
|---|---|
GET /api/sheets | List sheets (sample first, then newest uploads) |
GET /api/sheets/:id/image | Raw sheet pixels (sample from embed, rest from blob) |
POST /api/sheets | Upload a sheet (multipart: file, name, cols, rows, fps) |
PATCH /api/sheets/:id | Update name/cols/rows/fps |
DELETE /api/sheets/:id | Remove an uploaded sheet |
| File | Role |
|---|---|
main.ts | Hono server β JSON API, static files, /source redirect |
index.html | Markup + controls |
style.css | Retro-arcade styling |
app.js | All animation logic (geometry, rAF loop, strip, gallery, upload/paste) |
default-sprite.js | The built-in sample sheet as an embedded base64 PNG |
Uploaded sheets are kept in std/blob under three keys: sprite:index (an id list),
sprite:meta:<id> (the metadata), and sprite:img:<id> (base64 pixels). The sample
id is special-cased and never touches blob.
Replace SAMPLE_B64 (and tweak SAMPLE_META) in default-sprite.js with another
base64-encoded image. It's served straight from /api/sheets/sample/image, so no
upload is needed for the default.