Appearance
- i want an undo system
- first, figure out "go back to" points
- drag
- stretch (gigantic hierarchy ???)
- rename
- edit a cell
- delete
- add/insert child
- rotate
- straighten
- not?
- select
- fit
- 2D/3D
- solid/xray
Proposal: Snapshot-based Undo
Why snapshots over commands
Command pattern would require retrofitting every mutation site with execute/undo pairs — 12+ action types, each with its own reversal logic (delete is especially gnarly: subtree + formula cleanup). Snapshot approach: capture serialized scene state before each mutation, restore to undo.
Existing infrastructure
scenes.save()serializes the full scene toPortable_Scene(all SOs, constants, camera, selection)Smart_Object.serialize()/deserialize()round-trips cleanly- Engine's setup/load path rebuilds the live scene from
Portable_Scene
Design
New file: src/lib/ts/managers/History.ts
class History {
stack: Portable_Scene[] // past states (capped, eg 50)
redo_stack: Portable_Scene[]
snapshot(): void // capture current state, push to stack, clear redo
undo(): Portable_Scene | null // pop stack, push current to redo, return scene to restore
redo(): Portable_Scene | null // pop redo, push current to stack, return scene to restore
clear(): void // reset both stacks (on file load / new scene)
}Snapshot sites (before the mutation, not after)
- Drag start —
drag.set_target() - Rotate start —
rotate_object()first call per gesture - Dimension commit —
dimensions.commit() - Angular commit —
angulars.commit() - Delete —
engine.delete_selected_so() - Add child —
engine.add_child_so() - Insert from file —
engine.insert_child_from_text() - Rename — SO name or constant name change
- Reset angle —
P_Angles.sveltereset handler - Formula edit — attribute cell commit in
D_Attributes
Not undoable (view state, not model state)
select, fit, 2D/3D toggle, solid/xray
Trigger
Cmd+Z / Cmd+Shift+Z in Events.ts keydown handler.
Restore path
undo() returns a Portable_Scene. Caller (engine) runs the same path as file-load: clear scene, deserialize SOs, rewire hierarchy, rebuild constraints, restore selection + camera.
Tradeoffs
- Memory: 50 snapshots of a typical scene (10 SOs) ≈ ~500KB. Fine.
- Hierarchy concern ("stretch — gigantic hierarchy ???"): snapshot sidesteps this. No need to figure out which descendants changed. Restore the whole thing.
- Continuous drags: only pre-drag state saved, so undo jumps to before the drag started. Standard CAD behavior.
Build plan
History.ts— stack manager (~60 lines)history.snapshot()calls at each mutation site (~10 one-liners)engine.undo()/engine.redo()— call history then restore- Cmd+Z / Cmd+Shift+Z handling in
Events.ts