'use client';
import React, { Suspense, useRef, useCallback, useState } from 'react';
import { Canvas } from '@react-three/fiber';
import {
Environment,
ContactShadows,
OrbitControls,
useProgress,
Html,
} from '@react-three/drei';
import { useThree } from '@react-three/fiber';
import { RobotModel } from './RobotModel';
import { snapshotStore } from '@/store/useSnapshotStore';
import type { WebGLRenderer, Scene, Camera } from 'three';
function Loader() {
const { progress } = useProgress();
return (
{progress.toFixed(0)}% loaded
);
}
function SceneCapture({ onCapture }: { onCapture: (gl: WebGLRenderer, scene: Scene, camera: Camera) => void }) {
const { gl, scene, camera } = useThree();
React.useEffect(() => {
onCapture(gl, scene, camera);
}, [gl, scene, camera, onCapture]);
return null;
}
function SceneContent({ onCapture }: { onCapture: (gl: WebGLRenderer, scene: Scene, camera: Camera) => void }) {
return (
<>
>
);
}
export function RobotCanvas() {
const glRef = useRef(null);
const sceneRef = useRef(null);
const cameraRef = useRef(null);
const [isCapturing, setIsCapturing] = useState(false);
const [shareStatus, setShareStatus] = useState<'idle' | 'copied' | 'failed'>('idle');
const handleCapture = useCallback((gl: WebGLRenderer, scene: Scene, camera: Camera) => {
glRef.current = gl;
sceneRef.current = scene;
cameraRef.current = camera;
// Register a programmatic capture function for the checkout snapshot
snapshotStore.getState().registerCapture(() => {
if (!glRef.current || !sceneRef.current || !cameraRef.current) return null;
try {
glRef.current.render(sceneRef.current, cameraRef.current);
return glRef.current.domElement.toDataURL('image/jpeg', 0.75);
} catch {
return null;
}
});
}, []);
const handleShare = useCallback(async () => {
try {
await navigator.clipboard.writeText(window.location.href);
setShareStatus('copied');
setTimeout(() => setShareStatus('idle'), 2000);
} catch {
setShareStatus('failed');
setTimeout(() => setShareStatus('idle'), 2000);
}
}, []);
const handleSnapshot = useCallback(() => {
if (!glRef.current || !sceneRef.current || !cameraRef.current) return;
setIsCapturing(true);
try {
glRef.current.render(sceneRef.current, cameraRef.current);
const dataUrl = glRef.current.domElement.toDataURL('image/png');
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
const link = document.createElement('a');
link.download = `g1-robot-${timestamp}.png`;
link.href = dataUrl;
link.click();
} catch (error) {
console.error('Failed to capture snapshot:', error);
} finally {
setIsCapturing(false);
}
}, []);
const btnBase: React.CSSProperties = {
position: 'absolute',
top: '1rem',
padding: '0.5rem 1rem',
backdropFilter: 'blur(8px)',
borderRadius: '0.5rem',
cursor: 'pointer',
fontSize: '0.8rem',
fontWeight: 500,
display: 'flex',
alignItems: 'center',
gap: '0.5rem',
transition: 'all 0.2s ease',
zIndex: 10,
};
return (
);
}