From e1e0e6cc0ca6e6ba00ad5709a7cb55907a7eee2c Mon Sep 17 00:00:00 2001 From: Thomas Hallock Date: Tue, 6 Jan 2026 09:45:51 -0600 Subject: [PATCH] fix(vision): ensure training data collection works with remote camera MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vision source registration effect was not re-running when the first remote camera frame arrived, because remoteLatestFrame was not in the dependency array. The element that remoteImageRef points to only renders when remoteLatestFrame is truthy, so the effect would run before the element existed and fail to register the source. Now both local and remote cameras properly register their vision source for training data collection when a correct answer is entered. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- apps/web/src/components/vision/DockedVisionFeed.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/vision/DockedVisionFeed.tsx b/apps/web/src/components/vision/DockedVisionFeed.tsx index 47651407..81473627 100644 --- a/apps/web/src/components/vision/DockedVisionFeed.tsx +++ b/apps/web/src/components/vision/DockedVisionFeed.tsx @@ -272,10 +272,12 @@ export function DockedVisionFeed({ onValueDetected, columnCount = 5 }: DockedVis }, [videoStream]) // Register vision source for training data capture + // Note: We depend on remoteLatestFrame because the element only renders when we have a frame, + // so remoteImageRef.current is null until the first frame arrives useEffect(() => { if (isLocalCamera && videoRef.current && videoStream) { visionSourceRef.current = { type: 'video', element: videoRef.current } - } else if (isRemoteCamera && remoteImageRef.current && remoteIsPhoneConnected) { + } else if (isRemoteCamera && remoteImageRef.current && remoteIsPhoneConnected && remoteLatestFrame) { visionSourceRef.current = { type: 'image', element: remoteImageRef.current } } @@ -283,7 +285,7 @@ export function DockedVisionFeed({ onValueDetected, columnCount = 5 }: DockedVis // Clear the source ref when this component unmounts visionSourceRef.current = null } - }, [isLocalCamera, isRemoteCamera, videoStream, remoteIsPhoneConnected, visionSourceRef]) + }, [isLocalCamera, isRemoteCamera, videoStream, remoteIsPhoneConnected, remoteLatestFrame, visionSourceRef]) // Subscribe to remote camera session useEffect(() => {