-- sporel-module-map-editor v0.1.0 -- Interactive map editor — see docs/superpowers/specs/2026-05-23-sporel-module-map-editor-design.md local maps = require("lib-core.maps") local camera = require("lib-core.camera") local input = require("lib-core.input") local state = require("src.state") local actions = require("src.actions") local ui = require("src.ui") -- ===================================================================== -- Setup -- ===================================================================== local WORK_PATH = "maps/work.map.json" local work_map_id = maps.load(WORK_PATH) maps.set_current(work_map_id) maps.load_textures(engine.module.asset_aliases()) state.set_map(work_map_id, WORK_PATH) -- Center camera on the map local m_size = maps.size() local t_size = maps.tile_size() camera.set_target((m_size.w * t_size) / 2, (m_size.h * t_size) / 2) camera.set_zoom(1.0) -- ===================================================================== -- Input bindings -- ===================================================================== input.bind("quit", { "escape" }) input.bind("erase", { "e" }) input.bind("rotate", { "r" }) input.bind("save_map", { "s" }) engine.print("map-editor: ready. Hotkeys: E=erase, R=rotate, S=save, ESC=quit") -- ===================================================================== -- Frame hooks -- ===================================================================== function update(ctx, dt) -- Quit if input.was_action_pressed("quit") then engine.exit() return end -- Update mouse-cell tracking for status chip local mx, my = engine.input.get_mouse_pos() local wx, wy = camera.screen_to_world(mx, my) local cell_x = math.floor(wx / t_size) local cell_y = math.floor(wy / t_size) if cell_x >= 0 and cell_y >= 0 and cell_x < m_size.w and cell_y < m_size.h then state.set_mouse_cell(cell_x, cell_y) else state.set_mouse_cell(nil) end -- Hotkey: rotate if input.was_action_pressed("rotate") then actions.cycle_rotation() end -- Hotkey: save if input.was_action_pressed("save_map") then actions.save() end -- Hotkey: erase (uses current mouse-hover cell) if input.was_action_pressed("erase") then local cell = state.get_mouse_cell() if cell then actions.erase_cell_at(cell.x, cell.y) end end -- Mouse clicks: hit-test UI first, then map area if engine.input.was_mouse_pressed(engine.input.MOUSE_LEFT) then local consumed = ui.handle_click(mx, my, "left") if not consumed and state.get_mouse_cell() then local cell = state.get_mouse_cell() actions.paint_cell_at(cell.x, cell.y) end end if engine.input.was_mouse_pressed(engine.input.MOUSE_RIGHT) then ui.handle_click(mx, my, "right") end camera.update(dt) end function draw() maps.draw_map() ui.draw() end