Skip to content

fix(editor): refresh project snapshot on watch receiver updates to invalidate legacy zoom after split (#2230) - #3925

Closed
cocvn157 wants to merge 2 commits into
CapSoftware:mainfrom
cocvn157:fix/preview-zoom-area-update-after-split-2230
Closed

cocvn157 wants to merge 2 commits into
CapSoftware:mainfrom
cocvn157:fix/preview-zoom-area-update-after-split-2230

Conversation

@cocvn157

@cocvn157 cocvn157 commented Nov 7, 2026 •

Copy link
Copy Markdown

Fixes #2230
/claim #2230

Context and Problem

When a user splits a zoom segment into two and then adjusts the new split zoom segment to a new area (manual coordinates, mode, or zoom amount), the editor preview continued zooming into the old area from before the split.

Root Cause

In crates/editor/src/editor_instance.rs, refresh_project_snapshot updates the preview renderer's cached project snapshot when project configuration changes arrive over the project_rx: watch::Receiver<ProjectConfiguration> watch channel.

Previously, refresh_project_snapshot called let project = project_rx.borrow_and_update() and then checked if !project.has_changed() { return None; }. Because project was the watch::Ref newly returned by borrow_and_update(), calling has_changed() on the reference checked whether another write had arrived after that exact borrow, which evaluates to false in sequential execution. As a result:

  • refresh_project_snapshot consistently returned None instead of yielding the previous and updated project snapshot.
  • EditorInstance::spawn_preview_renderer never triggered zoom_timelines.clear() or updated project.
  • The preview renderer held onto stale ZoomTransformTimeline state computed prior to the split, rendering frames with the legacy zoom target instead of the newly adjusted zoom area.

Changes

  1. Updated refresh_project_snapshot in crates/editor/src/editor_instance.rs to check if !project_rx.has_changed().unwrap_or(false) { return None; } before calling borrow_and_update(), matching the receiver check pattern used across playback and preview tasks.
  2. When changes arrive, refresh_project_snapshot now correctly advances the receiver, replaces the snapshot with the updated config, and returns the previous snapshot.
  3. In spawn_preview_renderer, !ZoomTransformTimeline::project_inputs_match(&previous, &project, screen_size) correctly evaluates to true on zoom splits and adjustments, clearing cached zoom timelines and precomputing with the new target parameters.
  4. Added unit test preview_project_snapshot_detects_zoom_split_and_area_adjustment verifying that splitting a zoom and modifying coordinates triggers snapshot updates and signals project input changes.

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge, with both previous findings fixed and no new actionable issues found.

Summary

Updates the preview's saved project settings so zoom edits clear the old zoom timelines.

  • The preview refreshes zoom settings after project edits.

Tests were not run.

Reviews (3) · Last reviewed commit: "test(editor): construct TimelineConfigur..." · Reviewed by Greptile

@vercel

vercel Bot commented Nov 7, 2026

Copy link
Copy Markdown
Contributor

@cocvn157 is attempting to deploy a commit to the Cap Software Inc Team on Vercel.

A member of the Team first needs to authorize it.

Comment thread crates/editor/src/editor_instance.rs Outdated
let mut initial_config = ProjectConfiguration::default();
initial_config.timeline = Some(TimelineConfiguration {
zoom_segments: vec![initial_zoom],
..Default::default()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Editor tests cannot compile

The new test uses ..Default::default(), but TimelineConfiguration does not implement Default. This prevents the editor's tests from compiling. Fill in the remaining fields explicitly or build the fixture with the existing JSON approach.

Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/editor/src/editor_instance.rs
Line: 2511

Comment:
**Editor tests cannot compile**

The new test uses `..Default::default()`, but `TimelineConfiguration` does not implement `Default`. This prevents the editor's tests from compiling. Fill in the remaining fields explicitly or build the fixture with the existing JSON approach.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Comment thread crates/editor/src/editor_instance.rs Outdated
let mut snapshot = Arc::new(project_rx.borrow_and_update().clone());
let initial = Arc::clone(&snapshot);

// User splits zoom into two, then adjusts the new split zoom to a new area (x: 0.75, y: 0.75)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Comment repeats the test setup

The added comment narrates the split and coordinate values already shown by the test. AGENTS.md explicitly bans comments that narrate code or describe the current change. Remove it before merging to satisfy that requirement; the test name and fixture already explain the case.

Context Used: AGENTS.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/editor/src/editor_instance.rs
Line: 2518

Comment:
**Comment repeats the test setup**

The added comment narrates the split and coordinate values already shown by the test. `AGENTS.md` explicitly bans comments that narrate code or describe the current change. Remove it before merging to satisfy that requirement; the test name and fixture already explain the case.

**Context Used:** AGENTS.md ([source](https://github.com/capsoftware/cap/blob/main/AGENTS.md))

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@richiemcilroy

Copy link
Copy Markdown
Member

Thanks @cocvn157, this looks like a useful change.

Before we can merge it:

  • Greptile is at 4/5 on the latest commit; it needs 5/5. Its open points:
    • The new test uses ..Default::default() on TimelineConfiguration, which has no Default, so the editor tests don't compile.
    • The comment in the new test narrates the setup; please remove it.

Once those are sorted, request a re-review from Greptile.

@cocvn157

cocvn157 commented Nov 8, 2026 •

Copy link
Copy Markdown
Author

Thanks @richiemcilroy! Updated in 0433190 to construct TimelineConfiguration with explicit fields and removed the test setup comment, and retriggered Greptile.

@richiemcilroy

Copy link
Copy Markdown
Member

Thanks so much for this, @cocvn157! On main, refresh_project_snapshot already returns the previous snapshot after a change: the Ref from borrow_and_update() reports has_changed() for the version it just marked seen, and the existing preview_project_snapshot_refreshes_once_to_the_latest_project test covers that in CI. So this change doesn't alter behaviour, and whatever still causes #2230 must be somewhere else in the preview path. Closing this one, but we really appreciate the time you put into it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

User has legacy zoom view after splitting zoom areas.

2 participants