import { DetectionFeedback, Frame, PrismSession, } from "@prismlabs/web-scan-core"; import React, { useCallback, useEffect, useRef } from "react"; import { Subscription } from "rxjs"; import { getCssVarValue } from "../theme/theme-helpers"; import { PosingState } from "./posing-state-distributor"; import { PoseTheme } from "./skelton-drawing-utils"; interface PoseOverlayProps { prismSession: PrismSession; posingState: PosingState | null; drawSkeleton: ( frame: Frame, detectionFeedback: DetectionFeedback | undefined, canvas: HTMLCanvasElement, theme: PoseTheme ) => void; } export const PoseOverlay: React.FC = ({ prismSession, posingState, drawSkeleton, }) => { const canvasRef = useRef(null); const subscriptionRef = useRef(null); const canvasHandler = useCallback((canvas: HTMLCanvasElement | null) => { if (canvas) { canvasRef.current = canvas; // Make sure canvas size matches the video dimensions const videoElement = prismSession.captureSession.cameraManager.videoElement; if (videoElement) { canvas.width = videoElement.videoWidth; canvas.height = videoElement.videoHeight; } } }, []); // Set up canvas and drawing context useEffect(() => { // Clear any existing subscriptions if (subscriptionRef.current) { subscriptionRef.current.unsubscribe(); } const theme: PoseTheme = { acceptableColor: getCssVarValue("--pose-acceptable-color"), unacceptableColor: getCssVarValue("--pose-unacceptable-color"), landmarkColor: getCssVarValue("--pose-landmark-color"), boneThickness: 30, }; // Subscribe to frame updates from the frame distributor subscriptionRef.current = prismSession.captureSession.frameDistributor.windowedAverageFrame.subscribe( (frame: Frame | undefined) => { if (frame && canvasRef.current) { const canvas = canvasRef.current; drawSkeleton(frame, posingState?.detectionFeedback, canvas, theme); } } ); return () => { subscriptionRef.current?.unsubscribe(); }; }, [posingState]); return ( ); };