Skip to content

Add webcam mirror toggle#633

Merged
siddharthvaddem merged 4 commits into
siddharthvaddem:mainfrom
AjTheSpidey:codex/webcam-mirror-toggle
Jun 2, 2026
Merged

Add webcam mirror toggle#633
siddharthvaddem merged 4 commits into
siddharthvaddem:mainfrom
AjTheSpidey:codex/webcam-mirror-toggle

Conversation

@AjTheSpidey
Copy link
Copy Markdown
Contributor

@AjTheSpidey AjTheSpidey commented May 21, 2026

Fixes #632.

Added a Mirror webcam switch in the editor layout panel. When it is on, the webcam flips in the preview and the same flip is used during GIF/MP4 export, so the saved file matches what you see while editing.

Tested locally:

  • npx biome check --write on the touched files
  • npx vitest --run src/components/video-editor/projectPersistence.test.ts src/lib/exporter/frameRenderer.test.ts
  • npm run build-vite

One note: full npm run lint still hits existing formatter/line-ending errors in untouched repo files, so I kept the check scoped to the files changed here.

Summary by CodeRabbit

  • New Features

    • Added a "Mirror webcam" toggle in Settings (default: off); preview mirrors in playback and applies to video and GIF exports.
    • Mirror setting is persisted with projects, restored on load, and included in undo/redo history.
  • Tests

    • Added unit tests for mirrored/non-mirrored webcam frame drawing and project state normalization.
  • Localization

    • Added "Mirror webcam" translations across multiple languages.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b56e39f3-1b6e-4662-8b52-25bd559d08c2

📥 Commits

Reviewing files that changed from the base of the PR and between 205ea55 and b56daae.

📒 Files selected for processing (18)
  • 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/hooks/useEditorHistory.ts
  • src/i18n/locales/ar/settings.json
  • 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/ja-JP/settings.json
  • src/i18n/locales/ko-KR/settings.json
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/tr/settings.json
  • src/i18n/locales/vi/settings.json
  • src/i18n/locales/zh-CN/settings.json
  • src/i18n/locales/zh-TW/settings.json
✅ Files skipped from review due to trivial changes (7)
  • src/i18n/locales/es/settings.json
  • src/i18n/locales/fr/settings.json
  • src/i18n/locales/zh-CN/settings.json
  • src/i18n/locales/ar/settings.json
  • src/i18n/locales/en/settings.json
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/ko-KR/settings.json
🚧 Files skipped from review as they are similar to previous changes (10)
  • src/i18n/locales/zh-TW/settings.json
  • src/i18n/locales/it/settings.json
  • src/components/video-editor/VideoPlayback.tsx
  • src/i18n/locales/vi/settings.json
  • src/components/video-editor/types.ts
  • src/components/video-editor/projectPersistence.ts
  • src/i18n/locales/ja-JP/settings.json
  • src/hooks/useEditorHistory.ts
  • src/components/video-editor/SettingsPanel.tsx
  • src/components/video-editor/VideoEditor.tsx

📝 Walkthrough

Walkthrough

Adds a webcam "mirror" toggle and default, threads the flag through editor state and persistence, mirrors live preview via CSS, and uses a new canvas helper so exports render mirrored webcam frames; includes tests and i18n labels.

Changes

Webcam Mirroring Feature

Layer / File(s) Summary
Core types and default constant
src/components/video-editor/types.ts, src/lib/exporter/webcamFrameDrawing.ts
Adds DEFAULT_WEBCAM_MIRRORED and defines WebcamFrameCrop + WebcamCanvasContext.
Canvas drawing utility + tests
src/lib/exporter/webcamFrameDrawing.ts, src/lib/exporter/frameRenderer.test.ts
Implements drawWebcamFrameImage(mirrored?) and tests normal, mirrored, and failure paths with a mocked canvas context.
Export pipeline integration
src/lib/exporter/frameRenderer.ts, src/lib/exporter/gifExporter.ts, src/lib/exporter/videoExporter.ts
Replaces inline webcam draw with drawWebcamFrameImage and threads webcamMirrored through FrameRenderer, GifExporter, and VideoExporter configs.
Editor state and project persistence
src/hooks/useEditorHistory.ts, src/components/video-editor/projectPersistence.ts, src/components/video-editor/projectPersistence.test.ts
Adds webcamMirrored: boolean to editor/project state, uses DEFAULT_WEBCAM_MIRRORED as default, normalizes loaded projects, and adds normalization tests.
UI controls, preview rendering, and wiring
src/components/video-editor/SettingsPanel.tsx, src/components/video-editor/VideoPlayback.tsx, src/components/video-editor/VideoEditor.tsx
Exposes mirror toggle in SettingsPanel (hidden for no-webcam preset), wires handler into editor state via pushState, and applies scaleX(-1) in VideoPlayback when enabled; passes flag into saves/exports.
Localization updates
src/i18n/locales/*/settings.json
Adds mirrorWebcam translation key across multiple locales for the new UI label.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • siddharthvaddem

Poem

a tiny switch flips the webcam's grin
preview skews, export learns to spin
canvas saves, tests nod and sigh
kinda cursed, lowkey neat — ship it, shy ✨

🚥 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 'Add webcam mirror toggle' clearly and concisely describes the main feature addition—a new toggle for mirroring the webcam in the editor UI.
Description check ✅ Passed The description covers purpose (fixes #632, adds mirror webcam switch), motivation (so saved files match preview), testing steps, and includes local verification with biome/vitest/build commands.
Linked Issues check ✅ Passed The PR fully implements the feature request from #632: a horizontal flip toggle that mirrors the webcam across the vertical axis in both the preview and exports (GIF/MP4).
Out of Scope Changes check ✅ Passed All changes are directly related to implementing webcam mirroring: UI toggle, state management, persistence, renderer integration, and i18n strings. No unrelated modifications detected.

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


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
Contributor

@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: 2

🤖 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/SettingsPanel.tsx`:
- Around line 1194-1199: The "Mirror webcam" label and its aria-label are
hardcoded; replace both with your i18n lookup (e.g., use the t function from
your translation hook) so the text and aria-label are localized. In
SettingsPanel (where webcamMirrored and onWebcamMirroredChange are used) change
"Mirror webcam" to something like t('settings.mirrorWebcam') and the Switch
aria-label to t('settings.mirrorWebcamAria') (and add those keys to the locale
files), ensuring you import/use the existing translation hook (e.g., const { t }
= useTranslation()) in the component.

In `@src/lib/exporter/webcamFrameDrawing.ts`:
- Around line 20-26: The mirrored branch in webcamFrameDrawing uses ctx.save(),
ctx.translate(...), ctx.scale(...), ctx.drawImage(...), then ctx.restore(); but
if drawImage throws the transform leaks—wrap the transform and draw in a
try/finally so ctx.restore() always runs; specifically locate the mirrored
handling block that calls ctx.save(), ctx.translate, ctx.scale and ctx.drawImage
and ensure restore() is invoked in finally before returning from the function.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 25b5b6c5-a18f-4633-ab71-fa740eb019d9

📥 Commits

Reviewing files that changed from the base of the PR and between 9f7f498 and 411f9a3.

📒 Files selected for processing (12)
  • src/components/video-editor/SettingsPanel.tsx
  • src/components/video-editor/VideoEditor.tsx
  • src/components/video-editor/VideoPlayback.tsx
  • src/components/video-editor/projectPersistence.test.ts
  • src/components/video-editor/projectPersistence.ts
  • src/components/video-editor/types.ts
  • src/hooks/useEditorHistory.ts
  • src/lib/exporter/frameRenderer.test.ts
  • src/lib/exporter/frameRenderer.ts
  • src/lib/exporter/gifExporter.ts
  • src/lib/exporter/videoExporter.ts
  • src/lib/exporter/webcamFrameDrawing.ts

Comment thread src/components/video-editor/SettingsPanel.tsx Outdated
Comment thread src/lib/exporter/webcamFrameDrawing.ts
@AjTheSpidey AjTheSpidey force-pushed the codex/webcam-mirror-toggle branch from e5f023c to 2cf09a8 Compare May 24, 2026 01:00
Copy link
Copy Markdown
Contributor

@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 (3)
src/i18n/locales/en/settings.json (2)

48-49: 💤 Low value

capitalization inconsistency between webcam labels

line 48 uses "Webcam Size" (capital W) but line 49 uses "Mirror webcam" (lowercase w). kinda inconsistent but lowkey not a blocker since both are readable. might wanna decide on one style tho

🤖 Prompt for 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.

In `@src/i18n/locales/en/settings.json` around lines 48 - 49, The two i18n entries
are inconsistent in capitalization—"webcamSize" value is "Webcam Size" but
"mirrorWebcam" value is "Mirror webcam"; update the "mirrorWebcam" value to
"Mirror Webcam" to match Title Case used by "webcamSize" (and audit other locale
files for the same keys to keep translations consistent across languages).

3-3: 💤 Low value

unrelated localization change detected

this line modifies zoom.previewHold which isn't part of the webcam mirror feature. same with line 116's jpgOnly change. these look like cleanup/improvements but weren't mentioned in the pr summary. not blocking but worth noting for commit hygiene

🤖 Prompt for 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.

In `@src/i18n/locales/en/settings.json` at line 3, This change modifies unrelated
localization keys ("previewHold" under zoom/zoom.previewHold and "jpgOnly"
elsewhere in settings.json) that are not part of the webcam mirror feature;
revert those localization edits or move them into a separate commit/PR and
update the PR description accordingly so this branch only contains webcam mirror
changes, referencing the keys "previewHold" and "jpgOnly" when making the revert
or split.
src/components/video-editor/SettingsPanel.tsx (1)

443-444: ⚡ Quick win

nit: keep webcamMirrored default aligned with shared defaults

Line 443 uses a literal false; lowkey risky for drift if DEFAULT_WEBCAM_MIRRORED changes later. Prefer the shared constant for SSOT consistency.

♻️ Proposed tweak
 import {
+	DEFAULT_WEBCAM_MIRRORED,
 	MAX_ZOOM_SCALE,
 	MIN_ZOOM_SCALE,
 	ROTATION_3D_PRESET_ORDER,
 	SPEED_OPTIONS,
 	ZOOM_DEPTH_SCALES,
 } from "./types";
@@
-	webcamMirrored = false,
+	webcamMirrored = DEFAULT_WEBCAM_MIRRORED,
🤖 Prompt for 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.

In `@src/components/video-editor/SettingsPanel.tsx` around lines 443 - 444, The
prop default for webcamMirrored in the SettingsPanel component should use the
shared constant instead of a hardcoded false; replace the literal default
(webcamMirrored = false) with the shared DEFAULT_WEBCAM_MIRRORED and ensure
DEFAULT_WEBCAM_MIRRORED is imported from the central defaults module so the
SettingsPanel (and its prop signature referencing webcamMirrored and
onWebcamMirroredChange) stays single-source-of-truth.
🤖 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.

Nitpick comments:
In `@src/components/video-editor/SettingsPanel.tsx`:
- Around line 443-444: The prop default for webcamMirrored in the SettingsPanel
component should use the shared constant instead of a hardcoded false; replace
the literal default (webcamMirrored = false) with the shared
DEFAULT_WEBCAM_MIRRORED and ensure DEFAULT_WEBCAM_MIRRORED is imported from the
central defaults module so the SettingsPanel (and its prop signature referencing
webcamMirrored and onWebcamMirroredChange) stays single-source-of-truth.

In `@src/i18n/locales/en/settings.json`:
- Around line 48-49: The two i18n entries are inconsistent in
capitalization—"webcamSize" value is "Webcam Size" but "mirrorWebcam" value is
"Mirror webcam"; update the "mirrorWebcam" value to "Mirror Webcam" to match
Title Case used by "webcamSize" (and audit other locale files for the same keys
to keep translations consistent across languages).
- Line 3: This change modifies unrelated localization keys ("previewHold" under
zoom/zoom.previewHold and "jpgOnly" elsewhere in settings.json) that are not
part of the webcam mirror feature; revert those localization edits or move them
into a separate commit/PR and update the PR description accordingly so this
branch only contains webcam mirror changes, referencing the keys "previewHold"
and "jpgOnly" when making the revert or split.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8f5111de-6ac6-43ad-9450-4393b2c9d557

📥 Commits

Reviewing files that changed from the base of the PR and between e5f023c and 2cf09a8.

📒 Files selected for processing (24)
  • src/components/video-editor/SettingsPanel.tsx
  • src/components/video-editor/VideoEditor.tsx
  • src/components/video-editor/VideoPlayback.tsx
  • src/components/video-editor/projectPersistence.test.ts
  • src/components/video-editor/projectPersistence.ts
  • src/components/video-editor/types.ts
  • src/hooks/useEditorHistory.ts
  • src/i18n/locales/ar/settings.json
  • 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/ja-JP/settings.json
  • src/i18n/locales/ko-KR/settings.json
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/tr/settings.json
  • src/i18n/locales/vi/settings.json
  • src/i18n/locales/zh-CN/settings.json
  • src/i18n/locales/zh-TW/settings.json
  • src/lib/exporter/frameRenderer.test.ts
  • src/lib/exporter/frameRenderer.ts
  • src/lib/exporter/gifExporter.ts
  • src/lib/exporter/videoExporter.ts
  • src/lib/exporter/webcamFrameDrawing.ts
✅ Files skipped from review due to trivial changes (7)
  • src/i18n/locales/ru/settings.json
  • src/i18n/locales/ar/settings.json
  • src/i18n/locales/es/settings.json
  • src/i18n/locales/fr/settings.json
  • src/i18n/locales/vi/settings.json
  • src/i18n/locales/tr/settings.json
  • src/i18n/locales/it/settings.json

@siddharthvaddem
Copy link
Copy Markdown
Owner

@AjTheSpidey please include screenshots/ videos when opening a PR that changes the UI in any way.

@AjTheSpidey
Copy link
Copy Markdown
Contributor Author

Added a screenshot from a local Electron run so the UI change is easier to see.

I used the sample video as both the screen recording and webcam clip, opened the Layout panel, and turned Mirror Webcam on. The small webcam preview is flipped in the screenshot.

Mirror Webcam toggle enabled

Also pushed a tiny cleanup for the default value and the English label capitalization.

@siddharthvaddem siddharthvaddem merged commit 9a83062 into siddharthvaddem:main Jun 2, 2026
11 checks passed
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]: Flip webcam video (horizontal / mirroring)

2 participants