For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
Navigation principale
4 sept. 2026 Codex

Créer des jeux avec Astra

Comment j’ai créé un jeu d’exploration spatiale procédural dans Codex, des illustrations conceptuelles aux planètes sur lesquelles on peut se poser.

Créer des jeux avec Astra

Astra sait désormais très bien traduire ce que j’ai en tête en gameplay et en direction artistique. Je l’utilise dans Codex pour créer Void Explorer, un jeu d’exploration spatiale où l’on peut voyager depuis des étoiles lointaines jusqu’à la surface de mondes extraterrestres.

Un montage de séquences de jeu de Void Explorer.

Le jeu compte 2 048 systèmes stellaires et plus de 10 000 planètes générées de manière procédurale, dont des mondes de la taille de la Terre. Chaque étoile visible fait partie de l’univers et peut être choisie comme destination. Vous pouvez sélectionner un point lumineux au loin et vous y rendre.

Vous pouvez vous approcher d’une planète depuis l’espace, traverser son atmosphère et poursuivre votre descente jusqu’à survoler un littoral. Vous pouvez vous poser, sortir du vaisseau, marcher et redécoller. Pour rendre ce voyage possible, il a fallu résoudre ensemble les questions d’échelle, de terrain, de commandes et de rendu.

J’ai inclus quelques prompts utilisés pendant le développement, raccourcis et clarifiés. Ils montrent comment j’ai décrit ce que je voulais et comment le travail technique s’est construit à partir de là.

Partez de l’expérience de jeu

Mon brief initial décrivait ce que le joueur devait pouvoir faire :

Tout ce que je vois doit être accessible. Conservez des distances réelles, puis jouez sur l’échelle et la vitesse pour rendre les déplacements possibles. Je veux pouvoir voler depuis l’espace jusque dans l’atmosphère d’une planète, puis descendre jusqu’au sol. Les planètes peuvent être aussi grandes que la Terre : il nous faudra donc un terrain procédural et un moteur de rendu par blocs.

Cela imposait des contraintes concrètes à Astra. Une étoile ne pouvait pas être un simple point peint dans le décor. Une planète ne pouvait pas devenir un niveau distinct à mon approche. Les trajets devaient couvrir des distances réelles, que des modes de déplacement fictifs, par impulsion et par hyperpropulsion, permettraient de parcourir en pratique.

J’ai aussi utilisé la génération d’images pour définir l’apparence du jeu avant d’en développer une grande partie. Les premières propositions étaient trop réalistes. La direction suivante était trop simple. Voici l’une de mes corrections :

C’est maintenant un peu trop simpliste. Il nous faut un juste milieu : de meilleures couleurs, des lumières au néon et davantage de contraste pour évoquer l’espace profond. Montrez-moi ce que cela donne à grande vitesse, avec des étoiles et de la poussière autour du vaisseau.

Une fois satisfait des images, j’ai demandé à Astra de les enregistrer et d’en faire des références pour la direction artistique du jeu. Nous avions des objectifs précis pour le vol orbital, les déplacements à grande vitesse, l’entrée dans l’atmosphère et l’atterrissage. Ces images facilitaient beaucoup l’évaluation de la version suivante.

Illustration conceptuelle générée montrant un vaisseau ivoire au-dessus d’une planète cyan à facettes, avec des touches de magenta et deux soleils aux teintes chaudes

Une illustration conceptuelle générée qui a défini la palette et la direction visuelle du jeu.

Laissez Astra proposer l’architecture

J’ai fixé les contraintes, et Astra a proposé l’implémentation. L’application utilise TypeScript et Vite, avec Three.js pour le rendu. Le code contrôle ainsi directement les maillages, les matériaux, l’éclairage et la géométrie procédurale, qui constituent l’essentiel du travail visuel de ce jeu.

La première version jouable utilisait un moteur de rendu WebGL2. Plus tard, j’ai demandé si Three.js limitait la qualité visuelle. Astra a recommandé de conserver la simulation et de passer à l’architecture WebGPU de Three.js pour le rendu. Nous avons gardé les systèmes d’univers, de navigation et de terrain tout en changeant la couche de rendu.

Le moteur de rendu utilise les matériaux à base de nœuds de Three.js et Three.js Shading Language (TSL) pour définir l’atmosphère, l’eau et les effets d’éclairage dans le code.

La génération du terrain s’exécute dans des Web Workers pour préparer la géométrie hors du thread qui gère les entrées et l’affichage. Vitest vérifie notamment la reproductibilité de la génération, les calculs de coordonnées et les contrats du terrain. Playwright teste le jeu dans un navigateur. Astra disposait ainsi de moyens de vérifier les systèmes sous-jacents pendant que je continuais à évaluer les sensations de jeu.

La direction artistique est restée le fil conducteur tout au long du développement. L’atmosphère autour d’une planète, la lueur de ses anneaux, la lumière colorée des étoiles et l’effet Neon Phosphor contribuent tous à l’apparence du jeu. Ce filtre ajoute une texture d’écran rétro tout en préservant la lisibilité des informations de navigation.

Séquence de jeu de Void Explorer montrant le vaisseau à quatre ailes, une planète cyan, des anneaux magenta, deux soleils et l’affichage de navigation

Une capture d’écran du jeu avec l’effet Neon Phosphor activé.

Donnez à Astra les moyens d’inspecter le jeu et d’y jouer

Je continuais à jouer moi-même, mais Astra avait aussi besoin de moyens d’analyser un problème au-delà de ma description. Le jeu expose une petite interface JavaScript, window.__VOID_EXPLORER__, que les tests dans le navigateur peuvent appeler pour inspecter l’état courant : l’astre dont je m’approche, le mode de vol, l’état de préparation du terrain et la caméra active. Il expose aussi des compteurs de rendu et de streaming, notamment les appels de rendu, le nombre de triangles, les tâches de génération de terrain en attente et les données de terrain en mémoire tampon.

Le jeu comporte des scènes de test nommées pour l’orbite, le déplacement par impulsion, la descente atmosphérique et l’atterrissage sur le littoral. Elles permettent à Astra de retrouver un point de départ utile sans devoir traverser l’univers à chaque fois. Playwright peut charger une scène, attendre que le terrain soit prêt, prendre une capture d’écran et vérifier l’état sous-jacent. Des tests de parcours distincts utilisent les véritables commandes et enregistrent les positions et les changements d’état pendant l’exécution du jeu. Préparer une scène d’atterrissage ne remplace donc pas le test de l’atterrissage lui-même.

Ces tests couvrent l’atterrissage, la sortie du vaisseau, la marche, la sauvegarde et le rechargement, l’embarquement et le décollage. Ils peuvent détecter des problèmes qu’une simple capture d’écran ne révélerait pas, comme une surface de collision qui n’est pas prête ou un vaisseau qui passe brusquement d’une position à une autre pendant une transition.

Je pouvais aussi demander à Astra d’inspecter l’onglet du navigateur dans lequel je jouais. Quand j’ai demandé si les nuages d’Aurelia étaient encore visibles, Astra a capturé ma vue courante et lu les informations de vol à l’écran. Il s’agissait de vérifications ponctuelles ; Astra n’observait pas en continu chaque image de mon vol.

Le cycle consistait à reproduire un problème, examiner les captures d’écran et l’état du jeu, remonter au code concerné, le modifier, puis relancer la vérification. Pour un autre jeu, je créerais ces outils dès le début : quelques scènes reproductibles, des informations d’état et des compteurs de performance utiles, ainsi que des tests dans le navigateur pour les interactions principales. Ils permettent à Astra d’analyser et de tester les modifications de manière autonome pendant que je continue à évaluer l’apparence du jeu et les sensations aux commandes.

Représentez l’univers à plusieurs échelles

Avoir des milliers de planètes ne signifie pas charger des milliers de maillages détaillés. Une planète commence par une description : son rayon, son orbite, son atmosphère et sa graine de génération. Cette graine rend son terrain reproductible. Le jeu génère la géométrie autour de la zone dont je m’approche et peut recréer le même paysage à mon retour.

Les coordonnées demandent la même attention. Des distances en années-lumière et une personne debout à côté d’un vaisseau correspondent à des échelles très différentes. Envoyer directement ces coordonnées immenses au GPU ferait perdre la précision nécessaire près du sol.

Astra a séparé l’adresse physique de la position utilisée pour le rendu. L’univers utilise de grandes cellules repérées par des entiers, avec des décalages locaux plus petits. Avant le rendu, le jeu soustrait la position de l’observateur : la caméra reste ainsi à l’origine et les objets proches ont des coordonnées de faible valeur. Les distances affichées et les tailles relatives restent cohérentes.

Les éléments mobiles doivent aussi partager la même référence temporelle. Les étoiles, les planètes et les lunes suivent des orbites analytiques, et le moteur de rendu calcule leurs positions au même instant de simulation que celle de l’observateur. Un vaisseau posé reste solidaire de la planète en rotation. Les positions et les couleurs des étoiles alimentent l’éclairage : les deux soleils qui se couchent dans un système binaire sont donc les mêmes étoiles que je voyais depuis l’orbite.

Assurez une descente continue

Un vol depuis l’espace vers la surface d’une lune dans Void Explorer.

La transition de l’espace au sol a demandé beaucoup d’itérations. L’un de mes prompts faisait suite à une approche de planète sous un angle très faible :

Quand j’arrive presque parallèlement à la surface d’une planète, ma vitesse peut encore être trop élevée, et la planète disparaît presque pendant le chargement du terrain. Nous devons corriger ensemble la courbe de vitesse et le streaming du terrain. L’atmosphère pourrait-elle adoucir la transition entre le LOD distant et le terrain détaillé ? La planète ne doit jamais disparaître pendant l’approche.

Le contrôleur de vol applique désormais un plafond de vitesse distinct aux approches sous un angle faible. Ce plafond dépend de l’altitude et d’une estimation de la vitesse orbitale à partir du rayon et de la gravité de la planète. Plus près du sol, il échantillonne aussi le terrain en amont pour adapter le freinage.

Le jeu utilise plusieurs niveaux de détail, ou LOD. De loin, une planète est une sphère à facettes peu coûteuse à rendre, appelée proxy. À mesure qu’elle occupe une plus grande partie de l’écran, le moteur de rendu ajoute des détails. L’approche de la surface active un terrain construit à partir des six faces d’un cube projetées sur une sphère. Chaque face peut se subdiviser en quatre carrés plus petits, de façon répétée : c’est un quadtree.

Cela permet au jeu d’affiner le terrain dans la zone visible et dans la direction du déplacement, sans générer une surface de la taille de la Terre à une résolution adaptée à la marche. Près du sol, des portions locales fournissent une géométrie plus fine autour du vaisseau et du joueur.

Toutes ces représentations échantillonnent la même planète sous-jacente. Une fonction commune combine les continents, les crêtes montagneuses, les cratères et les reliefs plus fins. Elle fournit l’altitude, l’eau, le biome et d’autres données utilisées par le paysage. Les maillages grossiers et fins représentent ces données par approximation à différentes résolutions, avec des règles de couleur communes pour préserver la cohérence visuelle de la planète.

Le passage d’une représentation à l’autre compte autant que la génération. La planète distante reste visible jusqu’à ce que les six faces du terrain grossier soient prêtes. Une tuile de terrain reste en place jusqu’à ce que ses quatre tuiles enfants soient prêtes. Pendant une transition, des masques de pixels complémentaires attribuent chaque pixel à l’ancienne ou à la nouvelle surface. Cela évite de rendre toute la planète transparente pendant le chargement de sa remplaçante.

L’atmosphère évolue avec l’altitude physique, et les nuages se déplacent au-dessus des reliefs de la planète. Ils aident à relier la vue orbitale au paysage. Le moteur de rendu ne retire les surfaces grossières que là où un terrain plus fin est prêt. La silhouette des montagnes peut toutefois encore changer à mesure qu’une géométrie plus fine apparaît.

L’atterrissage ajoute une exigence plus stricte. Pour une zone de contact, le sol visible, les triangles de collision et les dangers liés aux liquides doivent tous provenir de la même génération et être prêts en même temps. La marche utilise Rapier dans un petit monde physique local. La logique d’atterrissage du vaisseau vérifie séparément ses pieds, son inclinaison et sa garde au sol par rapport au terrain.

Il y a ici une limite volontaire : les planètes utilisent des champs de hauteur, avec une seule altitude dans chaque direction vers la surface. Cela convient aux grands paysages, mais ne permet pas de créer des grottes, des surplombs ou des tunnels destructibles.

Mesurez le travail nécessaire au rendu d’une image lente

Certains de mes retours portaient à la fois sur l’apparence et les performances, car je rencontrais les deux problèmes pendant le même vol :

Pouvez-vous examiner la façon dont nous chargeons et affichons une planète lorsque je descends de l’espace vers le sol ? Le globe distant et le terrain détaillé n’ont pas une apparence cohérente, et la transition est brutale, surtout lorsque les couleurs changent. Je veux comprendre ce qui provoque ces ruptures visuelles et où nous pouvons réduire le travail nécessaire au chargement de détails supplémentaires, pour que la descente soit plus belle et reste fluide.

Astra a utilisé les compteurs du moteur de rendu de Three.js pour examiner les appels de rendu, les triangles, les géométries et les textures. Un test Playwright a recueilli 90 intervalles entre images et rapporté leurs durées moyennes et leurs percentiles, en plus de ces compteurs. Pour les problèmes visuels, les tests pouvaient aussi comparer les pixels rendus avec un effet activé puis désactivé, par exemple le terrain avec et sans le masque qui cache les surfaces de sol superposées. Cela a permis d’isoler la cause de la disparition du sol, au lieu de se fier uniquement à une capture d’écran de la scène défectueuse.

Une version antérieure du vaisseau avait montré l’utilité de ces mesures. Remplacer le vaisseau procédural par le premier modèle AURORA créé dans Blender avait augmenté le nombre de triangles de la scène, mais réduit ses appels de rendu. Astra a exécuté le même test orbital de 90 images avant et après la modification, avec le backend WebGPU :

MesureAvantAprès
Total des appels de rendu de la scène11977
Nombre total de triangles dans la scène48 80961 092
Intervalle moyen entre les images251,48 ms199,26 ms

Cette comparaison a été réalisée avec Chromium sans interface graphique et le rendu logiciel SwiftShader, avant la création du vaisseau à quatre ailes présenté ci-dessous. Elle mesure l’évolution dans cet environnement de test, pas la fréquence d’images sur mon GPU. Les outils fournissaient à Astra des mesures de temps dans le navigateur, des images rendues et des décomptes de ressources ; ils ne mesuraient ni les commandes GPU individuelles ni les temps d’exécution des shaders.

Astra a examiné le travail effectué pendant le chargement et la descente : la quantité de géométrie générée, le volume de données transférées entre les workers et le moteur de rendu, et la fréquence à laquelle les tâches de génération du terrain étaient abandonnées avant de servir.

L’un des changements consistait à ajuster le niveau de détail d’une planète lointaine en fonction de sa taille à l’écran. Une planète qui remplit le champ de vision doit immédiatement avoir une silhouette précise. Une planète plus petite qu’un pixel n’a pas besoin de la même géométrie. Lors d’une comparaison contrôlée de la scène de départ, la nouvelle stratégie utilisait 7 040 triangles pour les représentations simplifiées, contre 51 200 auparavant. Les deux stratégies utilisaient le même générateur de géométrie, ce qui permettait d’isoler l’effet de la décision de chargement.

Une autre amélioration conservait exactement le même nombre de triangles de terrain. Les maillages indexés réutilisent les sommets communs aux triangles voisins au lieu de répéter leurs données de position, de couleur et de normale. Sur l’ensemble des six couches de sol du test, avec la qualité du terrain réglée sur Élevé, le volume des buffers transférés est passé d’environ 35 Mo à 15 Mo, tout en conservant 241 952 triangles. Le sol et les éléments du décor ont également été répartis en tâches distinctes, pour que la géométrie du sol puisse être prête sans attendre le décor.

Le sélecteur de terrain effectuait lui aussi du travail inutile. Il pouvait demander des blocs, changer de décision, les abandonner et en demander d’autres. Astra a stabilisé ces décisions d’affinement et fait en sorte qu’une tuile ne soit affinée que si le budget permettait de générer ses quatre tuiles enfants. Dans une simulation contrôlée avec une latence fixe des workers, six secondes de descente suivies de trois secondes de stabilisation ont entraîné l’abandon de 13 tâches, contre 6 074 auparavant.

Graphique en courbes montrant le nombre de tâches de terrain planifiées puis abandonnées sur neuf secondes simulées. L’ancien sélecteur atteint 6 074 tâches ; le sélecteur modifié reste à 13. La caméra s’arrête au bout de six secondes.

Dans une simulation contrôlée avec deux workers et une latence simulée de 100 ms par worker, le nombre de tâches planifiées puis abandonnées est passé de 6 074 à 13. Cette mesure porte sur l’ordonnancement des tâches de terrain, pas sur la fréquence d’images.

Les workers ne suffisent pas à éliminer tous les blocages. Le mécanisme de repli qui génère le terrain sur le thread principal devait lui aussi céder la main. Astra a découpé la génération en étapes pouvant être suspendues puis reprises, avec un budget d’environ 4 ms par image. Ainsi, une grosse tâche de génération du terrain n’avait plus à s’exécuter d’un seul bloc. Le moteur de rendu limite aussi la résolution du monde indépendamment de celle de l’interface, ce qui préserve la netteté du texte de navigation lorsque la qualité visuelle est réduite.

Ces mesures sur le terrain montrent une réduction de la géométrie, des données transférées et du travail abandonné. Ce ne sont pas des benchmarks de fréquence d’images sur du matériel réel. Les tests en jouant dans le navigateur restent essentiels pour évaluer la compilation des shaders, les transferts vers le GPU, les mouvements et l’aspect réel de la transition.

De mon côté, je faisais des retours en jouant : ce qui me semblait lent, ce qui clochait visuellement et ce que je voulais améliorer. Astra a suivi les chemins d’exécution dans le code, écrit des scripts de test reproductibles pour le terrain et consigné les mesures. Une fois l’approche approuvée, il a implémenté les changements et relancé les mêmes tests pour comparer les résultats. Il a mené cette investigation et cette implémentation sans que je lui dicte chaque étape, tandis que je continuais à évaluer l’aspect du jeu et les sensations qu’il procurait.

Transformez les illustrations conceptuelles en ressources de jeu

L’univers est en grande partie généré par le code : planètes, terrain, nuages, anneaux et étoiles. Le vaisseau du joueur est le principal modèle 3D créé séparément, et j’ai suivi une autre approche pour celui-ci.

J’ai utilisé des illustrations conceptuelles générées et des rendus Blender pour examiner le vaisseau avant de l’intégrer au jeu. Quand les ailes ne correspondaient pas à ce que j’avais en tête, j’ai demandé des références plus utiles :

Générez des vues claires de ce vaisseau sous plusieurs angles. Portez une attention particulière aux ailes avant et arrière. Nous utiliserons ces images pour refaire le modèle 3D. Je n’aime pas les ailes arrondies et reliées entre elles du modèle actuel.

J’ai choisi la référence avec quatre ailes séparées, une forme symétrique et des lumières roses aux extrémités. J’ai ensuite demandé à Astra de créer un nouveau modèle dans Blender, de respecter le style artistique du jeu et de l’intégrer au jeu.

Il fallait pour cela transformer la référence en géométrie, examiner la silhouette et les matériaux, puis préparer une ressource utilisable par le jeu. Le fichier source Blender contient 193 maillages modifiables. Le vaisseau exporté compte 14 968 triangles, regroupés en huit lots de matériaux opaques. Je pouvais demander davantage de détails dans le modèle, tandis qu’Astra maîtrisait le coût de rendu de la version exportée.

Illustration conceptuelle générée, vue de dessus, montrant quatre ailes séparées, des lumières roses à leurs extrémités, une coque ivoire et une verrière verte

L’illustration conceptuelle générée du vaisseau que j’ai approuvée.

Rendu Blender du vaisseau montrant sa coque en céramique, ses quatre ailes séparées et ses deux moteurs cyan

Un rendu Blender du modèle utilisé dans le jeu.

Expérimentez avec l’eau procédurale

J’ai aussi passé beaucoup de temps à expérimenter avec l’eau dans Sunwake, un jeu où l’on pilote un petit bateau sur un océan procédural. Je voulais des vagues à facettes, des mouvements fluides et des couleurs de vitrail. Astra a créé un moteur de rendu de l’eau sur mesure dans Three.js, avec un même modèle de vagues pour la mer visible et la flottabilité du bateau. La coque monte, tangue et roule au gré des vagues, tandis qu’une simulation locale propage les rides et l’écume, et que le bateau laisse derrière lui des sillages et des gerbes d’eau. J’ai ensuite demandé à Astra de créer un bateau plus détaillé dans Blender et de l’intégrer au jeu. C’est la même approche que pour Void Explorer : un environnement procédural et un véhicule modélisé séparément, reliés par la simulation.

Scène de jeu de Sunwake montrant un bateau orange qui laisse un sillage écumeux à travers des vagues bleues à facettes, sous un lever de soleil rose

Sunwake associe un océan procédural à un bateau modélisé dans Blender.

Hollowflux explore une autre voie : un petit RPG d’action en 2D construit autour d’une rivière souterraine lumineuse. Les grottes, les personnages et l’équipement sont dessinés par le code, sans planches de sprites importées. Je demandais régulièrement à Astra de rendre plus convaincantes les perturbations de l’eau provoquées par la marche, les ruées et les attaques. Une grille de cellules suit la hauteur de l’eau, les courants, l’écume et la charge électrique. Les pas créent des rides, les coups de lance tracent de fins sillages et les coups de marteau propagent des ondes circulaires. Les courants tourbillonnent le long des berges et emportent l’écume vers l’aval, tout en poussant le joueur et les ennemis. L’eau influe aussi sur les combats : la décharge d’une anguille se propage dans les zones d’eau reliées entre elles ; monter sur une pierre sèche protège donc le joueur de cette décharge.

Un aventurier en pixel art avance dans une rivière bleu-vert lumineuse dans Hollowflux, entouré de rides à la surface de l’eau, de créatures et des parois sombres de la grotte

Hollowflux dessine ses graphismes par le code, avec une eau qui réagit aux mouvements et aux combats.

Créer et partager des jeux

Ce que j’aime dans le travail avec Astra, c’est que je peux partir de l’expérience que je souhaite créer, utiliser des images pour concrétiser la direction visuelle et faire des retours en jouant réellement. Signaler une planète qui disparaît peut conduire à modifier le chargement en continu, la géométrie et les déplacements. Demander une eau plus convaincante peut aboutir à une simulation commune au rendu visuel et au gameplay. C’est toujours à moi de juger si les sensations sont bonnes, mais Astra peut appliquer ces décisions au code, aux ressources et aux tests.

Partager un jeu sur navigateur est tout aussi simple. Avec le plugin Sites, vous pouvez demander à Astra :

Utilisez @Sites pour déployer ce jeu et donnez-moi un lien.

Publiez-le en accès public, et tout le monde pourra y jouer directement dans son navigateur.

Vous pouvez jouer à Void Explorer, à Sunwake et à Hollowflux dans votre navigateur.

Si vous avez une idée de jeu en tête, essayez d’en créer une petite version jouable avec Astra. Commencez par un élément dont vous voulez soigner les sensations, fournissez quelques références visuelles et testez le résultat. Un bateau, une pièce ou une seule interaction suffit pour commencer. Jouez, précisez ce que vous voulez changer et continuez à construire à partir de là.