Skip to content

feat: Add webcam size with slider#345

Open
GarryLaly wants to merge 3 commits intosiddharthvaddem:mainfrom
GarryLaly:feature/webcam-resize-slider
Open

feat: Add webcam size with slider#345
GarryLaly wants to merge 3 commits intosiddharthvaddem:mainfrom
GarryLaly:feature/webcam-resize-slider

Conversation

@GarryLaly
Copy link
Copy Markdown

@GarryLaly GarryLaly commented Apr 5, 2026

Pull Request Template

Description

Continues and improves the webcam resize feature from PR #289. Merges the original work with main, resolves all conflicts (including new webcamMaskShape feature), fixes broken type-checking and missing wiring, and replaces the small/medium/large preset dropdown with a continuous percentage slider (10%–50%) for finer control over webcam overlay size.

Motivation

PR #289 introduced webcam size presets but had several issues:

  • MAX_STAGE_FRACTION was referenced at module scope before being defined, causing TypeScript compilation errors
  • webcamSizePreset was never wired through the rendering pipeline (canvas preview, export, project persistence), so changing the preset had no visible effect
  • The fixed small/medium/large presets were too coarse — users need finer control over webcam sizing
  • Webcam size was inconsistent between landscape (16:9) and portrait (9:16) aspect ratios due to using canvasWidth/canvasHeight independently instead of a unified reference dimension

Type of Change

  • New Feature
  • Bug Fix
  • Refactor / Code Cleanup
  • Documentation Update
  • Other (please specify)

Related Issue(s)

Screenshots / Video

Screenshot:

Screenshot 2026-04-05 at 20 04 15

Video:

Screen.Recording.2026-04-05.at.20.05.27.mov

Testing

  1. Open the video editor with a webcam recording
  2. In the Layout accordion on the settings panel, verify the Webcam Size slider appears (range 10%–50%)
  3. Drag the slider — the webcam overlay on the canvas should resize in real-time
  4. Switch between 16:9 and 9:16 aspect ratios — verify the webcam size is visually consistent
  5. Export as MP4 and GIF — verify the exported video reflects the chosen webcam size
  6. Save and reload a project — verify the webcam size persists correctly
  7. Load an older project (without webcamSizePreset) — verify it defaults to 25%
  8. Run tests: npx vitest run --environment node src/lib/compositeLayout.test.ts — all 9 tests should pass

Checklist

  • I have performed a self-review of my code.
  • I have added any necessary screenshots or videos.
  • I have linked related issue(s) and updated the changelog if applicable.

Thank you for contributing!

Summary by CodeRabbit

  • New Features

    • Adjustable webcam size control added to picture-in-picture settings (10%–50%, clamped), preserved in project state, applied during playback and exports.
  • Tests

    • Layout tests updated to verify size monotonicity, clamping behavior, and layout consistency across aspect ratios.
  • Localization

    • Added "Webcam Size" label in English, Spanish, and Simplified Chinese.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 5, 2026

📝 Walkthrough

Walkthrough

This PR adds a webcam sizing preset feature: a numeric webcamSizePreset (default 25) threaded through UI, editor state/history, composite layout computation, exporters/frame rendering, project persistence, and i18n; SettingsPanel exposes a slider for picture-in-picture webcam sizing and layout logic uses a geometric-mean reference for scaling.

Changes

Cohort / File(s) Summary
Type Definitions
src/components/video-editor/types.ts, src/lib/compositeLayout.ts
Added WebcamSizePreset type and DEFAULT_WEBCAM_SIZE_PRESET (25); computeCompositeLayout now accepts optional webcamSizePreset.
State & History
src/hooks/useEditorHistory.ts, src/components/video-editor/projectPersistence.ts
Added webcamSizePreset to EditorState/ProjectEditorState, initialized in INITIAL_EDITOR_STATE, and normalized/clamped to 10–50 on load.
UI Components
src/components/video-editor/SettingsPanel.tsx, src/components/video-editor/VideoEditor.tsx
SettingsPanel props extended with webcamSizePreset, onWebcamSizePresetChange, onWebcamSizePresetCommit; slider UI rendered for picture-in-picture. VideoEditor wires the state and callbacks through.
Playback & Layout
src/components/video-editor/VideoPlayback.tsx, src/components/video-editor/videoPlayback/layoutUtils.ts
VideoPlayback accepts webcamSizePreset and forwards it to layout utilities; layoutVideoContent signature updated to include optional webcamSizePreset.
Composite Layout Logic & Tests
src/lib/compositeLayout.ts, src/lib/compositeLayout.test.ts
Replaced fixed overlay sizing with webcamSizeToFraction (clamped 10–50 → 0.10–0.50) and referenceDim = sqrt(w*h) for overlay bounds; tests updated to assert monotonic sizing and clamping behavior.
Export Pipeline
src/lib/exporter/frameRenderer.ts, src/lib/exporter/gifExporter.ts, src/lib/exporter/videoExporter.ts
Exporter configs and FrameRenderer extended to accept/propagate webcamSizePreset so rendering/export respects the preset.
I18n
src/i18n/locales/en/settings.json, src/i18n/locales/es/settings.json, src/i18n/locales/zh-CN/settings.json
Added layout.webcamSize translations: English "Webcam Size", Spanish "Tamaño de cámara", Chinese "摄像头大小".

Sequence Diagram

sequenceDiagram
    participant User
    participant SettingsPanel
    participant VideoEditor as VideoEditor (State)
    participant VideoPlayback
    participant LayoutUtils
    participant CompositeLayout

    User->>SettingsPanel: Drag webcam size slider
    SettingsPanel->>SettingsPanel: onWebcamSizePresetChange(pct)
    SettingsPanel->>VideoEditor: onWebcamSizePresetChange callback
    VideoEditor->>VideoEditor: Update editorState.webcamSizePreset
    VideoEditor->>VideoPlayback: Pass webcamSizePreset prop
    VideoPlayback->>LayoutUtils: layoutVideoContent(params including webcamSizePreset)
    LayoutUtils->>CompositeLayout: computeCompositeLayout(webcamSizePreset)
    CompositeLayout->>CompositeLayout: compute referenceDim (sqrt) & clamp fraction
    CompositeLayout->>VideoPlayback: Return composite layout
    VideoPlayback->>User: Render resized webcam overlay
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • siddharthvaddem

Poem

🐰 A slider born for webcam size,
Ten to fifty, watch it rise!
Picture-in-picture, snug and bright,
The rabbit tunes your frame just right. 📹✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: Add webcam size with slider' clearly and concisely describes the main change: introducing a slider control for adjusting webcam size.
Description check ✅ Passed The PR description follows the template with all required sections: Description, Motivation, Type of Change, Related Issues, Screenshots/Video, Testing, and Checklist all completed with substantive content.
Linked Issues check ✅ Passed The PR fully addresses issue #285 by implementing a resizable webcam overlay control with a slider (10%-50%), enabling users to adjust webcam size particularly for 9:16 portrait format recordings.
Out of Scope Changes check ✅ Passed All changes are in scope: webcam sizing feature implementation, bug fixes (TypeScript errors, missing wiring), i18n translations for the new feature, and tests for new layout logic.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/lib/compositeLayout.test.ts (1)

131-150: Rename this test or assert the centering contract again.

The title still says the stack is centered, but the assertions only verify full-canvas placement and never use maxContentSize. As written, this would stay green even if centering was removed accidentally.

🧪 Suggested adjustment
-it("centers the combined screen and webcam stack in vertical stack mode", () => {
+it("fills the canvas in vertical stack mode", () => {

If centering is still the intended contract, keep the current name and restore assertions that actually use maxContentSize.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/compositeLayout.test.ts` around lines 131 - 150, The test "centers
the combined screen and webcam stack in vertical stack mode" currently verifies
full-canvas placement but never exercises maxContentSize, so either rename the
test to reflect full-canvas behavior or restore assertions to verify centering
using maxContentSize; update the test around computeCompositeLayout to assert
that the combined content width/height respects maxContentSize and is centered
within canvas (e.g., check that (canvas.width - maxContentSize.width)/2 equals
the left x offset of the stacked group and similarly for vertical offsets), or
change the test name to something like "fills canvas in vertical-stack mode when
maxContentSize >= canvas" if you intend to keep the existing assertions.
src/components/video-editor/types.ts (1)

6-9: Export the slider bounds from the same source as the default.

10 and 50 are now duplicated in src/lib/compositeLayout.ts and src/components/video-editor/projectPersistence.ts, while only 25 is shared here. If the range changes later, preview, export, persistence, and tests can drift silently.

♻️ Suggested cleanup
 /** Webcam size as a percentage of the canvas reference dimension (10–50). */
 export type WebcamSizePreset = number;
 
+export const MIN_WEBCAM_SIZE_PRESET: WebcamSizePreset = 10;
+export const MAX_WEBCAM_SIZE_PRESET: WebcamSizePreset = 50;
 export const DEFAULT_WEBCAM_SIZE_PRESET: WebcamSizePreset = 25;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/video-editor/types.ts` around lines 6 - 9, Declare and export
explicit min/max constants alongside DEFAULT_WEBCAM_SIZE_PRESET in the same
module (e.g., MIN_WEBCAM_SIZE_PRESET and MAX_WEBCAM_SIZE_PRESET) and change
usages in compositeLayout and projectPersistence to import these constants
instead of hardcoded 10 and 50; update any related types or comments for
WebcamSizePreset if needed so the slider bounds and default come from a single
source of truth.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/lib/compositeLayout.ts`:
- Around line 61-65: webcamSizeToFraction currently lets NaN propagate through
Math.min/Math.max; update the function (webcamSizeToFraction) to guard the
incoming percent by first checking Number.isFinite(percent) (or
!Number.isNaN(percent)) and substituting a sensible default (e.g., 10) when it’s
invalid, then perform the existing clamping (clamped) and return clamped/100;
ensure the guard covers non-numeric and infinite values so scale/width/height
won't become NaN.

---

Nitpick comments:
In `@src/components/video-editor/types.ts`:
- Around line 6-9: Declare and export explicit min/max constants alongside
DEFAULT_WEBCAM_SIZE_PRESET in the same module (e.g., MIN_WEBCAM_SIZE_PRESET and
MAX_WEBCAM_SIZE_PRESET) and change usages in compositeLayout and
projectPersistence to import these constants instead of hardcoded 10 and 50;
update any related types or comments for WebcamSizePreset if needed so the
slider bounds and default come from a single source of truth.

In `@src/lib/compositeLayout.test.ts`:
- Around line 131-150: The test "centers the combined screen and webcam stack in
vertical stack mode" currently verifies full-canvas placement but never
exercises maxContentSize, so either rename the test to reflect full-canvas
behavior or restore assertions to verify centering using maxContentSize; update
the test around computeCompositeLayout to assert that the combined content
width/height respects maxContentSize and is centered within canvas (e.g., check
that (canvas.width - maxContentSize.width)/2 equals the left x offset of the
stacked group and similarly for vertical offsets), or change the test name to
something like "fills canvas in vertical-stack mode when maxContentSize >=
canvas" if you intend to keep the existing assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 62b66e5b-2a2c-4608-9d85-de9d7876be55

📥 Commits

Reviewing files that changed from the base of the PR and between da16872 and 7920156.

📒 Files selected for processing (15)
  • src/components/video-editor/SettingsPanel.tsx
  • src/components/video-editor/VideoEditor.tsx
  • src/components/video-editor/VideoPlayback.tsx
  • src/components/video-editor/projectPersistence.ts
  • src/components/video-editor/types.ts
  • src/components/video-editor/videoPlayback/layoutUtils.ts
  • src/hooks/useEditorHistory.ts
  • src/i18n/locales/en/settings.json
  • src/i18n/locales/es/settings.json
  • src/i18n/locales/zh-CN/settings.json
  • src/lib/compositeLayout.test.ts
  • src/lib/compositeLayout.ts
  • src/lib/exporter/frameRenderer.ts
  • src/lib/exporter/gifExporter.ts
  • src/lib/exporter/videoExporter.ts

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/lib/compositeLayout.ts (1)

154-155: Consider lowercase naming for the computed variable.

MAX_STAGE_FRACTION uses constant-style naming (SCREAMING_CASE) but is now a computed value derived from input. A name like stageFraction would better signal that it varies per call. Very minor style nit.

♻️ Optional rename
-	const MAX_STAGE_FRACTION = webcamSizeToFraction(webcamSizePreset);
+	const stageFraction = webcamSizeToFraction(webcamSizePreset);

Then update line 214-215:

-	const maxWidth = Math.max(transform.minSize, referenceDim * MAX_STAGE_FRACTION);
-	const maxHeight = Math.max(transform.minSize, referenceDim * MAX_STAGE_FRACTION);
+	const maxWidth = Math.max(transform.minSize, referenceDim * stageFraction);
+	const maxHeight = Math.max(transform.minSize, referenceDim * stageFraction);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/compositeLayout.ts` around lines 154 - 155, Rename the computed
constant MAX_STAGE_FRACTION to a lowercased, non-constant-style name (e.g.,
stageFraction) because it’s derived from input via
webcamSizeToFraction(webcamSizePreset); update all references to
MAX_STAGE_FRACTION (including usages near the previous lines referenced around
where MAX_STAGE_FRACTION was used) to the new name so the code consistently
reflects that this value varies per call.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/lib/compositeLayout.ts`:
- Around line 154-155: Rename the computed constant MAX_STAGE_FRACTION to a
lowercased, non-constant-style name (e.g., stageFraction) because it’s derived
from input via webcamSizeToFraction(webcamSizePreset); update all references to
MAX_STAGE_FRACTION (including usages near the previous lines referenced around
where MAX_STAGE_FRACTION was used) to the new name so the code consistently
reflects that this value varies per call.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8aaa7c4a-60c9-4bca-9521-50bd05d5665f

📥 Commits

Reviewing files that changed from the base of the PR and between 7920156 and 2ee7ccd.

📒 Files selected for processing (1)
  • src/lib/compositeLayout.ts

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.

[Feature]: The webcam recording is not resizable

1 participant