Skip to content

fix(editor): clamp captions and hide keyboard segments past trim boundary#1726

Open
MinitJain wants to merge 5 commits intoCapSoftware:mainfrom
MinitJain:fix/captions-trim-overflow
Open

fix(editor): clamp captions and hide keyboard segments past trim boundary#1726
MinitJain wants to merge 5 commits intoCapSoftware:mainfrom
MinitJain:fix/captions-trim-overflow

Conversation

@MinitJain
Copy link
Copy Markdown
Contributor

@MinitJain MinitJain commented Apr 10, 2026

Summary

  • Caption segments that start before the trim point but extend past it are now visually clamped at the trim boundary, instead of overflowing into the empty region beyond the clip
  • Keyboard segments that start at or after the trim boundary are filtered out entirely (since they are point-in-time events with no content before the trim point)

How it works

CaptionsTrack: SegmentRoot receives a clamped end value — Math.min(segment.end, totalDuration()) — so the rendered bar width stops at the trim point. The underlying segment data is unchanged, so drag interactions are unaffected.

KeyboardTrack: Segments are filtered with s.start < totalDuration() so keypresses that occur after the trim point are not rendered.

Test plan

  • Open a recording with captions in the editor
  • Trim the right side of the clip so the trim point cuts through a caption segment
  • Verify the caption bar stops at the trim boundary instead of extending past it
  • Trim past a keyboard segment — verify it disappears
  • Verify dragging and splitting captions still works correctly on untrimmed segments

Closes #1725
Related to #1689

🤖 Generated with Claude Code

Greptile Summary

This PR visually clamps caption segments at the trim boundary and hides keyboard/caption segments that start at or after the trim point, fixing overflow into the empty region beyond the clip. One defect was found in the split-mode interaction for CaptionsTrack.

  • P1 – wrong split time on clamped captions: segmentWidth() reads the original unclamped segment.end, but SegmentRoot renders the element using the clamped width. Clicks in the visual element are scaled against the wrong duration, so splits land at incorrect positions — up to a factor of 2× off for segments that span the trim boundary.

Confidence Score: 4/5

Safe to merge after fixing the split-time calculation for visually clamped caption segments.

One P1 defect: the segmentWidth local in CaptionsTrack uses the original unclamped end while SegmentRoot renders the clamped width, causing split-mode clicks to map to wrong positions on segments that cross the trim boundary. The fix is a one-liner. All other changes are correct.

apps/desktop/src/routes/editor/Timeline/CaptionsTrack.tsx — line 164, segmentWidth definition used in split handler.

Important Files Changed

Filename Overview
apps/desktop/src/routes/editor/Timeline/CaptionsTrack.tsx Adds visual clamping of caption segments at the trim boundary and filters out segments starting past trim. The segmentWidth local used in split-mode click handling still reads the original unclamped segment.end, producing incorrect split times for visually clamped segments.
apps/desktop/src/routes/editor/Timeline/KeyboardTrack.tsx Filters keyboard segments starting at or after the trim boundary. Segments that start before but end after the trim are shown with their full unclamped width, potentially overflowing past the trim visual boundary.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[captionSegments / keyboardSegments] -->|filter: s.start < totalDuration| B[Filtered visible segments]
    B --> C{Segment crosses trim boundary?}
    C -->|Yes - CaptionsTrack| D["SegmentRoot receives clamped end\n= Math.min(end, totalDuration)"]
    C -->|No| E[SegmentRoot receives original segment]
    C -->|Yes - KeyboardTrack| F["SegmentRoot receives original segment\n⚠️ may overflow trim visually"]
    D --> G[Visual width = clamped duration]
    E --> H[Visual width = full duration]
    G --> I{Split mode click?}
    I -->|segmentWidth uses original end| J[❌ Wrong split time calculated]
    I -->|segmentWidth uses clamped end| K[✅ Correct split time]
Loading

Comments Outside Diff (1)

  1. apps/desktop/src/routes/editor/Timeline/CaptionsTrack.tsx, line 164-184 (link)

    P1 Incorrect split time for visually clamped segments

    segmentWidth() uses the original unclamped segment.end, but rect.width reflects the clamped visual width passed to SegmentRoot. For a segment spanning, say, seconds 5–15 with totalDuration() = 10, rect.width corresponds to 5 s of visual space while segmentWidth() returns 10 — so clicking at 50% of the visual element produces splitTime = 5, which maps to the trim boundary rather than the midpoint of the visible portion. Any click past the visual midpoint maps to a split time beyond the trim.

    Fix segmentWidth to reflect the rendered width:

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/desktop/src/routes/editor/Timeline/CaptionsTrack.tsx
    Line: 164-184
    
    Comment:
    **Incorrect split time for visually clamped segments**
    
    `segmentWidth()` uses the original unclamped `segment.end`, but `rect.width` reflects the clamped visual width passed to `SegmentRoot`. For a segment spanning, say, seconds 5–15 with `totalDuration() = 10`, `rect.width` corresponds to 5 s of visual space while `segmentWidth()` returns 10 — so clicking at 50% of the visual element produces `splitTime = 5`, which maps to the trim boundary rather than the midpoint of the visible portion. Any click past the visual midpoint maps to a split time beyond the trim.
    
    Fix `segmentWidth` to reflect the rendered width:
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
This is a comment left during a code review.
Path: apps/desktop/src/routes/editor/Timeline/CaptionsTrack.tsx
Line: 164-184

Comment:
**Incorrect split time for visually clamped segments**

`segmentWidth()` uses the original unclamped `segment.end`, but `rect.width` reflects the clamped visual width passed to `SegmentRoot`. For a segment spanning, say, seconds 5–15 with `totalDuration() = 10`, `rect.width` corresponds to 5 s of visual space while `segmentWidth()` returns 10 — so clicking at 50% of the visual element produces `splitTime = 5`, which maps to the trim boundary rather than the midpoint of the visible portion. Any click past the visual midpoint maps to a split time beyond the trim.

Fix `segmentWidth` to reflect the rendered width:

```suggestion
					const segmentWidth = () => Math.min(segment.end, totalDuration()) - segment.start;
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: apps/desktop/src/routes/editor/Timeline/KeyboardTrack.tsx
Line: 35-39

Comment:
**Keyboard segments crossing the trim boundary not visually clamped**

`KeyboardTrack` filters out segments where `start >= totalDuration()`, but keyboard segments whose `start < totalDuration()` and `end > totalDuration()` are rendered with their full unclamped width via the `segment={segment}` prop on `SegmentRoot`. This means they can visually overflow past the trim boundary, inconsistent with how `CaptionsTrack` clamps its segments. If a keyboard segment straddles the trim point, consider passing a clamped `end` to `SegmentRoot` the same way captions does:

```
segment={{ start: segment.start, end: Math.min(segment.end, totalDuration()) }}
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix(editor): clamp captions and hide key..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

(5/5) You can turn off certain types of comments like style here!

…dary

Closes CapSoftware#1725
Related to CapSoftware#1689

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment on lines +35 to +39
const keyboardSegments = createMemo(() =>
(project.timeline?.keyboardSegments ?? []).filter(
(s) => s.start < totalDuration(),
),
);
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 Keyboard segments crossing the trim boundary not visually clamped

KeyboardTrack filters out segments where start >= totalDuration(), but keyboard segments whose start < totalDuration() and end > totalDuration() are rendered with their full unclamped width via the segment={segment} prop on SegmentRoot. This means they can visually overflow past the trim boundary, inconsistent with how CaptionsTrack clamps its segments. If a keyboard segment straddles the trim point, consider passing a clamped end to SegmentRoot the same way captions does:

segment={{ start: segment.start, end: Math.min(segment.end, totalDuration()) }}
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/routes/editor/Timeline/KeyboardTrack.tsx
Line: 35-39

Comment:
**Keyboard segments crossing the trim boundary not visually clamped**

`KeyboardTrack` filters out segments where `start >= totalDuration()`, but keyboard segments whose `start < totalDuration()` and `end > totalDuration()` are rendered with their full unclamped width via the `segment={segment}` prop on `SegmentRoot`. This means they can visually overflow past the trim boundary, inconsistent with how `CaptionsTrack` clamps its segments. If a keyboard segment straddles the trim point, consider passing a clamped `end` to `SegmentRoot` the same way captions does:

```
segment={{ start: segment.start, end: Math.min(segment.end, totalDuration()) }}
```

How can I resolve this? If you propose a fix, please make it concise.

MinitJain and others added 2 commits April 10, 2026 13:25
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@MinitJain
Copy link
Copy Markdown
Contributor Author

Hey @richiemcilroy

fixed captions and keyboard segments overflowing past the trim boundary.
All CI checks passing ✅,
no conflicts.
Would love your review when you get a chance!

MinitJain and others added 2 commits April 12, 2026 00:31
…cessibility in debug builds

On macOS Sequoia, CGPreflightScreenCaptureAccess() always returns false
for ad-hoc signed or unsigned binaries regardless of System Settings,
making it impossible to test locally without a Developer ID certificate.

Adding a debug_assertions early return for ScreenRecording and
Accessibility allows contributors to run and test the app locally
without being blocked by the permissions screen.

Camera and microphone are unaffected as they prompt correctly without
a signed binary.

Fixes CapSoftware#1722

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…board segments

segmentWidth used the original unclamped segment.end while SegmentRoot
rendered the clamped visual width, causing split clicks to land at wrong
positions for segments crossing the trim boundary.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@MinitJain
Copy link
Copy Markdown
Contributor Author

The Clippy failures are not caused by this PR. The error is in crates/recording/src/memory_profiling.rs:61 which is a pre-existing needless_return violation in upstream main. This file does not exist in our branch at all. The CI runs on the simulated merge commit which surfaces the upstream issue. All checks related to our actual changes (Biome format, Biome lint, Typecheck, Cargo format) are passing.

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.

[Bug] Captions and keyboard segments overflow past trim boundary in timeline editor

1 participant