Skip to content

feat(history): add undo/redo (Ctrl+Z / Ctrl+Y)#16

Open
PeritoAndre wants to merge 2 commits into
mehanix:masterfrom
PeritoAndre:feat/undo-redo
Open

feat(history): add undo/redo (Ctrl+Z / Ctrl+Y)#16
PeritoAndre wants to merge 2 commits into
mehanix:masterfrom
PeritoAndre:feat/undo-redo

Conversation

@PeritoAndre

Copy link
Copy Markdown

The editor pushes actions onto FloorPlan.actions but never undoes them (see the undo-related TODOs in WallNodeSequence/DeleteWallNodeAction). This adds a HistoryManager that records a JSON snapshot of the plan via the existing FloorPlan.save() at the end of each interaction and reloads a previous/next snapshot to undo/redo.

  • HistoryManager (singleton, in the style of AddWallManager): undo/redo stacks, debounced capture on a document 'pointerup' (fires regardless of Pixi event bubbling), anti-reentrancy guard while restoring.
  • Main: HistoryManager.Instance.init() at the end of setup(); Ctrl+Z / Ctrl+Shift+Z / Ctrl+Y added to the existing document.onkeydown handler.
  • Public canUndo()/canRedo()/undo()/redo() so toolbar buttons can be wired too.

PeritoAndre and others added 2 commits June 7, 2026 11:32
The editor pushes actions onto FloorPlan.actions but never undoes them (see the
undo-related TODOs in WallNodeSequence/DeleteWallNodeAction). This adds a
HistoryManager that records a JSON snapshot of the plan via the existing
FloorPlan.save() at the end of each interaction and reloads a previous/next
snapshot to undo/redo.

Why snapshots instead of per-action undo(): moves, resizes and rotations are
applied directly by the transform handles and aren't modeled as Actions, so a
command-based history would miss them. Snapshots cover every change uniformly
and reuse the serialization the editor already has.

- HistoryManager (singleton, in the style of AddWallManager): undo/redo stacks,
  debounced capture on a document 'pointerup' (fires regardless of Pixi event
  bubbling), anti-reentrancy guard while restoring.
- Main: HistoryManager.Instance.init() at the end of setup(); Ctrl+Z /
  Ctrl+Shift+Z / Ctrl+Y added to the existing document.onkeydown handler.
- Public canUndo()/canRedo()/undo()/redo() so toolbar buttons can be wired too.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The wall tool's first click leaves a lone node (no wall attached yet) until the
next click connects it. The pointerup after that first click was recorded as a
snapshot, so undoing a freshly drawn wall stepped back to that lone node and
left an orphan point on the canvas instead of clearing the wall.

Skip commit() while a wall chain is open (AddWallManager.previousNode set). The
chain is captured once it ends — double-click, or a tool change via resetTools()
clears previousNode and the following pointerup records the finished walls.
A whole multi-click polyline becomes a single undo step, which is the expected
granularity for one continuous draw.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant