47 Commits

Author SHA1 Message Date
Calic
451da04cbd feat: ship manifest.launcher.md for master-detail launcher v0.3.3 2026-06-11 07:57:58 +02:00
Calic
bde1f7acfa chore(deps): bump lib-core.render 0.1.0 to 0.2.0, declare lib-core.composition
render 0.2.0 added a transitive dep on lib-core.composition.
Engine resolver is strict-strcmp (no semver expansion), so
consumers must declare every transitive lib in deps[].
v0.3.2
2026-06-10 23:28:52 +02:00
Calic
2734efa1a9 chore(map-editor): bump to v0.3.1; cheatsheet + README sync
Bumps the module version to v0.3.1 (lib-core.maps dep pin was
already bumped to 0.5.7 in CT6 to allow the editor to load).
Updates the file header, startup banner, cheatsheet Tab entry
(now mentions all three modes), and appends a Cell-Tile Mode
subsection to the README.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 23:10:30 +02:00
Calic
340dd5f700 test(map-editor): t11 confirms Edit-menu disable covers Cell-Tile
The existing `disabled = function() return not mode_is("direct")
end` predicate already covers Cell-Tile mode (which is also
non-direct). Self-test t11 enumerates the three transform items
across all three modes and confirms each is disabled in
auto-tile AND cell-tile, enabled only in direct.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 23:07:31 +02:00
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
Calic
51138e257f feat(map-editor): paint actions + LMB/RMB routing for Cell-Tile
paint_cell_material_at and erase_cell_material_at wrap
maps.set_cell_material with a mark_dirty. The canvas-click
dispatch in M.handle_click and the per-frame drag handler both
route through these actions when state.mode == "cell-tile". Self-
test t10 confirms a paint round-trips through maps.get_cell_material.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 23:02:53 +02:00
Calic
6eacde3eaa feat(map-editor): mode-pill 3 segments for Auto/Cell/Direct
MODE_PILL_W widens 130 -> 195 (3 x 65). mode_pill_layout returns
the new cell segment between auto and direct; draw_mode_pill
iterates the new triple; the click-handler dispatches the cell
segment to actions.set_mode("cell-tile"). Self-test t9 confirms
the three segments sit at consecutive SEG_W offsets.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 23:00:12 +02:00
Calic
e745be8d07 feat(map-editor): cell-tile as third state.mode + Tools menu entry
state.set_mode now accepts "cell-tile"; toggle_mode is renamed
cycle_mode (with a backwards-compat alias) and now advances
auto-tile -> cell-tile -> direct -> auto-tile. Tools > Mode
submenu gains a third entry between Auto-Tile and Direct.
Self-test gains t8 (set/get round-trip) and t12 (cycle order).
Startup banner updated to "Tab=cycle mode". Manifest dep pin
bumped to lib-core.maps 0.5.7 to match installed version.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 22:56:04 +02:00
Calic
f06ef5e2cb test(map-editor): seven menu-UI assertions on first CI frame
Adds a self_test() entry-point that the editor invokes once when
SPOREL_CI=1 is set, exercising the seven §7.1 acceptance checks
from the menu-UI spec: open/close, toggle flip, modal absorb,
disabled-item no-op, mode switch, category switch, and layer
visibility submenu round-trip. Any failed engine.test assertion
exits with non-zero.

Fixes cheatsheet modal on_click to close only on inside-bounds
click (was closing on any click, breaking t3 outside-click-absorb
assertion).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 20:14:29 +02:00
Calic
398d3b4dd9 chore(map-editor): bump to v0.3.0; cheatsheet + README sync
Updates the in-editor Cheatsheet to reflect the new G binding and
the Esc cascade; bumps manifest.module and the file header to
v0.3.0; adds a Menu UI section to README.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 20:10:32 +02:00
Calic
1945e91441 refactor(map-editor): retire legacy toolbar
Removes the eight-button top toolbar, its layout helpers, click
dispatcher and all TOOLBAR_* constants. Side-panel and palette
offsets now anchor to MENU_BAR_H. Mode-pill no longer overlaps a
parallel toolbar element.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 20:07:57 +02:00
Calic
107eade2fa feat(map-editor): wire Window toggles to hide side panel + palette
Both render and click handlers are now gated by the
is_layers_panel_shown / is_palette_shown predicates, so the new
Window menu toggles produce visible effects in the editor.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 20:04:55 +02:00
Calic
f2123ba79c feat(map-editor): save_as, map_properties, about modals
Three new modal entries plugged into the unified modal stack.
save_as accepts a typed filename and writes via
maps.save_to_disk; map_properties shows current map id, size and
atlas list as a read-only inspector; about is static text only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 20:02:17 +02:00
Calic
9213d3f91b feat(map-editor): submenu support — View > Layers, Tools > Mode
One level of submenu nesting. View > Layers exposes all eight
terrain-stack layers as toggles, sharing state with the right-side
Layers panel. Tools > Mode mirrors the Mode-pill's auto/direct
toggle with a Tab hotkey shown on Direct. Submenu opens by clicking
the parent item; clicking elsewhere closes everything.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 19:58:30 +02:00
Calic
211056ac8c feat(map-editor): fill all seven menu categories with initial items
Items in File / Edit / View / Map / Tools / Window / Help. New Map
and Open Map appear as disabled placeholders pending a v3-aware
maps.create and engine.asset.list_dir. Undo/Redo are disabled
pending an edit-stack. Cycle Rotation / Toggle Flip / Reset
Transform disable themselves in Auto-Tile mode via a mode_is()
callback. Submenus for View > Layers and Tools > Mode are
declared but their items array stays nil until the submenu render
slice.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 19:55:06 +02:00
Calic
b5afe35df8 feat(map-editor): dropdown click dispatch
Routes clicks on dropdown items to their per-type handler:
action.fire, open_modal for modal items, toggle.fire for toggles.
Disabled items absorb without closing; separators are inert.
Clicks outside the open dropdown close the menu and fall through to
canvas handling.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 19:51:58 +02:00
Calic
2c3015685c feat(map-editor): dropdown render for action/modal/toggle/separator
Renders the open dropdown for the active menu category with a
three-column item layout (indicator | label | hotkey). Toggle items
show their bound is_on() state with a [v]/[ ] indicator, modal
items append "...", separators draw as thin rules, disabled items
render in a muted colour. Submenu chevron is wired but submenus
themselves land in a later slice.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 19:49:53 +02:00
Calic
2eebd3d2d5 feat(map-editor): menu-bar top-level labels render + click
Adds the seven category labels (File, Edit, View, Map, Tools,
Window, Help) at the top of the screen with hover highlight and
click-to-open / click-to-close behaviour. Item arrays are still
empty stubs; dropdown rendering lands in the next slice.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 19:47:11 +02:00
Calic
1a9daa8ce1 feat(map-editor): Mode-pill render + click handler
Sticky two-segment pill anchored to the menu bar's right edge.
Click on a segment calls actions.set_mode; Tab hotkey continues to
toggle and the pill reflects the new state next frame. Pill
visually overlaps the legacy toolbar in this slice; the toolbar is
removed in a later commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 19:43:39 +02:00
Calic
6956919414 feat(map-editor): Esc cascades modal -> menu -> quit
Esc no longer immediately exits the editor; it first dismisses any
open modal, then any open dropdown menu, and only falls through to
engine.exit() when no overlay is up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 19:41:51 +02:00
Calic
15159d7fd5 refactor(map-editor): generalize cheatsheet into MODALS framework
Introduces a single-stack modal table where each entry declares
title, dimensions, render fn and on_click fn. The existing
Cheatsheet becomes the framework's first entry; behaviour is
preserved exactly. Dispatcher absorbs clicks while any modal is
open and routes them to the modal's on_click for close-decision.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 19:38:42 +02:00
Calic
e373aa8a1f refactor(map-editor): unify modal/menu state, drop cheatsheet_open
Adds menu_open, modal_open, show_layers_panel, show_palette to the
editor's state singleton; removes the now-redundant cheatsheet_open
flag. All cheatsheet-toggle paths route through the new generic
modal_open API. Visible behaviour unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 19:31:00 +02:00
Calic
1bf5f46924 feat(map-editor): layout constants for menu-bar UI
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 19:26:17 +02:00
Calic
5a3f633ab2 feat(map-editor): v0.2.0c.4 — G-toggle mode-aware world overlay
Adds a G key that toggles the world-space overlay on and off
(default on). The overlay adapts to the active painting mode:

- Auto-Tile mode shows the map-grid (paint-tile boundaries, which
  sit at half-tile offsets from the render-cell boundaries in
  dual-grid), the per-map-tile vertex dots, and the snapped
  paint-target highlight.
- Direct mode shows only a subtle render-cell grid, since LMB
  strokes write directly to render-cells in that mode.

Bumps the lib-core.maps dep pin to 0.5.6 to pick up the dual-grid
bitmask fix that makes the auto-tile output match the dual-grid
mental model.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-01 17:19:30 +02:00
calic
7df21d62fa chore(gitignore): ignore local screenshots/ from debug-ipc 2026-05-29 11:47:06 +02:00
calic
cf5771a573 feat(map-editor): v0.2.0c.3 — debug overlay (D toggle, per-cell slot/rot)
Diagnostic for the dual-grid + blob-14 painting model: D-key toggles
a per-cell text annotation rendered over the map. For each material
cell on the active layer, draws "S<slot>r<rot>" (and "f" when flip=1)
in green at the cell's top-left, sourced from the new lib-core.maps
0.5.5 cell_material_slot getter.

Use case: confirm that the renderer actually picks distinct slots
(corner_full / tee_full / cross / etc.) for painted regions rather
than always picking slot 13 solid — the rectilinear style fills enough
of each cell that visually adjacent slots 3/7/13 are hard to
distinguish without numerical labels.

Inline today; plan-stub
`docs/superpowers/plans/2026-05-29-debug-overlay-extract-to-lib.md`
deferred until a 2nd consumer (vagrant debug-render, puppet-editor,
etc.) appears.

Also bumps lib-core.maps dep 0.5.4 -> 0.5.5.
2026-05-29 09:56:52 +02:00
calic
c66e670336 docs(README): rewrite for v0.2 Rev 4 UI + drag-paint 2026-05-29 09:33:26 +02:00
calic
70b841c8d6 feat(map-editor): v0.2.0c.2 — palette uses real tile thumbnails
Replaces the placeholder colour swatches with actual atlas sub-tex
draws via the new lib-core.maps 0.5.4 getters:
 - atlas_diffuse_handle(atlas_idx) -> raylib Texture2D handle
 - atlas_tile_uv(atlas_idx, slot)  -> {x, y, w, h} or nil

Renders each slot 1..14 (lib slot 0..13) scaled to fit the swatch
rect with draw_sprite_transform. Falls back to the legacy colour
square + slot-number label when the atlas isn't loaded (headless,
material missing, etc.).

Drives off state.get_active_atlas() (defaults to 0 — fine for the
single-atlas work map; multi-atlas selector is a future slice).

Also bumps lib-core.maps dep 0.5.3 -> 0.5.4.
2026-05-29 01:37:45 +02:00
calic
c0a1bcf162 chore(deps): bump lib-core.maps 0.5.2 -> 0.5.3 2026-05-29 01:29:20 +02:00
calic
77832c07b2 feat(map-editor): v0.2.0c.1 — drag-paint strokes
LMB-hold strokes a line of paints (Auto-Tile: each hovered vertex;
Direct: each hovered cell as an override). RMB-hold strokes a line
of erases (clear_vertex / clear_override). On mouse-press inside the
UI (toolbar / palette / side-panel) the drag never enters paint-mode
so toolbar interaction stays unaffected.

State machine:
 - press(button) outside UI -> drag_paint = "paint"|"erase"
 - while drag_paint and corresponding button still down -> dispatch
   paint at current snap_vertex / mouse_cell each frame
 - button release -> drag_paint = nil

Idempotency: maps.set_vertex / set_override / clear_* are no-op when
the target state is unchanged, so the per-frame repaint is cheap and
doesn't grow the JSON on save.
2026-05-29 01:05:39 +02:00
calic
30f38d771f feat(map-editor): v0.2.0c — transform controls + Direct-mode override paint
State + actions:
 - active_flip (0/1) joins active_rot (0..3). Combined the two cover
   all 8 D4 orientations; single Flip button is sufficient (H+V
   would be redundant).
 - toggle_flip / reset_transform / paint_override_at /
   erase_override_at.

Toolbar:
 - New Flip (H) + Reset (0) buttons next to Rotate (R).
 - Status chip extended with `slot=N rot=N flip=N` indicator.

Paint:
 - Direct-mode + LMB on canvas now calls maps.set_override on the
   active material-bound terrain layer. Bare slot int when canonical
   (rot=0+flip=0), {slot, rot, flip} object otherwise — matches the
   v0.5.1 override-format extension. Palette slot 1..14 maps to lib
   slot 0..13 (palette is user-friendly 1-based; lib API is 0-based).
 - Direct-mode + RMB on canvas calls maps.clear_override.
 - Auto-Tile mode unchanged; transform state is ignored there (the
   renderer derives slot/rot/flip from the vertex bitmask).

Hotkeys:
 - h -> flip (new)
 - 0 -> reset_transform (new)
 - r continues to cycle rotation CW; Shift+R for CCW is out because
   lib-core.input has no modifier-combo support (deferred).

Cheatsheet rows updated.
2026-05-29 00:46:08 +02:00
calic
497c139727 fix(map-editor): v0.2.0b.1 — bind blob_rect_stone material so Auto-Tile renders
work.map.json was still schema-v2 with the legacy fa_terrain_v1
atlas — neither has a `material` field on its layers, so the
renderer's vertex/blob path never fired and Auto-Tile painting had
no visible effect (the set_vertex writes landed but the renderer
fell back to the cell-tile path that doesn't consume them).

Migration:
 - schema_version 2 -> 3
 - size 4x4 -> 16x16 (room to paint)
 - atlases: fa_terrain_v1 -> blob_rect_stone (S-V2E2-RM-Blob 14-slot
   atlas from lib-asset.prototype-blob-geom)
 - layers: surface + wall, both with "material": "blob_rect_stone";
   vertices+overrides start empty (lib-core.maps lazy-allocates on
   first set_vertex)

Manifest:
 - asset_aliases: fa_terrain_v1 -> blob_rect_stone (lib-asset.
   prototype-blob-geom)
 - deps: drop prototype-fa-starter, add prototype-blob-geom 0.1.0
2026-05-29 00:34:12 +02:00
calic
25e838c54f feat(map-editor): v0.2.0b — bottom palette + Auto-Tile vertex paint
UI:
 - Bottom palette strip (above status, left of side-panel): 14
   coloured swatches numbered 1-14. Click selects state.active_tile.
 - World-space overlay (Auto-Tile mode only): cell grid + vertex
   dots + snapped-vertex highlight ring.
 - Side-panel + status repositioned to clear the palette band.
 - Cheatsheet updated with the new LMB/RMB canvas + palette rows.

Paint:
 - Auto-Tile mode: LMB on canvas -> maps.set_vertex(active_layer,
   snap.vx, snap.vy, true); RMB -> set_vertex(..., false). Snap is
   computed in update() by rounding world coords to the nearest
   (W+1)x(H+1) vertex; off-map cursor publishes nil.
 - Direct mode: unchanged from 0.2.0a (paint_cell_at with active
   slot + rotation).

Notes:
 - Palette swatches are placeholder solid colours, not real tile
   thumbnails — that needs a tile-UV getter on lib-core.maps, which
   is out of scope for this sub-slice.
 - Transform controls, Direct-Override transform writes, and the
   Decal/Entity sub-selectors land in 0.2.0c/d.
2026-05-29 00:03:42 +02:00
calic
35d9940d63 feat(map-editor): v0.2.0a — Rev 4 layout reorg + mode switch + cheatsheet
Layout (per design paper §11):
 - Top toolbar with Mode buttons (Auto-Tile / Direct), Save, Erase,
   Rotate, Help.
 - Right Layers side-panel (8 rows, top-down draw order) as single
   source of truth for visibility + active layer — replaces the old
   left-edge layer chips.
 - Bottom status bar.

State + actions:
 - mode = "auto-tile" | "direct" (Tab toggles).
 - cheatsheet_open modal toggle (I key, dimmed overlay + key/action
   table).
 - SPOREL_CI=1 auto-exits after 30 frames (matches vagrant pattern;
   ci_frames in manifest is not engine-enforced for kind:"module").

Paint behaviour itself is unchanged from 0.1.0 — bottom palette + the
real Auto-Tile / Direct paint loops land in 0.2.0b/c/d.

deps: lib-core.maps 0.5.1 -> 0.5.2 (consumes set_vertex / get_vertex).
2026-05-28 23:56:02 +02:00
calic
8dbb5b9d9c deps: bump lib-core.maps 0.5.0 -> 0.5.1
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 23:11:09 +02:00
calic
34f8b85d57 deps: bump lib-core.maps 0.4.0 -> 0.5.0
Required by the schema-v3 work in lib-core.maps. The map-editor
v0.1 stays on the legacy tiles[] path and continues to function
unchanged through the auto-upgrade v1->v2->v3 chain on load.

Full migration to v3's vertex-painting + override-UI lands in the
map-editor v0.2 slice
(sporel-meta/docs/superpowers/plans/2026-05-28-map-editor-blob-v2.md).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 20:50:21 +02:00
Calic
8f5e59a9f7 Drop stale engine-binding-missing NOTE comments
The draw_rect_lines and draw_line bindings exist now; the inline
NOTE comments warning about missing bindings are stale.
2026-05-24 03:21:19 +02:00
Calic
e87948a3ca Wrap map draw in camera.begin/finish so world-space transforms apply
Without the camera scope, maps.draw_map() rendered the map at
screen coords starting at (0,0) regardless of camera.set_target,
and screen_to_world's inverse produced bogus cell coords (mouse
in screen-center mapped to top-left tile). Spine-prototype's
render() shows the right pattern: world-space draws inside
camera.begin/finish, screen-space overlays after.
2026-05-24 03:17:16 +02:00
Calic
2e25833a93 Rename draw() hook to render() so the engine actually calls it
The engine module-lifecycle looks up HOOK_RENDER by the global
name 'render' (engine_module_lifecycle.c:166). The previous draw()
function was a global with no caller, so the editor's UI never
rendered — the engine fell back to its 'no render hook defined'
placeholder.
2026-05-24 03:12:27 +02:00
Calic
b5fee40406 Match module id to directory name convention
Other module manifests (spine-prototype, vagrant-skeleton, etc.) use
the short directory name as the id, not the long 'sporel-module-X'
form which is reserved for the Gitea slug. The mismatch caused the
launcher script (which exports SPOREL_MODULE=map-editor) to fail
with ENGINE_ERR_MODULE_NOT_FOUND.
2026-05-24 03:08:31 +02:00
Calic
66997be86b Inline state/actions/ui into init.lua
The engine's Lua sandbox rejects require() for non-declared-dep
module names like 'src.state'. Multi-file modules in this codebase
either inline everything (spine-prototype, vagrant-skeleton) or
use dofile (lib-sporel.launcher). For three modules that share a
state singleton, dofile would cause state divergence. Cleanest
fix is to inline all three into init.lua via IIFE-wrapped local
module tables, preserving the file-internal namespacing while
satisfying the sandbox.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 03:08:03 +02:00
Calic
6d2d3ea26d Wire up editor: input bindings, frame hooks, launcher script
init.lua loads the work map, binds hotkeys (E/R/S/Esc), tracks
mouse-cell per frame, dispatches clicks to the UI hit-tester
and falls through to paint-cell for unconsumed map-area clicks.
run-map-editor.sh handles copy-in/copy-out for a real target map
or runs in-place against the module's work slot.
2026-05-24 01:22:49 +02:00
Calic
f8ce43784f Add immediate-mode overlay UI module
Vertical layer-chip column on the left edge (Roof up top with
divider, entity-slot dashed line between Lw and Ts), collapsible
atlas+tile picker bottom-left, status chip bottom-right. Each
frame redraws everything and dispatches mouse clicks via priority
hit-tests. Tile thumbnails are placeholder gray rects in v0.1.0
because lib-core.maps does not yet expose per-tile UVs to Lua.
2026-05-24 01:16:14 +02:00
Calic
9fefe7619a Add editor actions module composing maps write APIs
paint_cell_at, erase_cell_at, cycle_rotation, save plus thin
wrappers for the UI hit-tests (set_active_layer/_atlas/_tile,
toggle_layer_visible/_roof_mode/_picker). Each action updates
state and delegates the actual map mutation to lib-core.maps.
2026-05-24 01:11:35 +02:00
Calic
0b2eb20199 Add editor state module with accessor API
Singleton table covering map id+path, active layer/atlas/tile/rot,
roof-mode flag, per-layer visibility flags, dirty flag, and picker
open/close state. Mutations go through setters so the test module
can verify state transitions without poking the internal table.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-24 01:09:08 +02:00
Calic
45992065a1 Add manifest.core for engine bootstrap
Engine requires both manifest.core (lib metadata) and manifest.module
(module metadata) for proper package discovery and loading.
2026-05-24 01:06:04 +02:00
Calic
9d41ba8890 Scaffold sporel-module-map-editor package
Empty launchable module with deps on lib-core.maps 0.4.0, render,
camera, input, and the fa_terrain_v1 asset alias. Renders the
default 4x4 empty work-map; interactive editing wired in
subsequent commits.
2026-05-24 01:04:44 +02:00