Drag a rectangle on a face. Shift = erase. Hover a face to preview, click to stamp.
all layers
No model yet
Drop a .vox file to open it

New model

Size in voxels (1 to 256 each) and metres per voxel.

Help

Tools

Left mouse uses the current tool. Right-drag orbits, middle-drag pans, wheel zooms (or pick the Orbit tool to orbit with the left button).

AAdd: click or drag to place voxels on the face under the mouse
EErase: click or drag to remove voxels
PPaint: recolour existing voxels
IEyedropper: pick the colour of a voxel
BBox fill: drag a rectangle on a face; the Extrude field sets how far it sticks out. Tick Erase (or hold Shift while dragging) to cut the box into the model instead, Extrude layers deep, starting with the face you dragged on. One undo step per box.
TText: type the text, pick font (5x7 or 3x5), size, depth and mode (add / paint / carve). Hover a face to see where it goes (centred on the mouse, read from that side; floor text on faces that point up). Click to stamp. One undo step. Mirror X is not applied to text.
OOrbit tool
MMirror X on/off (edits are repeated on the other side)
[ ]Slice one layer down / up
Ctrl+ZUndo (at least 100 steps; running a recipe is one step)
Ctrl+Y / Ctrl+Shift+ZRedo
Ctrl+SDownload .vox
Ctrl+EnterRun the recipe (inside the recipe box)
EscCancel a box drag

The Slice slider hides everything above the chosen layer (y) so you can edit inner layers. The page saves your model and recipe in this browser automatically; New clears that.

Opening .vox files

A .vox keeps its own colours. Colours that exactly match palette.json show their palette name; the others show their hex code. Snap to palette (above the palette list) changes every voxel whose colour is not in palette.json to the nearest palette.json colour and switches the model to palette.json names. It asks first, saying how many colours and voxels will change, and is one undo step. Use it on models voxelised in ObjToSchematic. A file with no colour chunk opens with MagicaVoxel's default palette.

Recipe helpers

model(w, h, d, scale)                 start a model (scale = metres per voxel)
box(x, y, z, w, h, d, "colour")
hollow_box(x, y, z, w, h, d, "colour", wall = 1)
cylinder(x, y, z, radius, length, "colour", axis = "y")
line(x1, y1, z1, x2, y2, z2, "colour")
remove(x, y, z, w, h, d)              cut a hole
paint(x, y, z, w, h, d, "colour")     recolour existing voxels only
mirror_x()                            copy the left half onto the right
text(x, y, z, "TEXT", "colour", opts) letters in voxels (see below)
text_width("TEXT", opts)              width in voxels, to centre text
text_height(opts)                     height in voxels

text options (all optional): font "5x7" (default) or "3x5"; size voxels per font pixel (1); face "front" (read from +z, default), "back" (from -z), "left" (from -x), "right" (from +x), "floor" (from above, top of the text toward -z); depth layers thick (1); mode "add" (default), "paint" (recolour existing voxels only) or "carve" (remove; colour can be null); align "left" (default), "center" or "right", relative to x (z on left/right faces); spacing voxels between letters (1). (x, y, z) is the bottom-left corner of the text as the reader sees it, on the layer nearest the reader; depth goes away from the reader. Characters: A-Z, 0-9, space and - . , : / # ( ) ! ? ' & + ยท (lowercase is drawn as uppercase).

text(4, 10, 6, "BAY 1", "sign_text");
text(20, 0, 30, "A3", "safety_yellow", { face: "floor", mode: "paint" });
text(Math.floor(W / 2), 30, 6, "DROP ZONE", "sign_text", { align: "center" });

Axes: x = right, y = up, z = toward the viewer. Colour names come from palette.json. Loops and variables are normal JavaScript.