# Three.js & React Three Fiber für 3D Web

**Meta-Description:** 3D Webentwicklung mit Three.js und React Three Fiber. WebGL/WebGPU, interaktive Szenen und Performance-Optimierung.

**Keywords:** Three.js, React Three Fiber, 3D Web, WebGL, WebGPU, R3F, Drei, Interactive 3D

---

## Einführung

**Three.js** dominiert die 3D-Webentwicklung mit 270x mehr Downloads als Alternativen. **React Three Fiber** (R3F) bringt die deklarative React-Syntax in die 3D-Welt – perfekt für moderne Web-Projekte mit interaktiven Visualisierungen.

---

## Architecture Overview

```
┌─────────────────────────────────────────────────────────────┐
│              THREE.JS / R3F ARCHITECTURE                     │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Application Layer:                                         │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  React Components / Hooks / State                    │   │
│  └─────────────────────────────────────────────────────┘   │
│                           │                                 │
│  R3F Layer:               ▼                                 │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  React Three Fiber (React Renderer for Three.js)    │   │
│  │  ┌─────────┐  ┌─────────┐  ┌─────────┐            │   │
│  │  │ Canvas  │  │ Hooks   │  │ Events  │            │   │
│  │  │ (Root)  │  │ (Frame) │  │(Pointer)│            │   │
│  │  └─────────┘  └─────────┘  └─────────┘            │   │
│  └─────────────────────────────────────────────────────┘   │
│                           │                                 │
│  Drei (Helpers):          │                                 │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  OrbitControls | Environment | Text3D | useGLTF    │   │
│  └─────────────────────────────────────────────────────┘   │
│                           │                                 │
│  Three.js Core:           ▼                                 │
│  ┌─────────────────────────────────────────────────────┐   │
│  │  Scene | Camera | Renderer | Lights | Geometries   │   │
│  └─────────────────────────────────────────────────────┘   │
│                           │                                 │
│  Graphics API:            ▼                                 │
│  ┌───────────────────┬────────────────────┐               │
│  │      WebGL 2      │      WebGPU        │               │
│  │   (Supported)     │   (2026 Ready)     │               │
│  └───────────────────┴────────────────────┘               │
│                                                             │
└─────────────────────────────────────────────────────────────┘
```

---

## Setup & Installation

```bash
# React Three Fiber + Drei (Helpers)
npm install three @react-three/fiber @react-three/drei

# TypeScript Types
npm install -D @types/three

# Optional: Post-Processing, Physics
npm install @react-three/postprocessing
npm install @react-three/cannon
```

```typescript
// next.config.js (für Next.js)
const nextConfig = {
  transpilePackages: ['three'],
  webpack: (config) => {
    config.externals.push({
      'sharp': 'commonjs sharp',
      'canvas': 'commonjs canvas',
    });
    return config;
  }
};
```

---

## Basic Scene mit R3F

```tsx
// components/Scene.tsx
'use client';

import { Canvas } from '@react-three/fiber';
import { OrbitControls, Environment, PerspectiveCamera } from '@react-three/drei';
import { Suspense } from 'react';

export function Scene() {
  return (
    <Canvas>
      <PerspectiveCamera makeDefault position={[0, 2, 5]} />
      <OrbitControls enableDamping dampingFactor={0.05} />

      <Suspense fallback={<LoadingBox />}>
        <Environment preset="sunset" />
        <ambientLight intensity={0.5} />
        <directionalLight position={[10, 10, 5]} intensity={1} castShadow />

        <RotatingBox position={[-1.5, 0, 0]} />
        <FloatingSphere position={[1.5, 0, 0]} />
        <Floor />
      </Suspense>
    </Canvas>
  );
}

function LoadingBox() {
  return (
    <mesh>
      <boxGeometry args={[1, 1, 1]} />
      <meshBasicMaterial color="gray" wireframe />
    </mesh>
  );
}
```

---

## Interaktive Objekte

```tsx
// components/InteractiveObjects.tsx
'use client';

import { useRef, useState } from 'react';
import { useFrame } from '@react-three/fiber';
import { MeshWobbleMaterial, RoundedBox, Text } from '@react-three/drei';
import * as THREE from 'three';

interface BoxProps {
  position: [number, number, number];
}

export function RotatingBox({ position }: BoxProps) {
  const meshRef = useRef<THREE.Mesh>(null);
  const [hovered, setHovered] = useState(false);
  const [clicked, setClicked] = useState(false);

  useFrame((state, delta) => {
    if (meshRef.current) {
      meshRef.current.rotation.x += delta * 0.5;
      meshRef.current.rotation.y += delta * 0.3;

      // Hover Animation
      const scale = hovered ? 1.2 : 1;
      meshRef.current.scale.lerp(new THREE.Vector3(scale, scale, scale), 0.1);
    }
  });

  return (
    <mesh
      ref={meshRef}
      position={position}
      onClick={() => setClicked(!clicked)}
      onPointerOver={() => setHovered(true)}
      onPointerOut={() => setHovered(false)}
    >
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial
        color={clicked ? '#ff6b6b' : hovered ? '#4ecdc4' : '#45b7d1'}
        metalness={0.5}
        roughness={0.2}
      />
    </mesh>
  );
}

export function FloatingSphere({ position }: BoxProps) {
  const meshRef = useRef<THREE.Mesh>(null);

  useFrame((state) => {
    if (meshRef.current) {
      // Floating Animation
      meshRef.current.position.y = position[1] + Math.sin(state.clock.elapsedTime) * 0.3;
    }
  });

  return (
    <mesh ref={meshRef} position={position}>
      <sphereGeometry args={[0.7, 32, 32]} />
      <MeshWobbleMaterial
        color="#9b59b6"
        metalness={0.8}
        roughness={0.1}
        factor={0.5}  // Wobble Intensity
        speed={2}     // Wobble Speed
      />
    </mesh>
  );
}

export function Floor() {
  return (
    <mesh rotation={[-Math.PI / 2, 0, 0]} position={[0, -1, 0]} receiveShadow>
      <planeGeometry args={[20, 20]} />
      <meshStandardMaterial color="#1a1a2e" metalness={0.2} roughness={0.8} />
    </mesh>
  );
}
```

---

## 3D Model Loading (GLTF)

```tsx
// components/Model.tsx
'use client';

import { useRef, useEffect } from 'react';
import { useGLTF, useAnimations, Clone } from '@react-three/drei';
import { useFrame } from '@react-three/fiber';
import * as THREE from 'three';

interface ModelProps {
  url: string;
  position?: [number, number, number];
  scale?: number;
  animate?: boolean;
}

export function Model({ url, position = [0, 0, 0], scale = 1, animate = true }: ModelProps) {
  const group = useRef<THREE.Group>(null);
  const { scene, animations } = useGLTF(url);
  const { actions, names } = useAnimations(animations, group);

  useEffect(() => {
    // Erste Animation abspielen
    if (animate && names.length > 0) {
      actions[names[0]]?.play();
    }
  }, [actions, names, animate]);

  // Shadow Setup
  useEffect(() => {
    scene.traverse((child) => {
      if (child instanceof THREE.Mesh) {
        child.castShadow = true;
        child.receiveShadow = true;
      }
    });
  }, [scene]);

  return (
    <group ref={group} position={position} scale={scale}>
      <Clone object={scene} />
    </group>
  );
}

// Preload für bessere Performance
useGLTF.preload('/models/robot.glb');

// Mit Draco Compression
export function CompressedModel({ url }: { url: string }) {
  const { scene } = useGLTF(url, true);  // true = Draco Loader
  return <primitive object={scene} />;
}
```

---

## Custom Shaders

```tsx
// components/CustomShader.tsx
'use client';

import { useRef, useMemo } from 'react';
import { useFrame, extend } from '@react-three/fiber';
import { shaderMaterial } from '@react-three/drei';
import * as THREE from 'three';

// Custom Shader Material
const GradientMaterial = shaderMaterial(
  // Uniforms
  {
    uTime: 0,
    uColor1: new THREE.Color('#ff0000'),
    uColor2: new THREE.Color('#0000ff'),
    uIntensity: 1.0
  },
  // Vertex Shader
  `
    varying vec2 vUv;
    varying vec3 vPosition;

    void main() {
      vUv = uv;
      vPosition = position;
      gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
  `,
  // Fragment Shader
  `
    uniform float uTime;
    uniform vec3 uColor1;
    uniform vec3 uColor2;
    uniform float uIntensity;
    varying vec2 vUv;
    varying vec3 vPosition;

    void main() {
      // Animated Gradient
      float mixValue = sin(vUv.y * 3.14159 + uTime) * 0.5 + 0.5;
      vec3 color = mix(uColor1, uColor2, mixValue);

      // Wave Effect
      float wave = sin(vPosition.x * 5.0 + uTime * 2.0) * 0.1;
      color += wave * uIntensity;

      gl_FragColor = vec4(color, 1.0);
    }
  `
);

// Extend für JSX Support
extend({ GradientMaterial });

// TypeScript Declaration
declare global {
  namespace JSX {
    interface IntrinsicElements {
      gradientMaterial: any;
    }
  }
}

export function ShaderSphere() {
  const materialRef = useRef<any>(null);

  useFrame((state) => {
    if (materialRef.current) {
      materialRef.current.uTime = state.clock.elapsedTime;
    }
  });

  return (
    <mesh>
      <sphereGeometry args={[1, 64, 64]} />
      <gradientMaterial
        ref={materialRef}
        uColor1="#ff6b6b"
        uColor2="#4ecdc4"
        uIntensity={0.5}
      />
    </mesh>
  );
}
```

---

## Post-Processing Effects

```tsx
// components/PostProcessing.tsx
'use client';

import { EffectComposer, Bloom, ChromaticAberration, Vignette } from '@react-three/postprocessing';
import { BlendFunction } from 'postprocessing';

export function Effects() {
  return (
    <EffectComposer>
      {/* Bloom für leuchtende Effekte */}
      <Bloom
        intensity={1.5}
        luminanceThreshold={0.9}
        luminanceSmoothing={0.025}
        mipmapBlur
      />

      {/* Chromatische Aberration */}
      <ChromaticAberration
        blendFunction={BlendFunction.NORMAL}
        offset={[0.002, 0.002]}
      />

      {/* Vignette */}
      <Vignette
        offset={0.3}
        darkness={0.5}
        blendFunction={BlendFunction.NORMAL}
      />
    </EffectComposer>
  );
}

// Verwendung
function SceneWithEffects() {
  return (
    <Canvas>
      <Scene />
      <Effects />
    </Canvas>
  );
}
```

---

## Physics mit Cannon

```tsx
// components/PhysicsScene.tsx
'use client';

import { Physics, usePlane, useBox, useSphere } from '@react-three/cannon';
import { useRef } from 'react';
import * as THREE from 'three';

export function PhysicsScene() {
  return (
    <Physics gravity={[0, -9.81, 0]}>
      <PhysicsGround />
      <PhysicsBox position={[0, 5, 0]} />
      <PhysicsBox position={[0.5, 7, 0]} />
      <PhysicsBall position={[-0.5, 10, 0]} />
    </Physics>
  );
}

function PhysicsGround() {
  const [ref] = usePlane<THREE.Mesh>(() => ({
    rotation: [-Math.PI / 2, 0, 0],
    position: [0, 0, 0]
  }));

  return (
    <mesh ref={ref} receiveShadow>
      <planeGeometry args={[20, 20]} />
      <meshStandardMaterial color="#333" />
    </mesh>
  );
}

function PhysicsBox({ position }: { position: [number, number, number] }) {
  const [ref] = useBox<THREE.Mesh>(() => ({
    mass: 1,
    position,
    args: [1, 1, 1]
  }));

  return (
    <mesh ref={ref} castShadow>
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial color="#ff6b6b" />
    </mesh>
  );
}

function PhysicsBall({ position }: { position: [number, number, number] }) {
  const [ref] = useSphere<THREE.Mesh>(() => ({
    mass: 2,
    position,
    args: [0.5]
  }));

  return (
    <mesh ref={ref} castShadow>
      <sphereGeometry args={[0.5, 32, 32]} />
      <meshStandardMaterial color="#4ecdc4" />
    </mesh>
  );
}
```

---

## Performance Optimierung

```tsx
// components/OptimizedScene.tsx
'use client';

import { useRef, useMemo } from 'react';
import { useFrame } from '@react-three/fiber';
import { Instances, Instance, Detailed, useGLTF } from '@react-three/drei';
import * as THREE from 'three';

// Instancing für viele gleiche Objekte
export function InstancedCubes({ count = 1000 }) {
  const positions = useMemo(() => {
    return Array.from({ length: count }, () => ({
      position: [
        (Math.random() - 0.5) * 20,
        (Math.random() - 0.5) * 20,
        (Math.random() - 0.5) * 20
      ] as [number, number, number],
      rotation: [
        Math.random() * Math.PI,
        Math.random() * Math.PI,
        Math.random() * Math.PI
      ] as [number, number, number],
      scale: 0.5 + Math.random() * 0.5
    }));
  }, [count]);

  return (
    <Instances limit={count} castShadow receiveShadow>
      <boxGeometry args={[1, 1, 1]} />
      <meshStandardMaterial color="#45b7d1" />
      {positions.map((props, i) => (
        <Instance
          key={i}
          position={props.position}
          rotation={props.rotation}
          scale={props.scale}
        />
      ))}
    </Instances>
  );
}

// Level of Detail (LOD)
export function LODModel() {
  return (
    <Detailed distances={[0, 10, 25, 50]}>
      {/* Höchste Qualität (nah) */}
      <mesh>
        <sphereGeometry args={[1, 64, 64]} />
        <meshStandardMaterial color="red" />
      </mesh>

      {/* Mittlere Qualität */}
      <mesh>
        <sphereGeometry args={[1, 32, 32]} />
        <meshStandardMaterial color="red" />
      </mesh>

      {/* Niedrige Qualität */}
      <mesh>
        <sphereGeometry args={[1, 16, 16]} />
        <meshStandardMaterial color="red" />
      </mesh>

      {/* Sehr niedrige Qualität (weit) */}
      <mesh>
        <sphereGeometry args={[1, 8, 8]} />
        <meshStandardMaterial color="red" />
      </mesh>
    </Detailed>
  );
}

// Lazy Loading
import { lazy, Suspense } from 'react';

const HeavyModel = lazy(() => import('./HeavyModel'));

export function LazyScene() {
  return (
    <Suspense fallback={<LoadingIndicator />}>
      <HeavyModel />
    </Suspense>
  );
}
```

---

## Best Practices

| Aspect | Recommendation |
|--------|----------------|
| **Geometry** | Instancing für viele gleiche Objekte |
| **Textures** | Compressed (WebP), Power of 2 |
| **Models** | Draco compression, LOD |
| **Shadows** | Nur wo nötig, Shadow Map Size |
| **Animations** | useFrame statt setInterval |
| **State** | Zustand außerhalb des Render Loops |
| **Cleanup** | dispose() für Geometries/Materials |

---

## Fazit

Three.js + React Three Fiber bietet:

1. **Deklarative Syntax**: React-Komponenten für 3D
2. **Ecosystem**: Drei, Cannon, Postprocessing
3. **WebGPU Ready**: Zukunftssicher mit WebGPU Support
4. **Performance**: Instancing, LOD, Lazy Loading

Die beste Kombination für 3D im Web.

---

## Bildprompts

1. "Interactive 3D scene with rotating objects, React Three Fiber demo"
2. "WebGL shader effect with gradient colors, custom material"
3. "Physics simulation with falling objects, cannon.js integration"

---

## Quellen

- [React Three Fiber Documentation](https://docs.pmnd.rs/react-three-fiber)
- [Three.js Journey](https://threejs-journey.com/)
- [Drei Helpers](https://github.com/pmndrs/drei)
- [What's New in Three.js 2026](https://www.utsubo.com/blog/threejs-2026-what-changed)
