feat: fill frame for fixed aspect ratios and full-width camera - #2382
YoavLevavi wants to merge 2 commits into
Conversation
With a fixed aspect ratio (e.g. 9:16), Fill Frame scales the recording to cover the whole output instead of letterboxing it. The screen follows a smoothed cursor (kept inside an edge margin) or rests at a fixed Screen Position, and zooms still pan to their own focus. Default / Hide Camera scenes can pin their own screen position, eased over the scene's transitions. The camera size limit rises to 100% so a camera can span the full output width, and camera bubbles stay inside the output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| fn fill_frame_active(project: &ProjectConfiguration) -> bool { | ||
| project.background.fill_frame | ||
| && project.aspect_ratio.is_some() | ||
| && FrameConfiguration::active_style(project.background.frame.as_ref()) == FrameStyle::None |
There was a problem hiding this comment.
Fill Frame silently stays off When a fixed-aspect project uses a macOS, Windows, Browser, or MacBook frame, the editor offers Fill Frame and locks screen dragging, but this condition prevents the renderer from applying Fill Frame. The recording remains fitted instead of filling the output, and the user cannot reposition it by dragging.
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/rendering/src/lib.rs
Line: 2545
Comment:
**Fill Frame silently stays off** When a fixed-aspect project uses a macOS, Windows, Browser, or MacBook frame, the editor offers Fill Frame and locks screen dragging, but this condition prevents the renderer from applying Fill Frame. The recording remains fitted instead of filling the output, and the user cannot reposition it by dragging.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
Fixed in f64f45f. Fill Frame is deliberately skipped with a decorative frame, because the window/MacBook chrome needs the fitted display. The editor now matches that: the Fill Frame toggle, Follow Cursor, the Screen Position pads and the screen-drag lock only appear when no frame style is active. Adding a frame shows the normal fitted, draggable layout.
| onClick={() => | ||
| setProject( | ||
| "timeline", | ||
| "sceneSegments", | ||
| props.segmentIndex, | ||
| "splitLayout", | ||
| null, | ||
| ) |
There was a problem hiding this comment.
Removing pin deletes layout settings If a user changes a configured split or floating scene to Default or Hide Camera, then clicks “Follow the default behavior,” this action deletes the entire
splitLayout, not just its screen-position pin. Switching back loses the saved screen zoom, camera zoom, and camera position.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/routes/editor/ConfigSidebar.tsx
Line: 5256-5263
Comment:
**Removing pin deletes layout settings** If a user changes a configured split or floating scene to Default or Hide Camera, then clicks “Follow the default behavior,” this action deletes the entire `splitLayout`, not just its screen-position pin. Switching back loses the saved screen zoom, camera zoom, and camera position.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
Fixed in f64f45f. The per-scene pin now has its own optional field, SceneSegment.fillFramePosition (serde default, skipped when None). It no longer reuses splitLayout.screenPosition. "Follow the default behavior" only clears that field, so a scene's split or floating zoom and positions survive switching modes. The renderer test now sets a split layout alongside the pin to cover this.
| let scene = scenes.iter().find(|scene| { | ||
| matches!(scene.mode, SceneMode::Default | SceneMode::HideCamera) | ||
| && time >= scene.start | ||
| && time < scene.end | ||
| })?; |
There was a problem hiding this comment.
Scene pin starts late A scene’s transition-in begins before
scene.start, but this lookup does not select its pin until scene.start. The screen stays at its default framing through the first part of the transition, then continues panning after the scene has started.
Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/rendering/src/lib.rs
Line: 2593-2597
Comment:
**Scene pin starts late** A scene’s transition-in begins before `scene.start`, but this lookup does not select its pin until `scene.start`. The screen stays at its default framing through the first part of the transition, then continues panning after the scene has started.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
Fixed in f64f45f. The pin is selected over [start - transition_in, end + transition_out), the same window scene transitions use elsewhere, and eases in before start and out after end. It reaches full weight exactly at start. The test checks partial weight at 1.75 s (entering), full at 2.0 s, and partial at 6.25 s (leaving).
| <PositionPad | ||
| value={() => split().screenPosition} | ||
| onChange={(pos) => updateSplit({ screenPosition: pos })} |
There was a problem hiding this comment.
Position pad shows wrong focus Before a scene has its own pin, this pad shows the split-layout default of center. When Follow Cursor is off and the Background screen position is elsewhere, the pad misrepresents the scene’s current framing; using it can then create a pin at a different position.
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/routes/editor/ConfigSidebar.tsx
Line: 5249-5251
Comment:
**Position pad shows wrong focus** Before a scene has its own pin, this pad shows the split-layout default of center. When Follow Cursor is off and the Background screen position is elsewhere, the pad misrepresents the scene’s current framing; using it can then create a pin at a different position.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
Fixed in f64f45f. Before a scene has its own pin, the pad shows the scene's effective framing: the Background Screen Position when Follow Cursor is off, otherwise center. Dragging it starts from what's on screen.
- hide Fill Frame while a decorative frame is active, where it can't apply - store the per-scene pin in its own fillFramePosition field so removing it keeps the scene's split layout - ease the pin across the full transition window around the scene edges - show the scene's effective framing in its position pad Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What
A Fill Frame mode for fixed aspect ratios, aimed at vertical (9:16) edits of landscape screen recordings, similar to Screen Studio's vertical mode.
While Fill Frame is on, the screen can't be dragged in the preview; the tooltip explains why and offers to turn Fill Frame off. The notch restore is skipped in Fill Frame, because the display no longer maps 1:1 to the capture edges.
Implementation
BackgroundConfigurationgainsfill_frame,fill_frame_follow_cursor(defaulttrue) andfill_frame_position(default center). All use serde defaults, so existing projects render exactly as before.crates/rendering/src/lib.rs):fill_frame_boundscomputes the display rect: cover scale × zoom amount, resting focus, zoom blend, and the cursor margin.fill_frame_cursor_focusaverages the cursor over a trailing 1.2 s window. It depends only on time, not on frame-to-frame state, so preview and export frame identically.fill_frame_scene_overrideprovides the per-scene pin with smoothstep easing.splitLayout.screenPosition, so no new timeline schema is needed.Testing
cap-rendering: new tests for:cap-project: legacy configs default to Follow Cursor and a centered position.cargo clippy -p cap-project -p cap-rendering -p cap-desktop --all-targets -D warningsis clean;cap-renderingandcap-projecttests pass. Desktop Vitest suite passes; Biome andtsc --noEmitare clean.🤖 Generated with Claude Code
The PR is not ready to merge because Fill Frame can appear enabled without rendering, and removing a scene pin can discard saved layout adjustments.
Findings
Fix with agent prompt
Summary
This PR adds fixed-aspect Fill Frame framing with cursor following and per-scene pins, raises the camera size limit, and updates the desktop controls and project bindings.
Reviews (1) · Last reviewed commit: "feat: fill frame for fixed aspect ratios..."