Product design

Bolt.new: try changes on the page before sending the batch to AI

Bolt.new is a browser-based AI app builder that turns requirements into runnable websites and apps. Visual Edits lets users adjust text and styles in a preview, inspect a batch of changes, then save it to code.

Break down the problem and try your own design and implementation first. Then explore the reasoning to check states, edge cases, trade-offs, and ways to test your approach. The guide offers a reasoning path, not a complete implementation.

01
FRONTEND EXERCISEAdvanced

How can undo history and the final changes stay consistent?

Scenario

Design a local draft-state module for your own visual editor. Users can repeatedly change properties, undo, redo and discard one property’s changes. Finally, export differences from the initial page. Keep both action history and actual changes to submit correct. Network requests, model callbacks, DOM targeting, page switching, CSS inheritance and shorthand properties are outside scope.

Inputs and terms

  1. The initial page is an ordered array of at most 100,000 elements. Each item is a non-null object with a unique nonempty string id and three fixed properties: text is a string, including empty; fontSize is an integer from 8 through 96; color is a lowercase six-digit HEX string such as #336699. Ignore other fields. The baseline is readonly for this session, and the three properties are independent.
  2. Process at most 100,000 events in arrival order. The four event types are set(id, property, value), discard(id, property), undo and redo. Discard restores one property to its baseline; set and discard affect only one property. Missing fields, unknown IDs or properties, and invalid types or values return a clearly located error without changing current values, either history stack or the difference set. Later valid events may still proceed.
  3. A set or discard that actually changes the current value creates one history step and clears the redo branch. A valid same-value event is a no-op: it neither enters history nor clears redo. Undo reverses the latest effective step; redo reapplies the latest undone step. An empty relevant stack also makes either operation a no-op.
  4. Only properties whose current values differ from baseline belong to the pending difference set. A property may have many history steps but exports at most one record containing id, property, before and after. Export in initial element order, then text, fontSize, color order. Do not output equal baseline and current values.
  5. Any invalid initial element rejects initialization as a whole; no partially usable state is returned. After successful initialization, each event is independently atomic. Upstream has normalized strings; do not add color-equivalence conversion or text-length limits. State your assumptions about string reads and comparisons when analyzing complexity.

Start with this example

Initially there is only element A: text=报名 (Register), fontSize=24, color=#888888. Apply: ① set size to 32; ② set size to 28; ③ set color to #336699; ④ undo; ⑤ set size to 28 again, unchanged; ⑥ redo; ⑦ discard size; ⑧ undo; ⑨ undo; ⑩ set text to 立即报名 (Register now); ⑪ redo.

List current properties, differences and redo availability after ③, ⑤, ⑥, ⑦, ⑧, ⑩ and ⑪. Explain why ⑤ must preserve the redo of ③, and why ⑩ must leave ⑪ with nothing to redo. Insert invalid size 0 at any intermediate point and explain why it cannot damage history.

Deliverables

Explain the roles of baseline, current values, history and difference indexes; trace the example; propose at least five invariants and tests. Each effective set, discard, undo or redo must avoid scanning the entire page or all history. Analyze time and space for n elements, m events and k final differences. You may explain structures such as JavaScript Map, but provide reasoning only, without a full implementation or line-by-line pseudocode.

Explore the reasoning
  1. Store history separately from differences. Baseline supplies before, and current values supply after. The difference index keeps only properties that differ from baseline. Each history step retains one actual property change and its prior and next values. Repeated size changes can therefore be undone individually even though export combines them.
  2. Validate before deciding whether anything changes. Invalid events cannot alter any structure. A valid same-value set or discard of an already-baseline value leaves both history and redo alone. Only a genuine new change invalidates the old redo branch.
  3. Restore just one property per historical step. Undo and redo move the same step between two stacks, use its recorded values and refresh that property’s membership in the difference set. Do not record undo as a new edit or copy the whole page at every step.
  4. Trace the branch. At ③, size 28 and blue give two differences. At ⑤, size 28 and gray leave only the size difference, with redo available. At ⑥, state matches ③ and redo is empty. At ⑦, size 24 and blue leave only color. At ⑧, size 28 and blue allow redoing discard. At ⑨, size 28 and gray remain. At ⑩, text becomes 立即报名, size stays 28 and color stays gray: text and size differ. The new edit clears redo, so ⑪ changes nothing. Text remains 报名 before ⑩.
  5. Check invariants and costs. Baseline never changes; difference keys are unique; membership exactly matches inequality from baseline; undo/redo can reverse and reapply an effective step; invalid and no-op events preserve redo. An ID index and two stacks support O(1) per event under average Map access, O(n) initialization and O(m) total history space. Sort k exported differences by original element index and fixed property order in O(k log k), with O(k) output space; current values and indexes add O(n+k). Include actual character costs if string copying or comparison scans content, rather than treating arbitrary-length text as free.