# 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 bash scripts/run-map-editor.sh ``` With a target — copy a real map in, edit, copy back out: ```bash 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`): ```text 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. ```bash 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`