diff --git a/frontend/src/components/control/BrowserCameraPreview.test.tsx b/frontend/src/components/control/BrowserCameraPreview.test.tsx index 818c762a7..c6bca6f70 100644 --- a/frontend/src/components/control/BrowserCameraPreview.test.tsx +++ b/frontend/src/components/control/BrowserCameraPreview.test.tsx @@ -39,3 +39,13 @@ test("a stream at another size keeps the recorded aspect ratio", () => { expect(video.style.width).toBe("100%"); expect(video.style.objectFit).toBe("cover"); }); +test("the reference ghost sits over the video with its rotation and opacity", () => { + act(() => root.render()); + const video = container.querySelector("video")!, ghost = container.querySelector("img")!; + expect(ghost.getAttribute("src")).toBe("blob:ref"); + expect(ghost.style.opacity).toBe("0.3"); + expect(ghost.style.transform).toBe(video.style.transform); + expect(ghost.style.width).toBe(video.style.width); + act(() => root.render()); + expect(container.querySelector("img")).toBeNull(); +}); diff --git a/frontend/src/components/control/BrowserCameraPreview.tsx b/frontend/src/components/control/BrowserCameraPreview.tsx index de6107d99..b2b693345 100644 --- a/frontend/src/components/control/BrowserCameraPreview.tsx +++ b/frontend/src/components/control/BrowserCameraPreview.tsx @@ -11,6 +11,9 @@ interface Props { height?: number; className?: string; fallback?: string; + /** Saved reference frame, drawn over the live video as a translucent ghost. */ + ghostSrc?: string; + ghostOpacity?: number; } /** @@ -26,6 +29,8 @@ export default function BrowserCameraPreview({ height = 480, className = "", fallback, + ghostSrc, + ghostOpacity = 0.5, }: Props) { const rotationError = cameraRotationError({ rotation }); const { videoRef, hasError } = useCameraStream(deviceId, paused || !!rotationError, { width, height }); @@ -39,6 +44,7 @@ export default function BrowserCameraPreview({ style={{ aspectRatio: geometry.aspectRatio }} > {showVideo ? ( + <>