D’abord la règle, ensuite le graphisme
Un prototype sans aucune texture, mais avec la bonne règle, en dit plus qu’une belle scène sans enjeu. Dans le jeu d’enquête, la règle signifie cinq personnages, huit indices dont trois sont des preuves solides, quatre motifs, quatre fins et une horloge de 72 heures dans laquelle chaque réplique coupe 10 minutes, et un déplacement 30. Les heures 00:00–07:00 sont sautées automatiquement, afin que l’horloge ne se consume pas pendant le sommeil.
La scène dans le navigateur, sur Three.js
La même bibliothèque dans cinq dépôts : Three.js 0.184–0.185, parfois via `@react-three/fiber` et `@react-three/drei`, parfois écrite directement. Deux projets utilisent la variante React ; deux autres écrivent Three.js pur, jusqu’au niveau où nous gérons manuellement les attributs de buffer. Le plus grand moteur interne a 1.824 lignes et dessine tous les satellites comme un seul objet `THREE.Points`, avec les attributs de position, couleur, taille et transparence mis à jour sur place, image par image.
Rendu qui baisse de lui-même sur les appareils faibles
Le shader de ce site comporte trois paliers : `low` avec 24 itérations de raymarching et un rapport de pixels 0,5, `medium` avec 40 et 0,65, `high` avec 80, une précision `highp` et un rapport plafonné à 2. Le choix est automatique : sur mobile il descend à `low`, et tout appareil de 4 cœurs ou moins le rétrograde de `high` à `medium`. Si WebGL est absent, le composant s’éteint proprement au lieu de lancer une erreur. La même discipline dans les autres projets : plafond 1,6 dans la scène de ville et 1,75 dans celle de terrain, 1,5 sur mobile dans le démonstrateur de monde, avec la boucle de rendu arrêtée lorsque le canvas sort de l’écran.
De grandes scènes qui restent un seul dessin
Une ville avec 9.506 bâtiments ne veut pas dire 9.506 objets. Chaque empreinte d’OpenStreetMap devient une `ExtrudeGeometry` sans chanfrein et avec `curveSegments: 1`, reçoit la couleur écrite directement dans les sommets, son attribut `uv` est supprimé — puis le tout est fusionné en une seule géométrie via `mergeGeometries`. Les anneaux géométriques dégénérés provenant des données publiques sont ignorés avec `try`/`catch`, et non laissés pour faire tomber la page.
Des personnages qui mentent, se souviennent et cèdent selon les conditions
La vérité de l’affaire ne se trouve pas dans la page. Les dossiers des cinq personnages — biographie, secret, condition dans laquelle il se brise — se trouvent dans un fichier qui commence par `import "server-only"` et ne peut pas être importé depuis le client. Le personnage signale un indice débloqué par un tag que le joueur ne voit pas, et le serveur ne l’accepte que si ce personnage a le droit de donner cet indice. Un modèle qui invente un indice qui ne lui appartient pas est ignoré, et non cru.
La langue comme mécanique, pas comme traduction
Un personnage répond brièvement et sur la défensive en roumain, mais en russe il devient loquace et dangereusement sincère — la règle est écrite dans son dossier, et la première réplique en russe augmente sa confiance. Le microphone suit la même langue (`ru-RU` ou `ro-RO`). Là où la localisation est classique, nous allons plus loin : la simulation de robots a huit langues, avec l’arabe explicitement marqué comme écriture de droite à gauche.
Simulation avec des formules, pas avec des impressions
La hauteur du saut se met à l’échelle avec le rapport des gravités, la période de marche avec 2π√(L/g), le nombre de Froude avec v²/(g·L), et la résistance de l’air avec la densité atmosphérique de la planète. L’autonomie de la batterie passe par une fonction de décroissance selon la température avec quatre seuils : au-dessus de 20 °C inchangée, au-dessus de 0 °C `0,85 + 0,0075·T`, au-dessus de −20 °C `0,55 + 0,015·T`, au-dessus de −40 °C `0,12 + 0,02·T`, et en dessous 5 %. La marche est une cinématique inverse à deux segments, résolue par la loi des cosinus, avec un facteur d’appui de 0,6 par cycle.
Son et voix construits, non téléchargés
L’atmosphère du jeu d’enquête ne contient aucun fichier audio : la pluie est un bruit rose filtré passe-bas à 1.400 Hz et passe-haut à 300 Hz, bouclé ; le crépitement du vinyle est fait d’impulsions courtes générées toutes les 180 ms ; le tonnerre est une explosion de bruit à décroissance exponentielle, programmée à 18–48 secondes. La pluie visuelle est un canvas 2D séparé, jusqu’à 180 gouttes inclinées. La voix fonctionne dans les deux sens : dictée via l’interface de reconnaissance du navigateur et répliques synthétisées par personnage via ElevenLabs `eleven_multilingual_v2`, MP3 44,1 kHz / 128 kbps.
Format de modèle 3D pour lequel il n’existe pas encore de chargeur prêt à l’emploi
Les robots Unitree G1 et Go2 viennent en MJCF, le format MuJoCo, qui ne dispose pas d’un chargeur standard pour Three.js. Je l’ai écrit : 170 lignes qui lisent le XML, reconstruisent la hiérarchie des corps, extraient chaque articulation avec son axe et son intervalle, et chargent la géométrie via `STLLoader` et `OBJLoader`. Dans la scène entrent 67 fichiers de mesh, 62 MB — 29 articulations actionnées pour l’humanoïde, 12 pour le quadrupède, comptées dans le bloc `<actuator>` de chaque modèle.