--- id: frontend-three-r3f title: Three.js / React Three Fiber — 3D 웹 category: Coding status: draft source_trust_level: B verification_status: conceptual created_at: 2026-05-09 updated_at: 2026-05-09 tags: [frontend, 3d, threejs, r3f, vibe-coding] tech_stack: { language: "TS / React", applicable_to: ["Frontend"] } applied_in: [] aliases: [Three.js, React Three Fiber, drei, Rapier, Spline, WebGL] --- # Three.js / R3F (React Three Fiber) > Web 3D 표준. **Three.js (vanilla) / React Three Fiber (React)** + **drei (helpers)** + **Rapier (physics)**. WebGL → WebGPU 미래. ## 📖 핵심 개념 - Scene: 3D 공간. - Mesh: geometry + material. - Camera: 시점. - Light: 조명. - Renderer: WebGL / WebGPU. ## 💻 코드 패턴 ### 기본 R3F ```tsx import { Canvas, useFrame } from '@react-three/fiber'; import { OrbitControls, Box } from '@react-three/drei'; import { useRef } from 'react'; function RotatingBox() { const ref = useRef(null); useFrame((_, delta) => { ref.current!.rotation.y += delta; }); return ( ); } export function Scene() { return ( ); } ``` ### drei (helpers) ```tsx import { OrbitControls, Environment, ContactShadows, Float, Text, Html, useGLTF, useTexture, PerspectiveCamera, Stage, } from '@react-three/drei'; ... Hello 3D
HTML overlay
``` ### GLTF 모델 로드 ```tsx function Model() { const { scene, animations } = useGLTF('/model.glb'); return ; } // Optimization — useGLTF preload useGLTF.preload('/model.glb'); ``` → DRACO compression 자동 (drei 가). ### Animation (모델) ```tsx import { useAnimations } from '@react-three/drei'; function AnimatedModel() { const ref = useRef(null); const { scene, animations } = useGLTF('/dancer.glb'); const { actions } = useAnimations(animations, ref); useEffect(() => { actions.idle?.play(); }, []); return ; } ``` ### Physics (Rapier) ```tsx import { Physics, RigidBody } from '@react-three/rapier'; ``` ### Material ```tsx // MeshPhysicalMaterial — 더 사실적 ``` ### Shader (custom GLSL) ```glsl // vertex.glsl varying vec2 vUv; void main() { vUv = uv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } // fragment.glsl varying vec2 vUv; uniform float uTime; void main() { vec3 color = vec3(sin(vUv.x + uTime), sin(vUv.y + uTime), 1.0); gl_FragColor = vec4(color, 1.0); } ``` ```tsx ``` ### Post-processing ```tsx import { EffectComposer, Bloom, ChromaticAberration } from '@react-three/postprocessing'; ``` ### Performance ```tsx // Instances (수천 mesh) import { Instances, Instance } from '@react-three/drei'; {data.map((d, i) => ( ))} ``` ```tsx // LOD (Level of Detail) import { Detailed } from '@react-three/drei'; ``` ```tsx // Frustum culling 자동 // Manual: ref.current.frustumCulled = true (default) // Shadows — 비싸. 작은 set 만 ``` ### Mobile / WebGL fallback ```tsx // 작은 화면 / GPU = quality down const isMobile = useMediaQuery('(max-width: 768px)'); ``` ### WebGPU (미래) ```tsx import { WebGPURenderer } from 'three/examples/jsm/renderers/webgpu/WebGPURenderer.js'; new WebGPURenderer({ canvas })} > ``` → WebGL 보다 빠름. 2025+ stable. ### React-spring + R3F ```tsx import { useSpring, animated } from '@react-spring/three'; const { position } = useSpring({ position: hovered ? [0, 1, 0] : [0, 0, 0] }); ``` ### 화면 → 3D coordinates ```ts import { useThree } from '@react-three/fiber'; function ClickToWorld() { const { camera, raycaster, mouse } = useThree(); const handle = (e: MouseEvent) => { raycaster.setFromCamera(mouse, camera); // raycaster.ray 로 intersection }; } ``` ### Spline (no-code 3D) ```tsx import Spline from '@splinetool/react-spline'; ``` → Designer 가 Spline app 에서 만들고 R3F 가 import. ### Bundle size 주의 ``` Three.js: ~600KB (큰) + drei, postprocessing, rapier ... → Dynamic import + code split ``` ```tsx const Scene = lazy(() => import('./Scene')); }> ``` ## 🤔 의사결정 기준 | 상황 | 추천 | |---|---| | Product showcase | R3F + drei + GLTF | | Game | R3F + Rapier physics | | Data viz | R3F + custom shader | | Designer 만든 scene | Spline | | 매우 simple (1-2 model) | | | 강력 / vanilla | Three.js direct | ## ❌ 안티패턴 - **모든 frame setState**: re-render. useFrame 안 ref. - **Shadow 모든 light + 큰 mapSize**: 60fps 깨짐. - **너무 많은 mesh (1000+)**: Instances. - **모델 압축 안 함 (GLB 100MB)**: load 느림. DRACO + Meshopt. - **WebGL fallback 없음 + GPU 약**: blank 화면. - **Mobile 무 dpr 2**: 발열. - **Memory leak (useEffect cleanup 없음)**: GPU resources 안 release. ## 🤖 LLM 활용 힌트 - R3F + drei + Rapier 가 표준 stack. - GLTF + DRACO compression. - Instances / LOD / shadow 절제. - Suspense + lazy load. ## 🔗 관련 문서 - [[Frontend_Animation_Motion]] - [[Web_Performance_Core_Vitals]] - [[Perf_Bundle_Analysis]]