Communitygithub.com

phido0410/threejs-3d

Scènes 3D avec Three.js, React Three Fiber (R3F), helpers Drei, physique Rapier (@react-three/rapier) et effets de post-traitement (@react-three/postprocessing).

Qu'est-ce que threejs-3d ?

Ce skill fournit une stack 3D complète pour le web et la vidéo, combinant Three.js, React Three Fiber (R3F), les helpers Drei, la physique Rapier et les effets de post-traitement. Il est conçu pour les développeurs créant des scènes 3D interactives ou animées avec des modèles (GLTF), lumières, caméras, cartes d'environnement, physique et effets comme le bloom, le vignettage ou la profondeur de champ. La documentation détaille les imports, les règles d'architecture (comme l'utilisation de `<Suspense>` pour les ressources asynchrones, les tailles d'échelle recommandées et la gestion des matériaux sans lumière), ainsi que des extraits de code prêts à l'emploi pour chaque sous-système. Pour les projets vidéo avec Remotion, des instructions spécifiques sont fournies pour remplacer `useFrame` par `useCurrentFrame()` et éviter les helpers animés automatiquement, garantissant ainsi un rendu déterministe et reproductible.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/phido0410/claude-video-skills/tree/HEAD/skills/threejs-3d

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Stack 3D Three.js

Vérifié en 2026-10 : three 0.186, @react-three/fiber 9.8, @react-three/drei 10.7, @react-three/rapier 2.2, @react-three/postprocessing 3.2 (+ postprocessing 6.39). Fiber 9 / Drei 10 / Rapier 2 / postprocessing 3 nécessitent React 19 (fiber 9.8 peer : react >=19 <19.4).

npm i three @react-three/fiber @react-three/drei
npm i @react-three/rapier                         # physique
npm i @react-three/postprocessing postprocessing  # effets
npm i -D @types/three

Scène de base (web)

import { useRef, Suspense } from 'react'
import * as THREE from 'three'
import { Canvas, useFrame } from '@react-three/fiber'
import { OrbitControls, Environment, ContactShadows } from '@react-three/drei'

function Box() {
  const ref = useRef<THREE.Mesh>(null!)
  useFrame((_, delta) => { ref.current.rotation.y += delta }) // muter les refs, jamais setState par frame
  return (
    <mesh ref={ref} castShadow>
      <boxGeometry />
      <meshStandardMaterial color="#4a9eff" />
    </mesh>
  )
}

<Canvas camera={{ position: [3, 2, 5], fov: 45 }} dpr={[1, 2]} shadows>
  <ambientLight intensity={0.3} />
  <directionalLight position={[5, 5, 5]} castShadow />
  <Suspense fallback={null}>
    <Box />
    <Environment preset="city" />
  </Suspense>
  <ContactShadows position={[0, -0.5, 0]} opacity={0.5} blur={2} />
  <OrbitControls />
</Canvas>

Règles :

  • Tout ce qui est asynchrone (useGLTF, useTexture, Environment, polices Text, WASM physique) se trouve sous <Suspense>.
  • useGLTF.preload(url) au niveau du module pour les modèles utilisés au premier rendu.
  • Maintenez les scènes autour de 1–10 unités ; des échelles trop grandes ou trop petites cassent les ombres et les contrôles.
  • MeshStandardMaterial a besoin de lumière ou d'un <Environment> ; sans rien, il s'affiche en noir.

Drei (choisir ce qui est nécessaire)

  • Caméra/contrôles : OrbitControls, CameraControls, PerspectiveCamera makeDefault
  • Ressources : useGLTF, useTexture, Environment (presets : apartment, city, dawn, forest, lobby, night, park, studio, sunset, warehouse), Center, Bounds
  • Mise en scène : ContactShadows, AccumulativeShadows, Stage, Float, Sparkles, Stars, Cloud
  • Matériaux : MeshTransmissionMaterial (verre), MeshReflectorMaterial (sol réfléchissant)
  • Texte : Text (SDF, n'importe quelle URL de police), Text3D (nécessite JSON de typeface), Html (superposition DOM)

Physique Rapier

import { Physics, RigidBody, CuboidCollider, type RapierRigidBody } from '@react-three/rapier'

<Suspense>
  <Physics gravity={[0, -9.81, 0]} /* debug */>
    <RigidBody colliders="hull" restitution={0.6} ref={bodyRef}>
      <mesh><torusGeometry /><meshStandardMaterial /></mesh>
    </RigidBody>
    <RigidBody type="fixed">
      <CuboidCollider args={[10, 0.1, 10]} /> {/* demi-dimensions */}
    </RigidBody>
  </Physics>
</Suspense>
// bodyRef.current?.applyImpulse({ x: 0, y: 5, z: 0 }, true)
  • colliders : "cuboid" (par défaut), "ball", "hull", "trimesh", false (ajoutez vous-mêmes les composants de collision).
  • type : "dynamic" (par défaut), "fixed", "kinematicPosition", "kinematicVelocity".
  • timeStep par défaut à 1/60 fixe. timeStep="vary" n'est pas déterministe. Pas manuel : useRapier().step(1 / 60).
  • debug sur <Physics> dessine les collisions.

Post-traitement

import { EffectComposer, Bloom, Vignette, DepthOfField, Noise } from '@react-three/postprocessing'

<EffectComposer>{/* dernier enfant de <Canvas> */}
  <Bloom luminanceThreshold={0.9} intensity={1.2} mipmapBlur />
  <Vignette offset={0.1} darkness={0.9} />
</EffectComposer>
  • Bloom ne capture que les pixels au-dessus de luminanceThreshold. Pour faire briller un objet : couleur emissive + emissiveIntensity > 1 + toneMapped={false} sur son matériau.
  • Chaque effet coûte un passage plein écran ; 2 à 4 effets suffisent.

Pour la vidéo

Remotion (voir remotion-markup/3d.md) : <ThreeCanvas width height> depuis @remotion/three ; pas de useFrame ; chaque mouvement provient de useCurrentFrame(). De plus :

  • Pas de OrbitControls — déplacez la caméra depuis frame (interpolate / spring).
  • Les helpers Drei qui s'animent sur leur propre horloge (Float, Sparkles, Stars, Cloud, MeshWobbleMaterial) scintillent dans les rendus. Laissez-les de côté ou reproduisez le mouvement depuis frame.
  • Physique : Remotion rend les images dans le désordre entre les onglets, donc une simulation en direct ne peut pas correspondre. Figez-la : initialisez @dimforge/rapier3d-compat (le moteur sous @react-three/rapier) une fois, world.step() avec timestep = 1 / fps pour chaque image, stockez la position + rotation de chaque corps par image, puis rendez les transformations à l'indice frame.

En dehors de Remotion (enregistrement écran, piloté par GSAP) : useFrame est acceptable ; pilotez le temps depuis une timeline (tl.time()) au lieu de delta lorsque le plan doit être reproductible.

Individual skills in this repo

This repo contains 3 individual skills — each has its own dedicated page.

Skills associés