forked from blackboxo/christmas-tree
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathApp.tsx
More file actions
93 lines (79 loc) · 3.28 KB
/
Copy pathApp.tsx
File metadata and controls
93 lines (79 loc) · 3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import React, { useState, Suspense } from 'react';
import { Canvas } from '@react-three/fiber';
import { Loader } from '@react-three/drei';
import { Experience } from './components/Experience';
import { UIOverlay } from './components/UIOverlay';
import { GestureController } from './components/GestureController';
import { TreeMode } from './types';
// Simple Error Boundary to catch 3D resource loading errors (like textures)
class ErrorBoundary extends React.Component<{children: React.ReactNode}, {hasError: boolean}> {
constructor(props: any) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error: any) {
return { hasError: true };
}
componentDidCatch(error: any, errorInfo: any) {
console.error("Error loading 3D scene:", error, errorInfo);
}
render() {
if (this.state.hasError) {
// You can customize this fallback UI
return (
<div className="absolute inset-0 z-50 flex items-center justify-center bg-black/80 text-[#D4AF37] font-serif p-8 text-center">
<div>
<h2 className="text-2xl mb-2">Something went wrong</h2>
<p className="opacity-70">A resource failed to load (likely a missing image). Check the console for details.</p>
<button
onClick={() => this.setState({ hasError: false })}
className="mt-4 px-4 py-2 border border-[#D4AF37] hover:bg-[#D4AF37] hover:text-black transition-colors"
>
Try Again
</button>
</div>
</div>
);
}
return this.props.children;
}
}
export default function App() {
const [mode, setMode] = useState<TreeMode>(TreeMode.FORMED);
const [handPosition, setHandPosition] = useState<{ x: number; y: number; detected: boolean }>({ x: 0.5, y: 0.5, detected: false });
const [uploadedPhotos, setUploadedPhotos] = useState<string[]>([]);
const toggleMode = () => {
setMode((prev) => (prev === TreeMode.FORMED ? TreeMode.CHAOS : TreeMode.FORMED));
};
const handleHandPosition = (x: number, y: number, detected: boolean) => {
setHandPosition({ x, y, detected });
};
const handlePhotosUpload = (photos: string[]) => {
setUploadedPhotos(photos);
};
return (
<div className="w-full h-screen relative bg-gradient-to-b from-black via-[#001a0d] to-[#0a2f1e]">
<ErrorBoundary>
<Canvas
dpr={[1, 2]}
camera={{ position: [0, 4, 20], fov: 45 }}
gl={{ antialias: false, stencil: false, alpha: false }}
shadows
>
<Suspense fallback={null}>
<Experience mode={mode} handPosition={handPosition} uploadedPhotos={uploadedPhotos} />
</Suspense>
</Canvas>
</ErrorBoundary>
<Loader
containerStyles={{ background: '#000' }}
innerStyles={{ width: '300px', height: '10px', background: '#333' }}
barStyles={{ background: '#D4AF37', height: '10px' }}
dataStyles={{ color: '#D4AF37', fontFamily: 'Cinzel' }}
/>
<UIOverlay mode={mode} onToggle={toggleMode} onPhotosUpload={handlePhotosUpload} hasPhotos={uploadedPhotos.length > 0} />
{/* Gesture Control Module */}
<GestureController currentMode={mode} onModeChange={setMode} onHandPosition={handleHandPosition} />
</div>
);
}