Skip to content

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.

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.

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.

  1. In the Level panel (Select tool, nothing selected), set World size bigger than one screen: type world w×h and 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.
  2. 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.
  3. Place a sprite and name one player (Select tool → name field).
  4. In Select set Camera → follow → player. Bounds default to the whole World size (auto); uncheck it to drag an explicit orange camera-bounds frame.
  5. 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.

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.

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:

Terminal window
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 simulator
tools/build_mpy.sh # optional: my_scene.mpy for the device

Load 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.