Najpierw reguła, potem grafika
Prototyp bez żadnej tekstury, ale z poprawną regułą, mówi więcej niż ładna scena bez stawki. W grze detektywistycznej reguła oznacza pięć postaci, osiem wskazówek, z których trzy są twardym dowodem, cztery motywy, cztery zakończenia i zegar 72-godzinny, w którym każda kwestia skraca czas o 10 minut, a przemieszczenie o 30. Godziny 00:00–07:00 są pomijane automatycznie, żeby zegar nie zużywał się we śnie.
Scena w przeglądarce, w Three.js
Ta sama biblioteka w pięciu repozytoriach: Three.js 0.184–0.185, czasem przez `@react-three/fiber` i `@react-three/drei`, czasem pisana bezpośrednio. Dwa projekty używają wariantu React; dwa inne piszą czysty Three.js, aż do poziomu, na którym ręcznie zarządzamy atrybutami bufora. Największy własny silnik ma 1.824 linie i rysuje wszystkie satelity jako jeden obiekt `THREE.Points`, z atrybutami pozycji, koloru, rozmiaru i przezroczystości aktualizowanymi na miejscu, klatka po klatce.
Renderowanie, które samo obniża jakość na słabszych urządzeniach
Shader na tej stronie ma trzy poziomy: `low` z 24 iteracjami raymarchingu i współczynnikiem pikseli 0,5, `medium` z 40 i 0,65, `high` z 80, precyzją `highp` i współczynnikiem ograniczonym do 2. Wybór jest automatyczny: na telefonie spada do `low`, a każde urządzenie z 4 rdzeniami lub mniej jest degradowane z `high` do `medium`. Jeśli brakuje WebGL, komponent wygasza się poprawnie zamiast rzucać błędem. Ta sama dyscyplina w innych projektach: limit 1,6 w scenie miasta i 1,75 w scenie terenu, 1,5 na telefonie w demonstratorze świata, z pętlą renderowania zatrzymaną, gdy canvas znika z ekranu.
Duże sceny, które pozostają jednym rysunkiem
Miasto z 9.506 budynkami nie oznacza 9.506 obiektów. Każdy ślad z OpenStreetMap staje się `ExtrudeGeometry` bez fazowania i z `curveSegments: 1`, dostaje kolor zapisany bezpośrednio w wierzchołkach, ma usuwany atrybut `uv` — a potem wszystko scala się w jedną geometrię przez `mergeGeometries`. Zdegenerowane pierścienie geometryczne z danych publicznych są pomijane przez `try`/`catch`, a nie zostawiane, by przewróciły stronę.
Postacie, które kłamią, pamiętają i ulegają warunkom
Prawda sprawy nie leży na stronie. Akta pięciu postaci — biografia, sekret, warunek, przy którym pęka — znajdują się w pliku, który zaczyna się od `import "server-only"` i nie może zostać zaimportowany z klienta. Postać sygnalizuje odblokowaną wskazówkę przez tag, którego gracz nie widzi, a serwer akceptuje to tylko wtedy, gdy ta postać ma prawo przekazać tę wskazówkę. Model, który wymyśla wskazówkę nie należącą do niego, jest ignorowany, a nie uznawany.
Język jako mechanika, a nie tłumaczenie
Postać odpowiada krótko i defensywnie po rumuńsku, ale po rosyjsku staje się gadatliwa i niebezpiecznie szczera — reguła jest zapisana w jej aktach, a pierwsza wypowiedź po rosyjsku zwiększa jej pewność siebie. Mikrofon podąża za tym samym językiem (`ru-RU` lub `ro-RO`). Tam, gdzie lokalizacja jest klasyczna, idziemy dalej: symulacja robotów ma osiem języków, z arabskim wyraźnie oznaczonym jako zapis od prawej do lewej.
Symulacja z formułami, a nie z wrażeniami
Wysokość skoku skaluje się stosunkiem grawitacji, okres chodu z 2π√(L/g), liczba Froude’a z v²/(g·L), a opór powietrza z gęstością atmosfery planety. Autonomia baterii przechodzi przez funkcję spadku zależną od temperatury z czterema progami: powyżej 20 °C bez zmian, powyżej 0 °C `0,85 + 0,0075·T`, powyżej −20 °C `0,55 + 0,015·T`, powyżej −40 °C `0,12 + 0,02·T`, a poniżej tego 5 %. Chód to kinematyka odwrotna z dwoma segmentami, rozwiązana przez twierdzenie cosinusów, ze współczynnikiem podparcia 0,6 na cykl.
Dźwięk i głos zbudowane, a nie pobrane
Atmosfera gry detektywistycznej nie ma żadnego pliku audio: deszcz to różowy szum filtrowany dolnoprzepustowo do 1.400 Hz i górnoprzepustowo do 300 Hz, zapętlony; trzaski winylu to krótkie impulsy generowane co 180 ms; grzmot to wybuch szumu z wykładniczym zanikiem, zaprogramowany na 18–48 sekund. Deszcz wizualny to osobny canvas 2D, do 180 pochylonych kropli. Głos działa w obie strony: dyktowanie przez interfejs rozpoznawania mowy przeglądarki i repliki syntetyzowane per postać przez ElevenLabs `eleven_multilingual_v2`, MP3 44,1 kHz / 128 kbps.
Format modelu 3D, dla którego nie ma jeszcze gotowego loadera
Roboty Unitree G1 i Go2 przychodzą w MJCF, formacie MuJoCo, który nie ma standardowego loadera dla Three.js. Napisałem go: 170 linii, które czytają XML, odbudowują hierarchię ciał, wyodrębniają każdy przegub z osią i zakresem oraz ładują geometrię przez `STLLoader` i `OBJLoader`. Do sceny trafia 67 plików mesh, 62 MB — 29 napędzanych przegubów w humanoidzie, 12 w czworonożnym, policzonych w bloku `<actuator>` każdego modelu.