···140140 - getShapesOnCurrentPage(state)
141141 - getSelectedShapes(state)
142142143143-Invariants (pick “repair” and test it):
143143+Invariants (pick "repair" and test it):
144144[x] Implement enforceInvariants(state): EditorState (repair strategy):
145145 - selectionIds := selectionIds filtered to existing shapes
146146 - currentPageId must exist:
···204204[x] Define draw order = page.shapeIds order
205205[x] hitTest uses reverse order for topmost selection
206206207207-Tests:
208208-[x] hitTestPoint returns expected shapeId for overlapping shapes
209209-[x] tolerance works for line/arrow selection
210210-211207(DoD):
212208- You can hover shapes and log the hit shape id (no selection yet).
213209···254250255251Tool router:
256252[x] routeAction(state, action) -> newState (delegates to active tool)
257257-258258-Tests:
259259-[x] Switching tools calls onExit/onEnter in correct order
260260-[x] Tool ignores actions it doesn't care about
261253262254(DoD):
263255- A dummy tool can consume pointer events and update state deterministically.
···287279[x] Escape clears selection
288280[x] Delete removes selected shapes
289281290290-Tests:
291291-[x] drag moves exactly by delta
292292-[x] shift-click toggles membership
293293-[x] delete removes and clears selection
294294-295282(DoD):
296283- You can select and move shapes reliably.
297284···302289Goal: place shapes with dedicated tools.
303290304291Rect tool (repeat pattern for others):
305305-[ ] PointerDown on canvas:
292292+[x] PointerDown on canvas:
306293 - create a draft rect shape with w/h=0 at startWorld
307294 - selection = [newId]
308308-[ ] PointerMove:
295295+[x] PointerMove:
309296 - update w/h based on currentWorld - startWorld
310310-[ ] PointerUp:
297297+[x] PointerUp:
311298 - if too small, delete it (click-cancel behavior)
312299 - else finalize
313300314314-[ ] Implement ellipse tool (same mechanics)
315315-[ ] Implement line tool (a=startWorld, b=currentWorld)
316316-[ ] Implement arrow tool (same as line but type="arrow")
317317-[ ] Implement text tool:
301301+[x] Implement ellipse tool (same mechanics)
302302+[x] Implement line tool (a=startWorld, b=currentWorld)
303303+[x] Implement arrow tool (same as line but type="arrow")
304304+[x] Implement text tool:
318305 - click to create text shape
319306 - open in-place editor overlay (contenteditable) in Svelte
320320-321321-Tests:
322322-[ ] shape creation creates one record with correct props
323323-[ ] click-cancel removes zero-area shapes
324307325308(DoD):
326309- You can draw rect/ellipse/line/arrow/text on the canvas.
···32931211. Milestone K: Bindings for arrows (v0) *wb-K*
330313==============================================================================
331314332332-Goal: arrow endpoints can “stick” to shapes.
315315+Goal: arrow endpoints can "stick" to shapes.
333316334317Binding creation:
335318[ ] On arrow finalize:
···50648918. Milestone R: Quality polish (what makes it feel "real") *wb-R*
507490==============================================================================
508491509509-Goal: the UX crosses the “this is legit” threshold.
492492+Goal: the UX crosses the "this is legit" threshold.
510493511494[ ] Snapping:
512495 - snap move to grid