Calic 46d1e78758 feat(map-editor): world-overlay variant for Cell-Tile mode
draw_world_overlay gains a cell-tile branch that renders a faint
render-cell grid and a 1-px hover-cell outline around the cursor
cell. The existing G-toggle continues to gate the entire overlay.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 23:05:22 +02:00

sporel-module-map-editor

Interactive map editor for Sporel .map.json files. v0.2 series ships the Rev 4 UX architecture (see design paper design/2026-05-28-autotile-blob-styles-design.md §11 in sporel-meta): top toolbar with mode-switch + actions, right Layers side-panel, bottom palette strip of material slot thumbnails, mouse drag-paint, and two mutually-exclusive paint modes (Auto-Tile vs Direct).

Run

Default — edit the module's in-place work map (maps/work.map.json, a 16×16 schema-v3 map bound to the blob_rect_stone material):

bash scripts/run-map-editor.sh

With a target — copy a real map in, edit, copy back out:

bash scripts/run-map-editor.sh ~/Projects/Sporel/sporel-modules/spine-prototype/maps/demo.map.json

Or via the install layer (per install-reference.sh):

Doubleclick C:/Games/Sporel/bin/Sporel.exe  →  launcher  →  map-editor

UI

  • Top toolbar (full-width): Auto-Tile/Direct mode buttons (mutually exclusive, Tab toggles), Save (S), Erase (E), Rotate (R), Flip (H), Reset (0), Help (I). Each button shows its hotkey label inline. The active mode is highlighted.
  • Right Layers side-panel (8 rows top-down: canopy, upper_wall, wall, lower_wall, topsurface, surface, subsurface, foundation). Per row: visibility eye + active marker + layer name.
    • Left-click name → set active layer
    • Left-click eye → toggle layer visibility
    • Right-click row → also toggles visibility
  • Bottom palette strip: 14 swatches (slots 1-14). Real tile thumbnails rendered from the active atlas via maps.atlas_tile_uv. Active slot has a gold border.
    • Left-click → set active slot
  • Status chip (bottom-left of palette band): mouse-cell, dirty flag (* when unsaved), and current transform indicator (slot=N rot=N flip=N) for Direct-mode awareness.
  • Auto-Tile-mode world overlay: cell grid (1 px), vertex dots (4 px squares), and a snapped-vertex highlight ring (green) at the nearest vertex to the cursor.
  • Cheatsheet modal (I): centered dim-overlay listing all hotkeys
    • LMB/RMB drag semantics.

Modes

Mode LMB on canvas RMB on canvas Notes
Auto-Tile Paints vertex at snap target — maps.set_vertex(layer, vx, vy, true). Any-corner rule flips up to 4 surrounding cells to material; renderer derives slot/rot/flip from neighbour bitmask. Clears vertex — set_vertex(..., false) Transform controls ignored (slot is derived from neighbours).
Direct Writes per-cell override — maps.set_override(layer, x, y, {slot, rot, flip}). Bare slot int when canonical (rot=0+flip=0). Clears override — maps.clear_override(layer, x, y) Honours active Rot/Flip from toolbar. Use to force-place a specific orientation that the auto-derived slot wouldn't pick.

Both modes support drag-paint: hold LMB (or RMB) and stroke across the canvas to apply the action at every hovered vertex/cell. UI hits on the toolbar / side-panel / palette never enter drag-mode.

Hotkeys

Key Action
Tab Toggle mode (Auto-Tile ↔ Direct)
I Show / hide cheatsheet
S Save current map to work.map.json
E Erase tile at mouse cell
R Cycle rotation 0 → 1 → 2 → 3 → 0 (Direct-mode override)
H Toggle flip 0 ↔ 1 (Direct-mode override)
0 Reset transform (rot=0, flip=0)
Esc Quit
LMB-drag Stroke-paint (mode-dependent)
RMB-drag Stroke-clear

Headless / smoke

ci_frames = 30 in manifest.module. The editor reads SPOREL_CI=1 and auto-exits after 30 frames so the smoke harness can run it without a window-close click.

SPOREL_CI=1 ./Sporel.exe --module=map-editor   # exits with rc=0 after ~0.5 s

Limitations (current scope)

  • Single-atlas palette: the palette draws from atlas_idx=0 only. Multi-atlas selector is a future slice. Workaround: keep one material atlas per map for now.
  • Single Flip flag: design paper mentions Flip-H + Flip-V as separate controls, but the override format only stores one flip field; combined with rot (0-3) the single flip covers all 8 D4 orientations, so the second button would be redundant.
  • No modifier hotkeys: lib-core.input doesn't expose modifier combos, so Shift+R for CCW rotation isn't supported. Workaround: press R three times.
  • No Decal / Entity sub-selectors: Direct mode on non-terrain layers is unimplemented (lands in 0.2.0d).
  • No Material-Properties modal: base_color re-bake trigger
    • tint editor are deferred (also 0.2.0d).
  • No multi-vertex brush sizes / procedural fill / undo-redo — see design paper §11 "Out of scope" for the full list.

Plan + spec

  • Design paper: docs/design/2026-05-28-autotile-blob-styles-design.md §11 in sporel-meta
  • Plan: docs/superpowers/plans/2026-05-28-map-editor-blob-v2.md

Menu UI (v0.3.0)

Top toolbar replaced with a seven-category menu bar (File, Edit, View, Map, Tools, Window, Help) plus a sticky two-segment Mode-pill on the right end. Item types: action, modal, toggle, submenu, separator; items can be conditionally disabled. A single-stack modal framework hosts the existing Cheatsheet (I) and three new modals: Save As, Map Properties (read-only), About. The Esc key cascades modal -> menu -> quit.

New Map and Open Map appear in the File menu as disabled placeholders pending a v3-aware maps.create and an engine.asset.list_dir in a future engine + lib slice.

All previous hotkeys (Tab, S, E, R, H, 0, D, G, I, Esc) continue to work; their bindings are documented in the items where applicable and in the in-editor Cheatsheet modal.

Description
Interactive map editor for v2 Sporel map files.
Readme 603 KiB
Languages
Lua 98.3%
Shell 1.7%