Skip to content

Add dynamic webcam overlay dimensions#682

Open
surim0n wants to merge 1 commit into
webadderallorg:mainfrom
surim0n:codex/dynamic-webcam-overlay-shape
Open

Add dynamic webcam overlay dimensions#682
surim0n wants to merge 1 commit into
webadderallorg:mainfrom
surim0n:codex/dynamic-webcam-overlay-shape

Conversation

@surim0n

@surim0n surim0n commented Jun 15, 2026

Copy link
Copy Markdown

Summary

  • Replaces the single webcam size control with separate width and height controls, while falling back to the old size value for existing projects.
  • Removes the square lock from webcam crop editing and lets crop aspect drive the overlay height when width/height are still linked.
  • Updates live preview, canvas export, and the modern Pixi renderer to draw rectangular webcam overlays correctly.
  • Skips the native static-layout shortcut for rectangular/cropped webcam overlays so export falls back to the renderer that supports the shape.
  • Adds locale labels and focused tests for overlay math and native static-layout eligibility.

Verification

  • npx vitest --run src/components/video-editor/webcamOverlay.test.ts src/lib/exporter/modernVideoExporter.nativeStaticLayout.test.ts
  • npx vitest --run src/lib/exporter/frameRenderer.test.ts src/lib/exporter/modernFrameRenderer.test.ts src/components/video-editor/webcamOverlay.test.ts src/lib/exporter/modernVideoExporter.nativeStaticLayout.test.ts
  • npx tsc --noEmit --noUnusedLocals false --noUnusedParameters false
  • npx biome check src/components/video-editor/WebcamCropControl.tsx src/components/video-editor/webcamOverlay.ts src/components/video-editor/webcamOverlay.test.ts src/components/video-editor/types.ts src/components/video-editor/projectPersistence.ts src/lib/exporter/modernVideoExporter.ts src/lib/exporter/modernVideoExporter.nativeStaticLayout.test.ts

Known existing check failures

  • npx tsc --noEmit fails on existing unused code in src/components/video-editor/videoPlayback/zoomRegionUtils.ts.
  • npm run i18n:check fails on existing missing/extra locale keys unrelated to these new webcam labels.
  • npm test has one unrelated failure in electron/ipc/paths/binaries.test.ts around Windows helper path resolution; the focused renderer/webcam tests pass.

Summary by CodeRabbit

  • New Features
    • Webcam overlay controls now support independent width and height, with separate sliders for “Webcam Width” and “Webcam Height”
    • Webcam cropping now preserves visual proportions by automatically matching overlay height to the crop region
  • Bug Fixes
    • Webcam overlay sizing/cropping is now consistent across playback and exports, including correct rectangular rendering and shadow scaling
  • Localization
    • Updated settings UI translations with new webcam width/height labels in all supported languages

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: f37036fb-4dc3-42b2-8a70-01e02930602c

📥 Commits

Reviewing files that changed from the base of the PR and between f58576d and e8eb226.

📒 Files selected for processing (22)
  • src/components/video-editor/SettingsPanel.tsx
  • src/components/video-editor/VideoEditor.tsx
  • src/components/video-editor/VideoPlayback.tsx
  • src/components/video-editor/WebcamCropControl.tsx
  • src/components/video-editor/projectPersistence.ts
  • src/components/video-editor/types.ts
  • src/components/video-editor/webcamOverlay.test.ts
  • src/components/video-editor/webcamOverlay.ts
  • src/i18n/locales/en/settings.json
  • src/i18n/locales/es/settings.json
  • src/i18n/locales/fr/settings.json
  • src/i18n/locales/it/settings.json
  • src/i18n/locales/ko/settings.json
  • src/i18n/locales/nl/settings.json
  • src/i18n/locales/pt-BR/settings.json
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/zh-CN/settings.json
  • src/i18n/locales/zh-TW/settings.json
  • src/lib/exporter/frameRenderer.ts
  • src/lib/exporter/modernFrameRenderer.ts
  • src/lib/exporter/modernVideoExporter.nativeStaticLayout.test.ts
  • src/lib/exporter/modernVideoExporter.ts
✅ Files skipped from review due to trivial changes (8)
  • src/i18n/locales/zh-TW/settings.json
  • src/i18n/locales/pt-BR/settings.json
  • src/i18n/locales/nl/settings.json
  • src/i18n/locales/es/settings.json
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/it/settings.json
  • src/i18n/locales/en/settings.json
  • src/i18n/locales/fr/settings.json
🚧 Files skipped from review as they are similar to previous changes (13)
  • src/components/video-editor/types.ts
  • src/lib/exporter/modernVideoExporter.nativeStaticLayout.test.ts
  • src/i18n/locales/zh-CN/settings.json
  • src/components/video-editor/webcamOverlay.test.ts
  • src/components/video-editor/SettingsPanel.tsx
  • src/components/video-editor/VideoPlayback.tsx
  • src/components/video-editor/VideoEditor.tsx
  • src/lib/exporter/frameRenderer.ts
  • src/lib/exporter/modernFrameRenderer.ts
  • src/components/video-editor/WebcamCropControl.tsx
  • src/i18n/locales/ko/settings.json
  • src/lib/exporter/modernVideoExporter.ts
  • src/components/video-editor/webcamOverlay.ts

📝 Walkthrough

Walkthrough

The PR replaces the single square webcam overlay size model with independent width and height dimensions. New helpers (getWebcamOverlayDimensionsPx, getCropMatchedWebcamHeightPercent) drive resized layout across the settings UI, playback preview, both frame renderers, project persistence normalization, and crop control. A native-static-layout skip guard is added for rectangular overlays.

Changes

Rectangular Webcam Overlay

Layer / File(s) Summary
Data shape and overlay math helpers
src/components/video-editor/types.ts, src/components/video-editor/webcamOverlay.ts, src/components/video-editor/webcamOverlay.test.ts
WebcamOverlaySettings gains width/height fields with defaults. getWebcamOverlayDimensionsPx is added to compute rectangular pixel dimensions; getWebcamOverlayPosition is updated to accept optional width/height; getCropMatchedWebcamHeightPercent is introduced with full test coverage for all three.
Project persistence and smoke-export initialization
src/components/video-editor/projectPersistence.ts, src/components/video-editor/VideoEditor.tsx
normalizeProjectEditor independently derives and clamps width/height from their respective webcam.* values (falling back to webcam.size, then DEFAULT_WEBCAM_SIZE). Smoke-export initialization preserves existing prev.width/prev.height instead of always overwriting with prev.size.
WebcamCropControl: aspect-independent crop refactor
src/components/video-editor/WebcamCropControl.tsx
Removes aspect-ratio-constrained crop normalization. Replaces normalizeAspectCropRegion/resizeCrop(displayAspectRatio) with normalizeWebcamCropRegion-based helpers. Extends onCropChange to pass previewFrame on both immediate and deferred commits.
Settings panel: two webcam dimension sliders
src/components/video-editor/SettingsPanel.tsx, src/i18n/locales/*/settings.json
Derives webcamWidth/webcamHeight from webcam.width/webcam.height, replaces the single "Webcam Size" slider with separate Width and Height sliders, and rewires onCropChange to recompute height via getCropMatchedWebcamHeightPercent. Adds webcamWidth/webcamHeight i18n keys across all nine locales.
VideoPlayback rectangular overlay layout
src/components/video-editor/VideoPlayback.tsx
Replaces single webcamSize with webcamWidth/webcamHeight (crop-matched). Rewrites crop-preview CSS using target aspect, refactors bubble layout to use getWebcamOverlayDimensionsPx for rectangular dimensions, squircle clip path, and shadow sizing.
Export frame renderers: rectangular overlay sizing
src/lib/exporter/frameRenderer.ts, src/lib/exporter/modernFrameRenderer.ts
drawWebcamOverlay derives heightPercent via getCropMatchedWebcamHeightPercent and computes rectangular dimensions for bubble canvas, crop/cover scaling, and shadow. WebcamLayoutCache changes from size to width/height; applyWebcamLayout uses per-axis centering; updateWebcamOverlay uses the new helpers end-to-end.
Native static-layout rectangular overlay guard
src/lib/exporter/modernVideoExporter.ts, src/lib/exporter/modernVideoExporter.nativeStaticLayout.test.ts
Adds hasUnsupportedNativeStaticLayoutWebcamShape detecting width/height mismatch or non-default crop; registers unsupported-rectangular-webcam-overlay skip reason; updates sizePercent to prefer webcam.width; tests assert the new skip reason fires for rectangular and non-finite dimensions.

Sequence Diagram(s)

sequenceDiagram
  participant SettingsPanel
  participant WebcamCropControl
  participant getCropMatchedWebcamHeightPercent
  participant updateWebcam

  SettingsPanel->>WebcamCropControl: render with webcamWidth, webcamHeight
  WebcamCropControl-->>SettingsPanel: onCropChange(cropRegion, previewFrame)
  SettingsPanel->>getCropMatchedWebcamHeightPercent: webcamWidth, webcamHeight, previewFrame.w/h, cropRegion
  getCropMatchedWebcamHeightPercent-->>SettingsPanel: matched heightPercent
  SettingsPanel->>updateWebcam: patch { cropRegion, height: matchedHeight }
Loading
sequenceDiagram
  participant VideoPlayback
  participant getCropMatchedWebcamHeightPercent
  participant getWebcamOverlayDimensionsPx
  participant getWebcamOverlayPosition
  participant BubbleElement

  VideoPlayback->>getCropMatchedWebcamHeightPercent: webcamWidth, rawWebcamHeight, videoDims, cropRegion
  getCropMatchedWebcamHeightPercent-->>VideoPlayback: webcamHeight
  VideoPlayback->>getWebcamOverlayDimensionsPx: containerDims, webcamWidth, webcamHeight, margin, zoom
  getWebcamOverlayDimensionsPx-->>VideoPlayback: { width, height } px
  VideoPlayback->>getWebcamOverlayPosition: containerDims, width, height, margin, preset
  getWebcamOverlayPosition-->>VideoPlayback: { x, y }
  VideoPlayback->>BubbleElement: style { width, height, aspectRatio, clipPath, boxShadow }
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • webadderallorg/Recordly#394: Introduces the original webcam crop/mirror controls and applies cropRegion in preview and export — the same pipeline this PR refactors to support independent width/height and crop-matched overlay sizing.
  • webadderallorg/Recordly#543: Refactors VideoEditor.tsx smoke-export config parsing into smokeExportConfig — this PR modifies the same VideoEditor.tsx initialization path to apply smokeExportConfig.webcamSize to new width/height fields.
  • webadderallorg/Recordly#646: Adjusts webcam-frame refresh timing in drawWebcamOverlay of frameRenderer.ts — this PR refactors the same method for rectangular overlay sizing and crop geometry.

🐇 Two sliders where one used to be,
Width and height, now running free!
The webcam bubble, no longer square,
Crops and stretches with pixel care.
A rectangle hops across the screen — 🎥

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 clearly summarizes the main change: adding dynamic (separate width and height) webcam overlay dimensions instead of a single size value.
Description check ✅ Passed The PR description provides a clear summary, motivation, verification steps, and known issues, but doesn't follow the template structure with explicit sections like 'Type of Change' or 'Testing Guide' checkboxes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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.

@surim0n surim0n force-pushed the codex/dynamic-webcam-overlay-shape branch from 1b2260a to f58576d Compare June 20, 2026 15:26
@surim0n surim0n marked this pull request as ready for review June 20, 2026 15:26

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/video-editor/projectPersistence.ts`:
- Around line 1030-1040: The size property at line 1030 can diverge from the
width property (lines 1031-1035) when persisted data has webcam.width but no
webcam.size, causing size to default while width gets restored from the data. To
fix this, update the size property to follow the same fallback logic as width:
first check if webcam.width is a finite number and clamp it, then fall back to
checking webcam.size, and finally default to DEFAULT_WEBCAM_SIZE. This ensures
the size and width properties remain synchronized and consistent regardless of
which properties exist in the persisted data.

In `@src/components/video-editor/SettingsPanel.tsx`:
- Around line 3920-3933: In the onCropChange callback within SettingsPanel.tsx,
the call to getCropMatchedWebcamHeightPercent is passing webcamWidth as both the
first and second parameters. The function expects the first parameter to be
widthPercent and the second parameter to be heightPercent. Replace the second
parameter (currently webcamWidth) with webcamHeight to ensure correct height
calculations when the crop region changes.

In `@src/lib/exporter/frameRenderer.ts`:
- Around line 2500-2503: The hardcoded fallback values of 50 in the
frameRenderer.ts file for widthPercent and heightPercent calculations do not
align with the playback defaults which use DEFAULT_WEBCAM_SIZE set to 40,
causing size mismatches for legacy webcam settings. Import DEFAULT_WEBCAM_SIZE
from src/components/video-editor/types.ts and replace both instances of the 50
fallback values (in the widthPercent assignment and in the heightPercent
parameter passed to getCropMatchedWebcamHeightPercent) with DEFAULT_WEBCAM_SIZE
to ensure consistency between preview and export rendering.

In `@src/lib/exporter/modernFrameRenderer.ts`:
- Around line 2919-2925: The call to getCropMatchedWebcamHeightPercent is
double-applying the crop aspect because renderableWebcamSource dimensions are
already crop-trimmed in the cache-backed path for non-default crops, yet the
webcam.cropRegion is still being passed as a parameter. To fix this,
conditionally pass the cropRegion parameter only when renderableWebcamSource has
not already been crop-trimmed, or pass null/undefined for the cropRegion
argument when the source dimensions are already cropped. This ensures the crop
aspect is only applied once during the heightPercent computation.

In `@src/lib/exporter/modernVideoExporter.ts`:
- Around line 1505-1507: The nullish coalescing operator at lines 1505 and 1506
does not filter out NaN values, so width and height variables can remain
non-finite. This causes Math.abs(width - height) at line 1507 to potentially
return NaN, which makes the comparison NaN > 0.001 evaluate to false and
incorrectly bypasses the unsupported-rectangular-webcam-overlay guard for
invalid persisted values. Add validation using isFinite() on the width and
height variables to ensure they are valid finite numbers before performing the
Math.abs comparison in the return statement.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c107421f-048b-4464-8a0f-e07fb5a4cd12

📥 Commits

Reviewing files that changed from the base of the PR and between 952d63d and f58576d.

📒 Files selected for processing (22)
  • src/components/video-editor/SettingsPanel.tsx
  • src/components/video-editor/VideoEditor.tsx
  • src/components/video-editor/VideoPlayback.tsx
  • src/components/video-editor/WebcamCropControl.tsx
  • src/components/video-editor/projectPersistence.ts
  • src/components/video-editor/types.ts
  • src/components/video-editor/webcamOverlay.test.ts
  • src/components/video-editor/webcamOverlay.ts
  • src/i18n/locales/en/settings.json
  • src/i18n/locales/es/settings.json
  • src/i18n/locales/fr/settings.json
  • src/i18n/locales/it/settings.json
  • src/i18n/locales/ko/settings.json
  • src/i18n/locales/nl/settings.json
  • src/i18n/locales/pt-BR/settings.json
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/zh-CN/settings.json
  • src/i18n/locales/zh-TW/settings.json
  • src/lib/exporter/frameRenderer.ts
  • src/lib/exporter/modernFrameRenderer.ts
  • src/lib/exporter/modernVideoExporter.nativeStaticLayout.test.ts
  • src/lib/exporter/modernVideoExporter.ts

Comment thread src/components/video-editor/projectPersistence.ts Outdated
Comment thread src/components/video-editor/SettingsPanel.tsx
Comment thread src/lib/exporter/frameRenderer.ts Outdated
Comment thread src/lib/exporter/modernFrameRenderer.ts
Comment thread src/lib/exporter/modernVideoExporter.ts Outdated
@surim0n surim0n force-pushed the codex/dynamic-webcam-overlay-shape branch from f58576d to e8eb226 Compare June 20, 2026 15:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant