# Phase 4: 2D Top-Down Room Editor — Core

**Status:** :white_check_mark: Complete
**Parent plan:** [PLAN.md](./PLAN.md)
**Domain:** frontend

## Objective
Build the core 2D top-down room editor using react-konva. This is the primary editing surface: grid, zoom/pan, wall rendering, tool system (select, door, window placement), snap-to-grid, undo/redo, and save to API.

## Tasks

- [x] Task 1: Set up react-konva Stage in `RoomEditorPage` — full-viewport canvas with zoom (scroll wheel) and pan (middle mouse / two-finger drag)
- [x] Task 2: Implement grid layer — configurable grid size (default 0.1m), visual grid lines, scale ruler on edges showing meters
- [x] Task 3: Render room walls from polygon shape data — closed polygon of wall segments, fill room interior with light color
- [x] Task 4: Implement tool system architecture — `EditorContext` with active tool state, tool-specific cursor, tool-specific click/drag handlers
- [x] Task 5: Implement Select tool — click to select elements, multi-select with Shift+click or drag rectangle, selection bounding box with resize handles
- [x] Task 6: Implement Door placement tool — click on a wall to place a door, door renders as an arc symbol in the wall, configurable width
- [x] Task 7: Implement Window placement tool — click on a wall to place a window, window renders as parallel lines in the wall, configurable width + height
- [x] Task 8: Implement snap-to-grid — `useSnapping` hook with configurable snap granularity
- [x] Task 9: Implement snap-to-wall — doors and windows snap to nearest wall segment when placed near one (built into DoorTool/WindowTool via `findNearestWall`)
- [x] Task 10: Implement undo/redo system — command pattern stack (`UndoRedoContext`). Keyboard shortcuts: Ctrl+Z / Ctrl+Shift+Z / Ctrl+Y
- [x] Task 11: Implement editor toolbar — horizontal toolbar above canvas with tool buttons (Select, Door, Window), undo/redo buttons, zoom controls, grid toggle, snap toggle, save button
- [x] Task 12: Implement properties panel — right sidebar showing properties of selected element(s). Editable fields for width, height, position, elevation.
- [x] Task 13: Implement canvas layer system — separate Konva Layers for: grid, walls, openings, electrical (placeholder), furniture (placeholder), measurements, selection overlay
- [x] Task 14: Implement save/load — save current room state (walls, openings) to API. Load via `getRoomFull` on page mount.
- [x] Task 15: Add keyboard shortcuts — Delete (remove selected), Escape (deselect/cancel), Ctrl+A (select all), Ctrl+S (save), V/D/W (tool shortcuts)
- [x] Task 16: Implement measurement annotations — auto-display wall lengths, room dimensions. Show distance from selected opening to wall ends. Auto-hide at low zoom.

## Files to Modify/Create
- `apps/client/src/pages/RoomEditorPage.tsx` — replace placeholder with full editor layout
- `apps/client/src/components/editor/EditorCanvas.tsx` — react-konva Stage with zoom/pan
- `apps/client/src/components/editor/layers/GridLayer.tsx` — grid rendering
- `apps/client/src/components/editor/layers/WallLayer.tsx` — wall polygon rendering
- `apps/client/src/components/editor/layers/OpeningLayer.tsx` — doors and windows on walls
- `apps/client/src/components/editor/layers/SelectionLayer.tsx` — selection overlay, handles
- `apps/client/src/components/editor/layers/MeasurementLayer.tsx` — dimension annotations
- `apps/client/src/components/editor/tools/SelectTool.ts` — select tool logic
- `apps/client/src/components/editor/tools/DoorTool.ts` — door placement logic
- `apps/client/src/components/editor/tools/WindowTool.ts` — window placement logic
- `apps/client/src/components/editor/EditorToolbar.tsx` — toolbar UI
- `apps/client/src/components/editor/PropertiesPanel.tsx` — properties sidebar
- `apps/client/src/components/editor/context/EditorContext.tsx` — editor state context (room data, selected elements, active tool)
- `apps/client/src/components/editor/context/UndoRedoContext.tsx` — undo/redo command stack
- `apps/client/src/components/editor/hooks/useEditorZoom.ts` — zoom/pan logic
- `apps/client/src/components/editor/hooks/useSnapping.ts` — snap-to-grid and snap-to-wall
- `apps/client/src/components/editor/hooks/useKeyboardShortcuts.ts` — keyboard shortcut handler
- `apps/client/src/components/editor/utils/geometry.ts` — geometry helpers (point-on-wall, distance, intersection)
- `apps/client/src/components/editor/utils/wallUtils.ts` — wall-specific geometry (find nearest wall, position along wall)

## Acceptance Criteria
- Canvas renders room walls from polygon data with correct scale
- Grid displays with configurable size and scale ruler
- Zoom and pan work smoothly (mouse wheel + drag)
- Select tool allows selecting, moving, and multi-selecting elements
- Doors and windows can be placed on walls and snap correctly
- Undo/redo works for all operations (add, move, delete, modify)
- Properties panel shows and allows editing selected element properties
- Editor state saves to and loads from the API
- Keyboard shortcuts work (Ctrl+Z, Delete, Escape, Ctrl+S)
- Measurement annotations show wall lengths and room dimensions

## Notes
- Konva uses a Stage > Layer > Shape hierarchy. Each Layer gets its own canvas for performance.
- Grid should use a repeating pattern rather than individual lines for performance at high zoom
- All coordinates are in meters (matching the data model). Canvas pixel-to-meter conversion via zoom level.
- The tool system should be extensible — Phase 5 adds electrical and furniture tools
- Undo/redo uses command pattern: each command has `execute()` and `undo()` methods
- Measurement annotations should auto-hide at low zoom levels to avoid clutter
- Electrical and furniture layers are created but empty — placeholders for Phase 5

## Review Checklist
- [x] All tasks completed
- [x] Code follows project conventions
- [x] No unintended side effects
- [ ] Build passes
- [ ] Tests pass (new + existing)

## Handoff to Phase 5

### What was built

Phase 4 implemented the complete 2D top-down room editor with react-konva. The editor is a full-page layout with toolbar on top, canvas in center, and properties panel on right.

### Architecture

- **Editor state** is managed via `EditorContext` (React context + reducer pattern). All state is immutable.
- **Undo/redo** uses a command pattern via `UndoRedoContext`. Each command has `execute()` and `undo()` methods.
- **Canvas layers** are separate Konva `<Layer>` components (7 layers): grid, walls, openings, electrical (placeholder), furniture (placeholder), measurements, selection.
- **Tool system** is driven by `activeTool` in EditorContext. Tool logic lives in `tools/*.ts` files as pure functions. The `EditorCanvas` dispatches to the active tool in its mouse event handlers.
- **Snapping** is implemented in `hooks/useSnapping.ts` with snap-to-grid and snap-to-wall. Door/window tools have their own wall snapping built into their `compute*Preview` functions.

### How to add new tools (Phase 5)

1. Add the tool type to `EditorToolType` union in `types.ts` (e.g., `'electrical'` and `'furniture'` are already there).
2. Create a tool file in `tools/` with preview computation and element creation functions.
3. Add tool button to `TOOLS` array in `EditorToolbar.tsx`.
4. Add tool cursor to `TOOL_CURSORS` in `EditorCanvas.tsx`.
5. Add mouse event handlers for the new tool in `EditorCanvas.tsx`'s `handleMouseDown` and `handleMouseMove` callbacks.
6. Implement the corresponding layer in `layers/ElectricalLayer.tsx` or `layers/FurnitureLayer.tsx` (currently empty placeholders).
7. Add `EditorAction` variants if needed in `types.ts` and handle them in the reducer in `EditorContext.tsx`.

### API functions added

`apps/client/src/api/client.ts` now exports:

- `bulkUpdateWalls(roomId, walls)` — PUT /api/rooms/:id/walls
- `createWallOpening(roomId, data)` — POST /api/rooms/:id/openings
- `updateWallOpening(roomId, openingId, data)` — PUT /api/rooms/:id/openings/:openingId
- `deleteWallOpening(roomId, openingId)` — DELETE /api/rooms/:id/openings/:openingId

### Known limitations / future improvements

- **Element dragging** (moving selected elements by dragging) is not yet implemented. The select tool supports click-select and drag-rectangle multi-select, but not drag-to-move.
- **Resize handles** on the selection bounding box are rendered but not interactive (no drag-to-resize).
- **Grid performance** at very high zoom could be improved by switching to a repeating canvas pattern instead of individual Line shapes.
- **Two-finger pan** on trackpad is not implemented (only middle-mouse-button pan). Could be added by detecting `e.evt.ctrlKey` on wheel events (pinch-to-zoom) or touch events.
