Skip to content

fix(studio): undo right after an edit undoes that edit, even before its save lands - #4807

Draft
miguel-heygen wants to merge 2 commits into
mainfrom
studio/undo-waits-for-committed-edit
Draft

miguel-heygen wants to merge 2 commits into
mainfrom
studio/undo-waits-for-committed-edit

Conversation

@miguel-heygen

Copy link
Copy Markdown
Collaborator

What

Cmd+Z pressed right after an edit, before the edit's save has landed, now undoes that edit. Before, it could undo nothing or the edit before it, and the edit's save then landed after the undo and stayed. A resize or move undone that way left the element in a third state (size reverted, position not), and a nudge burst was never undone at all.

Why

Undo first waits for pending edits (waitForPendingDomEditSaves), but it only saw saves already queued in the DOM edit save queue or registered as pending edits. A canvas or panel edit counts from the moment its commit is called, and many commits spend a while before their first write: a resize parses the element's animations before it writes, and a nudge burst does not call its commit until 400 ms after the last arrow key. An undo in that window found nothing pending, stepped the history, and the save landed afterwards.

How

  • Every action that saves an edit, as the DOM edit context hands it to the canvas and the panels, registers its whole promise as a pending edit when it is called. Undo's drain already waits for pending edits, so it now waits for the edit on screen and then undoes it. A failed edit rolls itself back and reports itself; the registration only waits for it to settle, so it cannot fail the undo.
  • A nudge burst still inside its debounce registers with the existing pending-edit flush, the same mechanism the colour grading controls use for their debounced save. Undo's drain commits the burst and waits for its save.

Measurement

Per-frame probe in the built Studio on the edit accuracy bench's gsap=none fixtures, px placement, no rotation, root, 100% zoom. Undo is pressed on the frame after release (or after the last arrow key), then the file and the screen are read 8 s later.

case main: file restored branch: file restored
resize no yes
nudge no yes
crop yes yes

The screen for nudge on this base still differs after the undo: on main a nudge in a composition without GSAP writes a GSAP set and reloads the preview. That route changes in the move and nudge PR, and with it the screen comes back too.

Test plan

  • DomEditContext.test.tsx: an edit committed through the context actions, whose save has not written anything yet, holds undo's drain until it settles; an edit that fails does not fail the drain. The first fails without the registration, the second fails when the registration keeps the rejection.
  • useDomEditNudge.test.tsx: undo's drain commits a burst still inside its debounce and waits for its save. Fails without the flush listener.
  • Studio typecheck, oxlint, oxfmt.

Before

Undo pressed on the frame after a resize, with the save slowed to 1.5 s so the race is certain: the box ends in neither the original nor the resized state, and the file keeps the resize.

Before: early undo

After

The same undo waits for the resize's save and undoes it: the box is back where it started and the file matches.

After: early undo

@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown

Edit accuracy: 434 passing here, 434 on the base branch

The gate passes.
Smoothness is reported in the artifact, not gated. A case fails only if it fails 2 of 3 runs.

This branch has not been deployed

No deployments
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