import { Suspense, useEffect, useRef, useState } from 'react'; import Spline from '@splinetool/react-spline'; interface SplineBackgroundProps { scene?: string; className?: string; onLoad?: () => void; } // Fallback component for loading state function SplineFallback({ message = 'Loading 3D Scene...' }: { message?: string }) { return (
{message}
); } export default function SplineBackground({ scene = "https://prod.spline.design/6Wq8T6XmHxrGMwni/scene.splinecode", className = "", onLoad }: SplineBackgroundProps) { const [error, setError] = useState(null); const [ready, setReady] = useState(false); const containerRef = useRef(null); const isSplineCode = scene.trim().toLowerCase().endsWith('.splinecode'); // Preflight check: ensure the scene URL is reachable before trying to load Spline useEffect(() => { let cancelled = false; setError(null); setReady(false); (async () => { try { // Use no-cors GET: many CDNs block HEAD and CORS; opaque means we cannot inspect but still OK to try const res = await fetch(scene, { method: 'GET', mode: 'no-cors' }); if (!cancelled) setReady(true); } catch (e) { console.error('Spline scene pre-check failed', e); if (!cancelled) setError('Failed to reach 3D scene'); } })(); return () => { cancelled = true; }; }, [scene]); // Handle WebGL context loss gracefully useEffect(() => { const el = containerRef.current; if (!el) return; const onContextLost = (ev: Event) => { console.warn('WebGL context lost'); setError('Graphics context lost'); ev.preventDefault(); }; const onContextRestored = () => { console.info('WebGL context restored'); setError(null); }; el.addEventListener('webglcontextlost', onContextLost as EventListener, false); el.addEventListener('webglcontextrestored', onContextRestored as EventListener, false); return () => { el.removeEventListener('webglcontextlost', onContextLost as EventListener, false); el.removeEventListener('webglcontextrestored', onContextRestored as EventListener, false); }; }, []); if (error) { return (
); } // If the provided URL is not a .splinecode, use an iframe fallback. This supports community/share links. if (!isSplineCode) { return (
{ready ? (