Add webcam mask shape support#288
Conversation
📝 WalkthroughWalkthroughThis PR adds configurable webcam mask shape support ("rectangle", "circle", "square", "rounded") to the video editor. Changes include new UI controls in SettingsPanel, state management through VideoEditor and projectPersistence, rendering updates in VideoPlayback with CSS clip-path, canvas utilities, and layout computation adjustments. Changes
Sequence Diagram(s)sequenceDiagram
actor User
participant SettingsPanel
participant VideoEditor
participant ProjectPersistence
participant VideoPlayback
participant LayoutUtils
participant CompositeLayout
User->>SettingsPanel: Select webcam mask shape<br/>(circle, square, etc.)
SettingsPanel->>VideoEditor: onWebcamMaskShapeChange(shape)
VideoEditor->>VideoEditor: pushState({webcamMaskShape: shape})
VideoEditor->>ProjectPersistence: createProjectData(editor)
ProjectPersistence->>ProjectPersistence: Persist webcamMaskShape
VideoEditor->>VideoPlayback: Re-render with webcamMaskShape prop
VideoPlayback->>LayoutUtils: layoutVideoContentUtil(..., webcamMaskShape)
LayoutUtils->>CompositeLayout: computeCompositeLayout({..., webcamMaskShape})
CompositeLayout->>CompositeLayout: Calculate shape-specific<br/>dimensions & borderRadius
CompositeLayout-->>VideoPlayback: Return webcamRect with maskShape
VideoPlayback->>VideoPlayback: Apply CSS clip-path<br/>or borderRadius based on shape
VideoPlayback-->>User: Render webcam with mask shape
sequenceDiagram
participant VideoEditor
participant Exporter
participant FrameRenderer
participant Canvas
participant WebcamMaskShapes
VideoEditor->>Exporter: Export with webcamMaskShape config
Exporter->>FrameRenderer: new FrameRenderer({..., webcamMaskShape})
FrameRenderer->>Canvas: Render frame with webcam
Canvas->>FrameRenderer: requestAnimationFrame callback
FrameRenderer->>Canvas: computeCompositeLayout({..., webcamMaskShape})
FrameRenderer->>WebcamMaskShapes: drawCanvasClipPath(ctx, x, y, w, h,<br/>shape, borderRadius)
WebcamMaskShapes->>Canvas: ctx.beginPath()<br/>ctx.arc() or ctx.roundRect()<br/>ctx.closePath()
Canvas->>Canvas: ctx.clip()
Canvas->>Canvas: ctx.drawImage(webcam)
FrameRenderer-->>VideoEditor: Frame with masked webcam rendered
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9d0ccf3bde
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/lib/exporter/videoExporter.ts (1)
35-35: Consider importingWebcamMaskShapeat the top with other types.Same as in
gifExporter.ts— the inline import type is inconsistent with how other types from@/components/video-editor/typesare imported (Lines 1-8).♻️ Suggested refactor
import type { AnnotationRegion, CropRegion, SpeedRegion, TrimRegion, WebcamLayoutPreset, + WebcamMaskShape, ZoomRegion, } from "@/components/video-editor/types";Then update Line 35:
- webcamMaskShape?: import("@/components/video-editor/types").WebcamMaskShape; + webcamMaskShape?: WebcamMaskShape;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/exporter/videoExporter.ts` at line 35, The inline type import for webcamMaskShape should be replaced by importing WebcamMaskShape alongside the other types at the top of videoExporter.ts; update the top imports to include WebcamMaskShape from "@/components/video-editor/types" and change the webcamMaskShape property declaration (webcamMaskShape?: import("@/components/video-editor/types").WebcamMaskShape;) to use the imported WebcamMaskShape type instead.src/lib/exporter/gifExporter.ts (1)
44-44: Consider importingWebcamMaskShapeat the top with other types.The inline import type syntax works but is inconsistent with how other types from
@/components/video-editor/typesare imported (Lines 2-8). Moving it to the top improves readability and consistency.♻️ Suggested refactor
import type { AnnotationRegion, CropRegion, SpeedRegion, TrimRegion, WebcamLayoutPreset, + WebcamMaskShape, ZoomRegion, } from "@/components/video-editor/types";Then update Line 44:
- webcamMaskShape?: import("@/components/video-editor/types").WebcamMaskShape; + webcamMaskShape?: WebcamMaskShape;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/exporter/gifExporter.ts` at line 44, The inline type import for WebcamMaskShape should be moved to the top alongside the other imports from "@/components/video-editor/types" for consistency and readability; add WebcamMaskShape to the existing import list (the same statement that currently imports other types from "@/components/video-editor/types") and then replace the inline reference "webcamMaskShape?: import(\"@/components/video-editor/types\").WebcamMaskShape;" with "webcamMaskShape?: WebcamMaskShape;" in the gifExporter.ts declaration.src/lib/webcamMaskShapes.ts (1)
40-45: VerifyroundRectbrowser support for your target environments.
CanvasRenderingContext2D.roundRect()is widely available: Chrome/Edge 99+, Firefox 112+, Safari 16.4+, and Opera 85+ (all supporting since April 2023). For older browser support, consider a polyfill or manual path drawing implementation.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/lib/webcamMaskShapes.ts` around lines 40 - 45, The code uses CanvasRenderingContext2D.roundRect (ctx.roundRect) in the switch cases for "rectangle"/"rounded"/"square"/default which may not exist in older browsers; add a fallback that detects if ctx.roundRect is undefined and then draws a rounded-rect path manually (using ctx.beginPath, moveTo/lineTo/arcTo or arc for corners, closePath, and ctx.fill()/ctx.stroke() as appropriate) or include a small polyfill that defines ctx.roundRect before use; update the switch branch in webcamMaskShapes (where ctx.roundRect is called) to call the fallback function (e.g., drawRoundedRect(ctx, x, y, w, h, borderRadius)) when ctx.roundRect is unavailable.
🤖 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/components/video-editor/SettingsPanel.tsx`:
- Around line 631-711: The shape option labels are hardcoded and the button
group doesn't expose pressed state; update the shape list used in the
webcamLayoutPreset === "picture-in-picture" block (the array mapped to render
buttons) to use localization keys via t(...) instead of hardcoded
"Rect"/"Circle"/"Square"/"Rounded", and add aria-pressed={webcamMaskShape ===
shape.value} to each button rendered by the map so assistive tech can detect the
selected state; ensure the onClick still calls
onWebcamMaskShapeChange(shape.value) and keep existing className logic using
webcamMaskShape for visual selection.
---
Nitpick comments:
In `@src/lib/exporter/gifExporter.ts`:
- Line 44: The inline type import for WebcamMaskShape should be moved to the top
alongside the other imports from "@/components/video-editor/types" for
consistency and readability; add WebcamMaskShape to the existing import list
(the same statement that currently imports other types from
"@/components/video-editor/types") and then replace the inline reference
"webcamMaskShape?: import(\"@/components/video-editor/types\").WebcamMaskShape;"
with "webcamMaskShape?: WebcamMaskShape;" in the gifExporter.ts declaration.
In `@src/lib/exporter/videoExporter.ts`:
- Line 35: The inline type import for webcamMaskShape should be replaced by
importing WebcamMaskShape alongside the other types at the top of
videoExporter.ts; update the top imports to include WebcamMaskShape from
"@/components/video-editor/types" and change the webcamMaskShape property
declaration (webcamMaskShape?:
import("@/components/video-editor/types").WebcamMaskShape;) to use the imported
WebcamMaskShape type instead.
In `@src/lib/webcamMaskShapes.ts`:
- Around line 40-45: The code uses CanvasRenderingContext2D.roundRect
(ctx.roundRect) in the switch cases for "rectangle"/"rounded"/"square"/default
which may not exist in older browsers; add a fallback that detects if
ctx.roundRect is undefined and then draws a rounded-rect path manually (using
ctx.beginPath, moveTo/lineTo/arcTo or arc for corners, closePath, and
ctx.fill()/ctx.stroke() as appropriate) or include a small polyfill that defines
ctx.roundRect before use; update the switch branch in webcamMaskShapes (where
ctx.roundRect is called) to call the fallback function (e.g.,
drawRoundedRect(ctx, x, y, w, h, borderRadius)) when ctx.roundRect is
unavailable.
🪄 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: 45695159-3486-4219-a24d-749c90b97808
📒 Files selected for processing (17)
src/components/video-editor/SettingsPanel.tsxsrc/components/video-editor/VideoEditor.tsxsrc/components/video-editor/VideoPlayback.tsxsrc/components/video-editor/projectPersistence.test.tssrc/components/video-editor/projectPersistence.tssrc/components/video-editor/types.tssrc/components/video-editor/videoPlayback/layoutUtils.tssrc/hooks/useEditorHistory.tssrc/i18n/locales/en/settings.jsonsrc/i18n/locales/es/settings.jsonsrc/i18n/locales/zh-CN/settings.jsonsrc/lib/compositeLayout.test.tssrc/lib/compositeLayout.tssrc/lib/exporter/frameRenderer.tssrc/lib/exporter/gifExporter.tssrc/lib/exporter/videoExporter.tssrc/lib/webcamMaskShapes.ts
|
awesome! while you are at it, can we also have this #285 fixed? Shape and size go hand in hand. Would really appreciate it |
|
okay makes sense - thanks for working on this |
Summary
webcamMaskShapes.tswith shape definitions and rendering logicDemo:
export-1775164482142.mp4
Test plan
compositeLayout.test.ts,projectPersistence.test.ts)Summary by CodeRabbit
Release Notes