A single-file, browser-based scratchpad for checking isometric art against a tile grid.
Drop your PNGs onto the page, tell it what tile size they were drawn for, paint them onto a grid, and read off the numbers your engine actually needs — tile size, scale, texture origin, footprint in cells. Nothing is uploaded anywhere; everything runs locally in the browser.
Iso Sandbox is a common tool between the art and the dev side, meant to cut down the back-and-forth between them.
Isometric art usually looks wrong the first time it lands in an engine: a tree is two pixels too tall, a wall does not line up with the floor, a rock is anchored to the wrong corner.
- Artists test their assets on a real grid before sending them.
- Developers get the settings the artist used, ready to drop into the engine.
- Multiple layers, each with its own tile size and vertical offset — floor, walls, and props can sit on different grids at the same time.
- Ground tiles vs. objects — ground art fills its cell, objects stand on it and are Y-sorted so they can overhang.
- Anchoring controls — pick which corner of the covered cells the art sits on, which point of the image is pinned there, and a pixel-level fine offset.
- Multi-cell footprints up to 24 × 24 cells.
- Brush with adjustable area, random coverage (for scattering grass or rocks) and random horizontal/vertical mirroring.
- Reference block — a plain grey box at the current tile size, for judging whether real art is too tall or too wide.
- Common aspect presets — 2:1 classic isometric, √3:1 true isometric, 4:1 shallow.
- Undo/redo, pan, zoom, grid and focus toggles.
- JSON export of every setting and placement, optionally with the images embedded as base64 so a scene reopens exactly as you left it.
Open the hosted version, or download
index.html and double-click it. No build step, no dependencies — that one file is the
whole application.
Then:
- Drop image files (PNG, JPG, WebP) anywhere on the window.
- Select an asset and set Drawn for tile width to the tile width the art was authored against, or press Fit to cells to infer it.
- Choose whether it is a ground tile or an object, how many cells it covers, and where it sits.
- Drag on the canvas to paint. Hold Alt and drag to erase.
- Open the Scene section to save or copy the JSON.
| Key | Action |
|---|---|
| drag | Place art |
| Alt + drag | Erase |
| right-drag | Pan |
| wheel | Zoom |
| 1…9 | Pick art |
| Shift + 1…9 | Pick layer |
| - / = | Brush area |
| [ / ] | Size of selected art |
| Ctrl + Z / Ctrl + Shift + Z | Undo / redo |
| G / F | Toggle grid / focus |
| ? | Show the shortcut list |
Note: nothing is stored between sessions. Save a scene JSON before closing the tab.
Save JSON file (or Copy) produces a document like this:
Conventions:
x/yon a cell are TileMap cell coordinates;+xruns down-right on screen and+ydown-left.texture_originis measured in pixels in the tile's own space, from a centred-on-cell draw;+ymoves the art up. It uses thetile_sizeaspect of the first layer the tile is placed on.- The
editorblock is Iso Sandbox's own state. Engines can ignore it; it exists so a saved scene reopens with the same controls.
Exports without embedded images still load — the scene opens with placeholders, and
dropping the matching art back in relinks it by filename. You can also drop a .json
straight onto the canvas to open it.
Any current desktop browser (Chrome, Firefox, Edge, Safari). It needs Canvas 2D, the File API and drag-and-drop. Not designed for touch or small screens.
Bug reports, ideas and pull requests are welcome — see CONTRIBUTING.md.
{ "format": "iso-sandbox", "version": 1, "exported": "2026-01-01T00:00:00.000Z", "conventions": { "cell": "...", "texture_origin": "...", "note": "..." }, "tiles": [ { "id": 0, "name": "grass.png", "source_file": "grass.png", "type": "tile", // "tile" (ground) or "sprite" (object) "texture_size": { "x": 256, "y": 128 }, "authored_tile_size": { "x": 128, "y": 64 }, "size_in_tiles": { "x": 1, "y": 1 }, "scale": 1.0, "texture_origin": { "x": 0, "y": 0 }, "image_data": "data:image/png;base64,…", // only when "Include the images" is on "editor": { "anchor": "front", "image_pivot": "bottom", "origin_offset": { "x": 0, "y": 0 }, "cursor": "center" } } ], "layers": [ { "name": "Ground", "visible": true, "tile_size": { "x": 128, "y": 64 }, "y_offset": 0, "cells": [ { "tile": 0, "x": 0, "y": 0, "flip_h": false, "flip_v": false } ] } ] }