Web level editor
This browser editor for picogame scenes and levels lets you import sprite and tileset
PNGs, paint tilemaps (with per-tile solid/coin/goal/hazard flags), place sprites,
HUD labels, zones, spawn points and particles, set up a follow-camera, and export the scene.json
that tools/scene_build.py bakes for the device/simulator.
The canvas is a window onto a world that can be larger than the device screen, so you can use the editor for both fixed-screen and scrolling levels.
The button above opens the editor full-screen (Esc closes). It also lives standalone at
/editor/. On first run a short getting-started card appears; press ? any time for
the full shortcut list.
Learn by loading a demo
Section titled “Learn by loading a demo”The Demos menu in the top bar loads ready-made levels. Open one to see how its Map size and Camera are configured:
- Sample (one screen) — a compact one-screen level showing every feature.
- Scrolling platformer (bounded) — a 960×240 world (~3 screens wide). Follow-camera on axis x with bounds = the finite world, so the camera clamps at the left/right ends (a level with definite ends).
- Open world (bigger both ways) — a 640×480 quest map, bigger than the screen in both dimensions. Follow-camera on axis xy, so you free-roam in x and y.
The getting-started card links to the same two scrolling demos.
World size vs. device screen
Section titled “World size vs. device screen”Two sizes matter, and the editor shows them as a pair in the Level panel (Select tool, nothing selected):
- World size — how big the whole level is, in pixels. This is where you set the size of your level: it defines the world extent and drives the camera bounds, Fit, the minimap, and the size of new tilemap layers. A live readout shows “≈ N × M screens”.
- Device screen — one handheld view (320×240), drawn as the dashed white box on the canvas.
To make a level that scrolls, set a World size bigger than one screen.
Make a level that scrolls
Section titled “Make a level that scrolls”- In the Level panel (Select tool, nothing selected), set World size bigger than one screen:
type
world w×hand Apply world size, or use a preset: 1 screen, 3× wide (platformer), 2×2 screens (open world). The editor offers to grow/crop your tilemap layers to fill it. - Pick the Paint tool and a tileset (import a PNG, or + Colour tileset for placeholders); a new layer already fills the whole world. Paint your ground across it. Pan with Space-drag / middle-drag / the Pan tool, use the minimap (top-right) to jump around, Fit to frame the whole world, 100% for 1:1.
- Place a sprite and name one
player(Select tool → name field). - In Select set Camera → follow → player. Bounds default to the whole World size (auto); uncheck it to drag an explicit orange camera-bounds frame.
- Export → scene.json, keep the PNGs next to it, and bake.
Changing World size (or a layer’s own size in the Paint panel) pads with empty tiles on grow, and crops with a confirm if painted tiles would be lost. Everything is undoable (Ctrl+Z). The per-layer Layer size control is for cases where a layer should be smaller than the world or offset for parallax. For most levels, change World size.
Tools & controls
Section titled “Tools & controls”| Tool | Key | Does |
|---|---|---|
| Select | 1 / V | Pick + move objects (drag). Click a stacked spot again to cycle. Edit tile flags/colour. |
| Paint | 2 / B | Paint the active layer. Drag = brush, Shift-drag = rectangle, Alt-click = flood fill. |
| Place | 3 / P | Drop the chosen sprite. |
| HUD | 4 | Camera-fixed text label; also manages particle layers. |
| Zone | 5 | Drag a trigger rectangle, then tag it. |
| Point | 6 | Drop a named point (e.g. spawn). |
| Pan | H / Space | Pan the view (middle-drag also pans). |
Wheel scrolls, Ctrl/⌘+wheel zooms to the cursor, +/− zoom, F fits. Arrows nudge the
selection (Shift = ×10) or pan when nothing is selected. Ctrl+Z/Y undo/redo, Ctrl+C/V/D
copy/paste/duplicate, Delete deletes, Esc deselects. The panel on the right changes with the
active tool, so you only see the controls that tool needs. Status messages do not interrupt your
work with prompt() or alert() dialogs.
Tile flags
Section titled “Tile flags”A flag gives a tile a meaning the game reads; it does not change how it looks. The loader builds fast lookup tables so the game asks the meaning instead of hardcoding tile numbers:
| flag | the game reads it as | typical use |
|---|---|---|
| solid | view.is_solid(tx, ty) |
walls / floor that block movement |
| coin | view.tile_has(tx, ty, "coin") |
collectible the game removes on pickup |
| goal | view.tile_has(tx, ty, "goal") |
level exit / win tile |
| hazard | view.tile_has(tx, ty, "hazard") |
lava / spikes that hurt the player |
Toggle Show flag badges on map (Paint panel) to see coloured corner badges on flagged tiles. Colour tilesets (Paint → + Colour tileset) make a placeholder set with no art; edit each colour with a picker, + add colour for more.
Bake and run on a device or in the simulator
Section titled “Bake and run on a device or in the simulator”Keep the imported/exported PNGs next to the downloaded scene.json, then:
python3 tools/scene_build.py my.scene.json # -> my_scene.py (SCENE = {...})python3 sim/run.py <a consumer that imports my_scene> # preview in the simulatortools/build_mpy.sh # optional: my_scene.mpy for the deviceLoad it in a game with picogame_scene.load(pg, my_scene.SCENE, font=...). See
examples/picogame_scene_example.py for a data-driven game built on a baked scene.