034
LVL 02 — CIRCUIT BREAKER SESSION 034 DAY 34

UNDO / REDO

🎫 PIXELCRAFT-022
Feature | 🟠 Hard | Priority: 🔴 Critical

The #1 user complaint: no undo. Implement Ctrl+Z (undo) and Ctrl+Y (redo) for all editing operations.
CONCEPTS.UNLOCKED
📚
Stack Data Structure
LIFO — Last In, First Out. Like a stack of plates: you add to the top and remove from the top. The most recently added item comes out first.
⬆⬇
Stack Operations
push (add to top), pop (remove from top), peek (look at top without removing), isEmpty (is it empty?), size (how many items?).
↩↪
The Undo/Redo Pattern
Two stacks: undo stack + redo stack. Every action pushes the old state onto undo. Undo pops from undo, pushes to redo. Redo does the reverse.
📜
The Command Pattern
Each action is an object that can be undone. Instead of just storing state snapshots, you store commands: { action: 'brightness', value: +20, undo: () => ... }.
#
Private Fields
#items = [] — the # prefix makes a field truly private. No code outside the class can access it. Encapsulation: the internal data structure is hidden.
🧠
Memory Management
Each undo entry stores a full state snapshot. 50 undo levels on a 4K image = 50 × 33MB = 1.6GB. Limit the stack size. Consider storing diffs instead of full snapshots.
HANDS-ON.TASKS
01
Implement a Stack Class
class Stack { #items = []; push(item) { this.#items.push(item); } pop() { return this.#items.pop(); } peek() { return this.#items[this.#items.length - 1]; } isEmpty() { return this.#items.length === 0; } size() { return this.#items.length; } clear() { this.#items = []; } }
The class keyword creates a blueprint for objects. #items is a private field — only Stack methods can access it. This is your first data structure built from scratch.
02
Build the Undo/Redo System
const undoStack = new Stack(); const redoStack = new Stack(); function performAction(newState) { undoStack.push(currentState); // Save before changing redoStack.clear(); // New action invalidates redo currentState = newState; render(); } function undo() { if (undoStack.isEmpty()) return; redoStack.push(currentState); currentState = undoStack.pop(); render(); } function redo() { if (redoStack.isEmpty()) return; undoStack.push(currentState); currentState = redoStack.pop(); render(); }
The key insight: a new action clears the redo stack. If you undo 5 times then do something new, those 5 "future" states are gone — you've created a new timeline.
03
Wire to Keyboard Shortcuts

Ctrl+Z = undo, Ctrl+Y = redo. Remember event.preventDefault() to stop the browser's default undo behavior from Session 20.

04
Show Count in UI

Display: "5 undos available | 2 redos available"

Update the count after every action, undo, and redo. Grey out the buttons when their stack is empty.

05
Test Extensively

Test sequence: apply 10 filters → undo 5 → redo 3 → new action → verify redo cleared.

StepUndo StackRedo Stack
Apply 10 filters10 items0 items
Undo 5 times5 items5 items
Redo 3 times8 items2 items
New action9 items0 items (cleared!)
06
Limit Stack Size

Memory management: max 50 undos. When the undo stack exceeds 50, remove the oldest item from the bottom. This prevents PixelCraft from consuming gigabytes of RAM.

07
Close the Ticket
git switch -c feature/PIXELCRAFT-022-undo-redo git add src/scripts/ git commit -m "Implement undo/redo with Stack data structure (PIXELCRAFT-022)" git push origin feature/PIXELCRAFT-022-undo-redo # PR → Review → Merge → Close ticket ✅
CS.DEEP-DIVE

Stacks appear everywhere in computing.

The undo pattern you just built is used by every editor, every IDE, every spreadsheet. You implemented the Command Pattern — one of the most famous in software engineering.

// Stacks in the wild:

Browser back/forward  → two stacks
Call stack            → function execution is
                         a stack
Compiler parsing      → evaluate 3 + 4 * 2
                         correctly
Depth-first search    → uses a stack
Text/image editors    → undo/redo

// Simple data structure.
// Profound applications.
"Stack Mastery"
[A] Write a bracket validator using a Stack: check if "({[]})" is balanced. Push opening brackets, pop on closing brackets, verify matches.
[B] Optimize memory: instead of storing full ImageData snapshots, store the filterState diff (what changed). Reconstruct any state by replaying diffs from the original.
[C] Add an "Edit History" panel showing all actions as a visual timeline. Click any point in the timeline to jump to that state (not just one step at a time).
REF.MATERIAL
VIDEO
CS50 / Harvard
Clear visual explanation of the stack data structure: push, pop, LIFO, real-world analogies, and implementation.
STACKCS50ESSENTIAL
ARTICLE
Mozilla Developer Network
Complete reference: class syntax, constructors, methods, private fields (#), static members, inheritance, and getters/setters.
CLASSESMDNREFERENCE
VIDEO
The Coding Train
Visual walkthrough of building an undo/redo system: the two-stack approach, state management, and edge cases.
UNDO/REDOVISUAL
ARTICLE
Wikipedia
The design pattern behind undo/redo: encapsulating actions as objects with execute() and undo() methods. Used across all major software.
DESIGN PATTERNCOMMANDCS
ARTICLE
javascript.info
Interactive class tutorial: syntax, constructors, methods, inheritance, private/public fields. Runnable examples.
CLASSESINTERACTIVE
// LEAVE EXCITED BECAUSE
Ctrl+Z works. YOU built it. With a data structure you can explain to anyone. Undo is one of the most beloved features in all of software.