Notes de développement de « Machine » de xkcd
Concept initial
- Une idée mûrie jusqu’à fin mars, puis retenue début avril
- « Et si on construisait un gigantesque dispositif en tuiles, comme le GIF Blue Ball créé par les utilisateurs de Something Awful ? Chacun contribuerait avec un petit rectangle. »
- Au départ, l’idée semblait déjà bien formée, mais en en discutant réellement, il est devenu clair qu’il restait encore beaucoup de décisions à prendre
- Nous n’avions pas tous la même vision sur des points essentiels : d’où viennent les balles, est-ce que tout le monde voit la même machine, quel est l’objectif, comment les joueurs interagissent, etc.
Ce que les tentatives précédentes ont appris
- Il y avait déjà une expérience de création de BD interactives centrées sur le contenu produit par les utilisateurs
- Lorenz : un exquis cadavre où les lecteurs écrivaient le texte des cases pour faire évoluer les blagues et l’histoire (très amusant)
- Collector's Edition : un jeu où les lecteurs trouvaient des autocollants cachés dans les archives xkcd et les collaient de manière permanente sur un canevas partagé (sans obtenir le résultat espéré)
- Commencer avec une carte centrale vide au départ menait rapidement au chaos
- Il n’y avait pas assez d’incitations autour du placement des autocollants, donc il était difficile de faire avancer l’intrigue par des actions individuelles, et seuls des motifs simples apparaissaient
- Il n’y avait ni histoire globale ni objectif clair, et les relations entre les autocollants restaient floues
- Pour qu’un canevas collectif fonctionne, il faut montrer par l’exemple ce qu’il est possible de créer, et fournir un contexte partagé ainsi qu’un objectif
Concevoir les contraintes
- Une fois la décision prise de construire une grande machine à chute de billes, trop de possibilités se sont présentées
- Décision d’utiliser une grille de 100x100
- Simuler en temps réel 10 000 tuiles côté client semblait risqué
- Il n’était pas certain que des joueurs puissent construire, sans communication directe, des sous-sections d’une machine complexe, ni que des tuiles séparées fonctionneraient une fois assemblées
- Après plusieurs expériences de pensée, trois principes clés ont été retenus :
1. Maximiser l’expressivité des joueurs, même au prix de la précision
- À quel point la machine devait-elle être prévisible ?
- Faire tourner l’ensemble sur le serveur ou valider les tuiles individuellement a aussi été envisagé, mais l’éditeur prototype a montré qu’il était facile de créer des motifs chaotiques de collisions de billes
- Dès que les billes ne se déplaçaient plus en ligne droite sans interférence, il devenait facile de produire des machines imprévisibles
- Rendre la machine plus prévisible entrait en conflit avec la liberté laissée aux joueurs
- Le calendrier de développement serré a aussi poussé vers une approche avec moins de prédiction et de simulation
- Il a donc été décidé d’offrir aux joueurs une très grande liberté de création, y compris pour des machines extrêmement non déterministes ou cassées
- Cela impliquait une modération active pour vérifier le respect des contraintes et retirer les contenus inappropriés
2. Fournir des contraintes strictes pour encourager des machines compatibles et interchangeables
- L’acceptation via modération et les machines imprévisibles créées par les joueurs ont au contraire accru le besoin d’ordre
- Au départ, les entrées et sorties étaient envisagées comme totalement libres, mais il est devenu clair qu’en cas de remplacement de tuiles initiales lors de la modération, cela pouvait provoquer des perturbations massives
- Il fallait concevoir des contraintes assez fortes pour que plusieurs joueurs puissent produire des designs compatibles dans le même espace de tuile
- Application du principe de robustesse : « soyez conservateur dans ce que vous envoyez, soyez tolérant dans ce que vous recevez »
- Pour imposer des contraintes d’entrée/sortie, il fallait une carte complète de la machine dès le départ
- La génération de carte permettait aussi d’ajuster la difficulté de la machine (du simple 1 entrée / 1 sortie jusqu’aux fusions complexes 4 entrées / 4 sorties)
- Pour fournir un retour en temps réel, il a été décidé de limiter les tuiles afin qu’elles expulsent les billes à une cadence similaire à celle à laquelle elles les reçoivent
- Restrictions sur les machines qui avalent les billes ou les retardent
- Tests de chaos des tuiles avec des cadences d’entrée aléatoires
- Mise en place du principe : « faire tourner la machine un moment et vérifier qu’en moyenne elle respecte les contraintes »
3. La machine doit atteindre un état stable dans les 30 premières secondes
- Cela a soulevé la question du temps que les modérateurs devraient passer à observer
- Calcul du temps nécessaire pour modérer l’ensemble de la machine (83,3 heures pour 10 000 tuiles)
- Décision arbitraire d’exiger un état stable en moins de 30 secondes
- Les billes ont été configurées pour disparaître après 30 secondes
- Au début, il n’y avait pas de durée d’expiration, donc les billes s’accumulaient pendant que les joueurs apprenaient le jeu et finissaient par remplir l’écran
- Avec davantage de corps rigides actifs, la simulation physique ralentissait
- Les billes devenaient plus gênantes qu’amusantes
- L’expiration des billes empêchait aussi la machine d’accumuler des erreurs au fil du temps
- Les modérateurs n’avaient qu’à observer 30 secondes pour comprendre en grande partie où les billes pouvaient aller
Simulation et surréalité
- Deux grands défis dans l’architecture de Machine :
- Avec ces contraintes de conception, est-ce qu’assembler des tuiles hétérogènes en une machine complète pouvait fonctionner ?
- Cela a été vérifié en générant et résolvant quelques petites cartes
- S’il était impossible de faire tourner cette machine géante en temps réel sur le serveur ou le client, comment l’afficher ?
L’objectif : permettre de faire défiler l’écran tout en suivant une seule bille
- Même si la machine entière n’était pas simulée, la zone autour de ce que le joueur voyait devait l’être
- Au début, un test a consisté à simuler uniquement la zone visible sur une carte infinie
- Cela fonctionnait assez bien, mais lors du défilement, les tuiles entraient dans la simulation avec un état initial vide, ce qui créait des ruptures dans le flux
- Il fallait qu’au lieu d’être vides, elles donnent l’impression d’être déjà en activité
Deuxième défi : ne prendre des instantanés des tuiles qu’une fois leur état stable atteint, afin qu’elles n’existent qu’au moment juste avant d’entrer dans la zone visible lors du défilement
- Dans la BD finale, vue avec le clipping d’affichage désactivé (CSS overflow:hidden, contain:paint désactivé) :
- Avez-vous remarqué les instantanés ? Sans y prêter une attention particulière, c’est difficile à voir
- Seules les tuiles rendues existent dans la simulation physique
- Optimisation de l’affichage : seules les billes dans la zone visible sont montrées, mais la simulation s’effectue sur toute l’étendue des tuiles
- Pour simuler le sommet de la machine, des billes sont générées et injectées sur la rangée tout en haut de la simulation (selon la cadence attendue par les contraintes d’entrée)
- Intégration de la génération d’instantanés dans l’interface de modération
- Les modérateurs devaient attendre au moins 30 secondes avant de pouvoir approuver une tuile
- Le clic sur le bouton d’approbation générait l’instantané
- À leur discrétion, ils pouvaient aussi attendre un peu plus longtemps jusqu’à ce que la machine leur semble dans un bon état visuel
- Cette approche par instantanés a mieux fonctionné que prévu
- Bon effet secondaire : réinitialiser les erreurs accumulées dans les machines
- La première impression des tuiles vues en défilant correspond à un état propre et satisfaisant validé par les modérateurs
- En réalité, si on observait longtemps, beaucoup de machines pouvaient finir par tomber en panne ou se dégrader, mais cela ne se voyait pas, car en continuant d’explorer on entrait dans de nouveaux instantanés
- La machine que l’on fait défiler dans la BD n’est pas réelle. Elle est surréelle.
- Elle n’est jamais simulée entièrement d’un seul coup, et cela a même produit un meilleur résultat
Rendre des milliers de billes avec React et le DOM
- Construit sur le moteur physique Rapier
- Performances impressionnantes grâce à une excellente documentation, une API propre avec des primitives utiles, et une implémentation Rust (exécutée en WASM dans le navigateur)
- Au départ, les garanties de déterminisme de Rapier étaient attirantes, mais il n’y a pas eu de simulation côté serveur
- Écriture d’un contexte React personnalisé
<PhysicsContext> au-dessus de Rapier
- Création des objets physiques Rapier et gestion de leur cycle de vie dans le cycle de vie des composants React
- Cela a facilité le développement de composants « widget » pour chaque objet plaçable avec surface physique ou de collision
- React servait de scene graph simple et un peu bricolé
- Simplification du chargement/déchargement des tuiles lors du défilement : quand une tuile est démontée, toute sa physique et son DOM sont nettoyés
- Bonus : il est devenu facile de relier le hot reloading à fast refresh (très utile pour ajuster les formes de collision)
- Autre avantage de l’approche par contexte React :
- Si un hook physique est utilisé hors de
<PhysicsContext>, il devient un noop
- Cela a été utilisé pour rendre des aperçus statiques de tuiles dans l’interface de modération
- Il aurait peut-être été préférable d’utiliser des composants plutôt que des hooks pour créer les objets Rapier (comme le fait react-three-rapier)
- Cela s’accorde mieux avec le diffing React (lorsqu’une dépendance change,
useEffect supprime l’instance précédente avant d’en créer une nouvelle)
- Machine est rendu entièrement avec le DOM
- Au début du développement, il y avait une inquiétude quant au fait d’atteindre les limites du rendu DOM en matière de performances
- Si cela devenait trop lent, un basculement vers PixiJS ou canvas était envisagé, mais l’idée était de voir jusqu’où le DOM pouvait aller
- Optimisations de performances du rendu :
- La frame loop applique directement les styles aux widgets qui ont une simulation physique
- Le diff de React ne s’exécute que lorsqu’il y a des changements structurels dans le scene graph
- Au départ, les billes étaient rendues avec React
1 commentaires
Avis Hacker News
En synthétisant plusieurs commentaires, on peut résumer les points suivants :
Rapiera été utilisé, mais des plantages se sont parfois produits à cause d’erreurs récursives