Skip to content

fix(desktop-gpui): add and edit clip transitions in the editor - #3490

Open
richiemcilroy wants to merge 5 commits into
mainfrom
fix/gpui-clip-transitions
Open

richiemcilroy wants to merge 5 commits into
mainfrom
fix/gpui-clip-transitions

Conversation

@richiemcilroy

@richiemcilroy richiemcilroy commented Oct 27, 2026 •

Copy link
Copy Markdown
Member

Users on 0.6.1 can't add a transition between clips in the GPUI editor (reported on Discord: "How to set transition effect"). The Tauri editor had a "+" on each clip boundary and a transition popover; the GPUI port kept the transition model, rendering and removal but never ported a way to add or change one, and drew nothing on the timeline.

  • editor_clips::set_clip_transition: puts a crossfade or fade-through-black on a clip's leading boundary, clamped to half the shorter clip (clampTransitionDuration), and ripples every other track by the change in overlap, the same ripple removal already used (now shared).
  • Clip menu (right-click a clip, or its cog): a Transition section on every clip after the first, with None / Crossfade / Fade and 0.25 / 0.5 / 1 / 1.5 s lengths (longer ones are left out when the clips are too short). Edits go through project_changed and note_edit, so they save and undo like the other clip settings.
  • Timeline: the transition shows as an accent band over the overlap at the clip's leading edge.

Not ported: the boundary "+" button and dragging the band to resize. The "+" shares its pixels with the clip's trim handle, so it needs press routing by height that the timeline does not have yet.

Tests: adding overlaps the clips and ripples a zoom on the next clip by the overlap; lengthening ripples by the difference and changes the kind; removing restores everything; durations clamp to half the shorter clip and the minimum; the first clip and too-short clips take none.

RetriggerView in GreptileConfidence Score: 4/5

Fix the effect movement on transition removal before merging.

Findings

  1. P1 Removing transitions moves unrelated effects ▶
Fix with agent prompt
### Issue 1
apps/desktop-gpui/src/editor_clips.rs:334-338
With two 10-second clips and a zoom at [9, 9.8], adding a 1-second transition leaves the zoom unchanged. Removing it then makes `incoming` equal 9, so `boundary_for` treats that zoom as attached to the incoming clip and moves it to [10, 10.8]. Adding and removing a transition therefore changes an existing effect's timing.

Do not infer attachment from matching start times alone. Add a round-trip test where an existing effect starts at the new overlap edge.

---

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

Summary

Adds transition controls to the GPUI clip menu and draws overlap bands on the timeline.

  • Clip menus can add, adjust, and remove transitions between clips.
  • The timeline marks each incoming clip transition with an accent band.

Reviews (2) · Last reviewed commit: "Merge remote-tracking branch 'origin/fix..." · Reviewed by Greptile

@vercel

vercel Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
cap-status Ready Ready Preview Oct 27, 2026 11:15pm UTC

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Capy found 1 potential issue (1 medium).

View 3 other findings in Capy.

Open in Capy

Comment thread apps/desktop-gpui/src/editor_clips.rs Outdated
let old = timeline
.effective_transition(segment_index)
.map_or(0.0, |transition| transition.duration);
let boundary = transition_boundary(timeline, segment_index, old);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Transition resizing leaves boundary-adjacent overlays behind

Medium Severity

With two 10-second clips and a zoom at 10–12 seconds, adding a 0.5-second transition moves the zoom to 9.5–11.5. Lengthening that transition to one second still computes a ripple boundary of 10 (offset 9.5 plus old overlap 0.5), so ripple_track leaves the zoom's start at 9.5 and only shortens its end to 11, although the incoming clip now starts at 9. Removing the transition likewise fails to restore the original start. This silently changes overlay alignment and duration through the new menu. Use a consistent boundary/remap that follows already-shifted incoming-clip content during resizing and removal, and cover annotations starting at the clip boundary in the round-trip test.

Open in Capy

Comment thread apps/desktop-gpui/src/editor_clips.rs Outdated
let old = timeline
.effective_transition(segment_index)
.map_or(0.0, |transition| transition.duration);
let boundary = transition_boundary(timeline, segment_index, old);

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 Effects lose their timing

With two 10-second clips and a zoom at [10, 12], adding a 0.5-second transition moves the zoom to [9.5, 11.5]. Changing the transition to 1 second still ripples at 10, so only the zoom's end moves. It becomes [9.5, 11] instead of [9, 11]. Removing the transition then leaves [9.5, 12], not the original timing.

Use the current incoming clip boundary when changing an existing overlap, and add a test with an effect starting at the clip boundary.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/editor_clips.rs
Line: 247

Comment:
**Effects lose their timing**

With two 10-second clips and a zoom at [10, 12], adding a 0.5-second transition moves the zoom to [9.5, 11.5]. Changing the transition to 1 second still ripples at 10, so only the zoom's end moves. It becomes [9.5, 11] instead of [9, 11]. Removing the transition then leaves [9.5, 12], not the original timing.

Use the current incoming clip boundary when changing an existing overlap, and add a test with an effect starting at the clip boundary.

---

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

Comment on lines +1724 to +1726
transition_in: timeline.effective_transition(index).map(|transition| {
(
transition.duration,

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 Transition band ends too early

Fullscreen text holds stretch the clip boxes, but the transition band uses only transition.duration. With two 10-second clips, a 0.5-second transition, and a hold at [9.75, 11.75], the boxes overlap from 9.5 to 12 seconds while the band ends at 10. The band therefore understates the visible overlap.

Compute its length from the overlap's output-time endpoints so the band includes holds too.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/editor_timeline.rs
Line: 1724-1726

Comment:
**Transition band ends too early**

Fullscreen text holds stretch the clip boxes, but the transition band uses only `transition.duration`. With two 10-second clips, a 0.5-second transition, and a hold at [9.75, 11.75], the boxes overlap from 9.5 to 12 seconds while the band ends at 10. The band therefore understates the visible overlap.

Compute its length from the overlap's output-time endpoints so the band includes holds too.

---

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

Comment thread apps/desktop-gpui/src/editor_window.rs Outdated
let merge_next =
edits::clip_merge_blocker(&timeline.segments, index, edits::ClipMergeDirection::Next);
let can_delete = timeline.segments.len() > 1;
// The transition into this clip from the one before it.

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 Comments repeat the code

This new comment only repeats the next line. The repository guide explicitly bans comments that narrate the code or restate names and types. Remove it and the similar narration above CLIP_TRANSITION_DURATIONS and the transition-band rendering block. Keep comments that explain non-obvious timing rules or trade-offs. This repository requirement must be satisfied before merging.

Context Used: AGENTS.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/editor_window.rs
Line: 8563

Comment:
**Comments repeat the code**

This new comment only repeats the next line. The repository guide explicitly bans comments that narrate the code or restate names and types. Remove it and the similar narration above `CLIP_TRANSITION_DURATIONS` and the transition-band rendering block. Keep comments that explain non-obvious timing rules or trade-offs. This repository requirement must be satisfied before merging.

**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!

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Capy found no issues.

View 1 other finding in Capy.

Open in Capy

@richiemcilroy

Copy link
Copy Markdown
Member Author

@greptileai

Comment thread apps/desktop-gpui/src/editor_clips.rs Outdated
Comment on lines +334 to +338
fn boundary_for(self, start: f64) -> f64 {
if (start - self.incoming).abs() < 1e-6 {
start
} else {
self.boundary

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 Removing transitions moves unrelated effects

With two 10-second clips and a zoom at [9, 9.8], adding a 1-second transition leaves the zoom unchanged. Removing it then makes incoming equal 9, so boundary_for treats that zoom as attached to the incoming clip and moves it to [10, 10.8]. Adding and removing a transition therefore changes an existing effect's timing.

Do not infer attachment from matching start times alone. Add a round-trip test where an existing effect starts at the new overlap edge.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop-gpui/src/editor_clips.rs
Line: 334-338

Comment:
**Removing transitions moves unrelated effects**

With two 10-second clips and a zoom at [9, 9.8], adding a 1-second transition leaves the zoom unchanged. Removing it then makes `incoming` equal 9, so `boundary_for` treats that zoom as attached to the incoming clip and moves it to [10, 10.8]. Adding and removing a transition therefore changes an existing effect's timing.

Do not infer attachment from matching start times alone. Add a round-trip test where an existing effect starts at the new overlap edge.

---

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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Fixed in f3725d1: an effect now goes with the incoming clip only when it starts with that clip and runs past the outgoing clip's end, so [9, 9.8] stays put through add and remove (new test an_effect_ending_inside_the_new_overlap_keeps_its_timing). The project does not record which clip an effect belongs to, so one that starts with the incoming clip and ends inside the overlap could belong to either; it is left with the outgoing clip, as the single-boundary ripple does.

@capy-ai capy-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Capy found no issues.

View 1 other finding in Capy.

Open in Capy

This branch was successfully deployed

2 active deployments
Preview – cap-web — f3725d18 Deployed Oct 27, 2026 by vercel[bot]
Preview – cap-status — f3725d18 Deployed Oct 27, 2026 by vercel[bot]
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