Skip to content

Pourquoi nous avons créé notre propre moteur WebGPU au lieu de forker PlayCanvas

Par Oleg Sidorkin, CTO et cofondateur de Cinevva

Un monde stylisé en low poly rendu par le moteur WebGPU de Cinevva : des collines ondulantes, une grotte creusée dans une falaise, une rivière sinueuse et un avatar avançant sur un chemin à l'heure dorée

Toute personne ayant un profil technique qui découvre Cinevva World pose la même question dans les cinq premières minutes. Vous êtes une petite équipe. Il existe des moteurs 3D web éprouvés. Pourquoi avoir écrit votre propre moteur de rendu, votre propre système de physique des personnages et votre propre système d'animation, au lieu de vous appuyer sur PlayCanvas ou Babylon pour livrer plus vite ?

C'est une question légitime, et répondre « parce que ce n'est pas nous qui l'avons inventé » serait une mauvaise réponse. Nous avons fait nos devoirs. Nous avons testé les moteurs existants, lu leur code source et réalisé des prototypes avec deux d'entre eux avant de prendre notre décision. Cet article présente la version honnête de cette décision : les véritables points forts des solutions prêtes à l'emploi, les quatre aspects pour lesquels nos besoins divergeaient suffisamment pour justifier une création maison, et les situations où vous devriez choisir l'une de ces solutions plutôt que de nous imiter. Nous avons documenté le développement lui-même dans une longue série technique consacrée à la création d'un monde ouvert dans le navigateur. Lorsqu'une affirmation ci-dessous s'appuie sur un journal de développement concret, je fournirai le lien correspondant.

Les solutions que nous avons réellement évaluées

Quatre types d'outils sont qualifiés de « moteurs de jeu web », alors qu'ils ne sont pas de même nature.

Three.js est une bibliothèque de rendu, pas un moteur de jeu. Elle vous fournit un graphe de scène, des matériaux, des chargeurs et un moteur de rendu, puis vous laisse faire. Pas d'éditeur, pas de physique, pas de système d'entités, aucune opinion sur la manière dont votre jeu doit être structuré. C'est à la fois son attrait et son coût. Vous construisez vous-même tout ce qui se trouve au-dessus du moteur de rendu, mais rien ne vous impose de contraintes. Elle est sous licence MIT, possède le plus vaste écosystème du secteur et, lorsque vous tombez sur un obscur bug de shader à deux heures du matin, une réponse vous attend sur un forum.

Babylon.js est un moteur complet doté d'un graphe de scène, d'une intégration physique (Havok), d'un pipeline de ressources et d'un éditeur web. Il est sous licence MIT, soutenu par une équipe de Microsoft, et ses travaux sur WebGPU progressent rapidement. Si vous voulez une solution tout-en-un et acceptez de travailler dans la structure imposée par le moteur, c'est un excellent choix par défaut.

PlayCanvas est ce qui se rapproche le plus d'un « Unity pour le web ». À l'heure où nous écrivons ces lignes, le moteur est en version 2.19.6, publiée le 5 juin 2026, et son code source est disponible sous licence MIT. Cependant, ce que la plupart des gens utilisent réellement est l'éditeur visuel hébergé, qui est un produit commercial et non open source. PlayCanvas repose sur un système entité-composant, permet d'écrire des scripts en TypeScript ou JavaScript, fait transiter les ressources par un pipeline GLB côté serveur, et de véritables jeux commerciaux ont été publiés avec lui (Snap utilise notamment PlayCanvas en production). Son moteur de rendu fonctionne avec WebGL2 et propose une voie WebGPU encore en cours de maturation, plutôt que de l'utiliser par défaut. Ce dernier détail compte plus qu'il n'y paraît, et j'y reviendrai.

Unity WebGL n'est pas du tout un moteur web. C'est une cible d'exportation. Vous développez dans l'éditeur de bureau Unity, puis compilez le projet sous forme de bundle WebGL. C'est le bon outil si vous possédez déjà un jeu Unity et souhaitez le proposer dans un navigateur, mais le mauvais si « se charge instantanément dans un onglet sur un téléphone de milieu de gamme » constitue une exigence absolue, car le poids de l'environnement d'exécution et du téléchargement est lui aussi embarqué.

N'importe laquelle de ces solutions constitue une base raisonnable pour un jeu web classique. Mais notre jeu web n'avait rien de classique.

Première décision : WebGPU est notre socle, pas notre ligne d'arrivée

Voici la divergence qui nous éloigne de toutes les solutions existantes. Pour nous, WebGPU est une exigence, pas une fonctionnalité que nous adopterons progressivement.

Notre terrain n'est pas une carte de hauteurs statique. Il s'agit d'un système hybride associant un champ de cartes de hauteurs diffusé en continu et des chunks générés par marching cubes à partir d'un champ de distance signé. Le monde peut ainsi contenir de véritables grottes et surplombs, que les créateurs peuvent sculpter en direct. Les brosses de sculpture, la dispersion de la végétation et le maillage du terrain s'exécutent tous sous forme de compute shaders. Sans calcul GPU, le monde ne fonctionne pas en mode dégradé : il ne fonctionne tout simplement pas.

C'est l'exact opposé de la position actuelle des moteurs généralistes. Leur prise en charge de WebGPU est conçue comme une amélioration progressive venant compléter un moteur de rendu principalement basé sur WebGL2, avec une solution de repli pour les navigateurs qui ne le prennent pas en charge. PlayCanvas, en particulier, privilégie WebGL2, tandis que WebGPU y est encore en bêta. C'est le bon choix pour eux, car leur mission consiste à exécuter la plus grande variété possible de jeux sur la plus grande variété possible d'appareils. Notre objectif est plus étroit, mais plus poussé. Nous avons donc fait le choix inverse : nous sommes passés exclusivement à WebGPU lors du prototype 13 et n'avons jamais fait marche arrière. Les navigateurs sans WebGPU ne bénéficient pas d'un mode dégradé : ils ne sont pas pris en charge. Nous considérons cela comme une donnée de couverture plutôt que de prétendre qu'un repli vers WebGL2 ne nécessite que l'activation d'une option de configuration. Ce n'est pas le cas. Il faudrait réécrire partiellement nos étapes de terrain et de végétation.

Construire sur un moteur privilégiant WebGL2 nous aurait obligés soit à lutter contre ses hypothèses de repli pour chaque fonctionnalité de calcul GPU, soit à maintenir éternellement deux voies de rendu. Posséder notre propre moteur de rendu nous a permis de considérer le calcul GPU comme la base.

Deuxième décision : un solveur de personnage, pas un moteur physique

La solution classique consiste à intégrer un moteur physique. Nous l'avons essayée. Un premier prototype a validé le fonctionnement de Rapier dans un worker, avec un résultat tout à fait correct.

Nous avons tout de même écrit notre propre système, et la version livrée ne contient aucune trace de Rapier, Cannon ou Ammo. La raison tient au périmètre. Nous n'avons pas besoin de corps rigides, d'articulations, de ragdolls ni d'un solveur de contraintes. Nous avons besoin qu'une seule capsule se déplace correctement sur le terrain, et que la marche, la glissade, le vol plané, l'escalade et la nage partagent une réponse unique à la question : « Suis-je au sol, sur quelle surface et avec quelle inclinaison ? » Un moteur physique généraliste complique cette tâche au lieu de la simplifier, car ces modes finissent par entrer en conflit avec ses ressorts et amortisseurs internes.

Notre contrôleur de personnage est donc une machine à états multicanal modulaire. Chaque mode est une petite unité qui indique s'il souhaite prendre le contrôle pendant cette frame et qui, s'il l'obtient, définit la vélocité et l'orientation. Les modes sont départagés par priorité sur trois canaux — ressource, puis posture, puis locomotion — et consultent tous la même requête de terrain. La collision repose sur le sondage d'une capsule par rapport à la carte de hauteurs ou au champ de distance signé, selon le chunk.

Le détail dont je suis le plus fier n'a rien de spectaculaire. La détection du sol analyse toutes les surfaces de la colonne verticale située sous les pieds du personnage et sélectionne la plus haute se trouvant au niveau de la capsule ou en dessous, au lieu de se fier au gradient du champ de distance signé. Au bord d'un surplomb, la surface latérale la plus proche est la paroi de la falaise. Une normale basée sur le gradient oscille alors entre « sol » et « mur », ce qui provoque des glissades fantômes. Grâce à la requête par colonne, se tenir sur une corniche devient parfaitement banal, ce qui est exactement le résultat recherché. Un collisionneur de champ de hauteur prêt à l'emploi ne nous aurait pas fourni cela gratuitement, car il ne peut même pas accéder à notre terrain. Celui-ci réside sur le GPU dans notre propre format. Aucun moteur externe ne peut gérer ses collisions sans que nous recopiions l'intégralité du champ dans le format de son collisionneur à chaque modification.

Troisième décision : des animations transférables entre les rigs

Les avatars utilisent le rig Synty POLYGON, tandis que nos clips de mouvement proviennent d'une vaste bibliothèque d'animations ouverte. Comme le rig et les clips partagent les mêmes noms d'os, le cas courant ne nécessite aucun retargeting à l'exécution : les pistes sont simplement associées par leur nom. Nous avons présenté l'ensemble du pipeline de personnages dans l'article sur les personnages universels.

Le travail intéressant concerne les cas où ils ne correspondent pas. Nous avons créé une passe de retargeting qui transpose un squelette sur un autre, et son bon fonctionnement a nécessité de résoudre trois problèmes précis. Il faut d'abord aligner les poses de référence, car l'association d'une pose en A et d'une pose en T ajoute silencieusement environ trente degrés par articulation. Il faut ensuite mettre à l'échelle le mouvement de la racine et la longueur des pas avec deux ratios distincts : la distance entre les hanches et le sol pour la verticale, et les proportions globales pour l'horizontale. Enfin, il faut tester les clips retargetés par rapport à leur source à une fréquence d'échantillonnage fixe, afin que les régressions soient détectées avant qu'un joueur ne les remarque. Ce pipeline nous permet d'ajouter de nouvelles sources d'animation et, à terme, des personnages fournis par les créateurs, sans corriger manuellement chaque clip.

Par-dessus vient se greffer une machine à états d'animation qui choisit à chaque frame la famille de clips appropriée en fonction de l'état du mouvement : variante de saut selon la vitesse, intensité de l'atterrissage selon l'impact, direction de la pente calculée à partir du produit scalaire de la vélocité et du gradient du terrain, arrêts respectant la phase des pieds pour éviter que le personnage ne termine sa course en moonwalk, et temporisation de cent millisecondes afin qu'un simple choc contre un mur ne fasse pas alterner frénétiquement les états de marche et de chute. Rien de tout cela n'est exotique, mais c'est le genre de résultat qu'on n'obtient qu'en maîtrisant entièrement cette couche.

Quatrième décision : la partie qu'aucun moteur ne fournit

Les trois autres décisions portent sur le fonctionnement du monde. Celle-ci concerne la nature même du produit, et explique pourquoi la comparaison avec PlayCanvas relève finalement d'une erreur de catégorie.

PlayCanvas, Babylon, Unity et une application Three.js développée sur mesure reposent tous sur le même modèle : vous créez votre jeu assis à un bureau, dans un éditeur 2D, en observant le monde de l'extérieur, puis vous appuyez sur Lecture et publiez un environnement d'exécution distinct. Même l'édition intégrée au moteur suppose que vous soyez devant une station de travail, en train de manipuler une scène que vous observez.

Cinevva World inverse ce modèle. Vous créez depuis l'intérieur du monde, sous la forme d'un avatar se tenant dans le même espace que celui qu'occuperont vos joueurs, en décrivant ce que vous voulez et en le regardant apparaître. La création et le jeu forment une seule session continue, et non une étape de production reliée à un environnement d'exécution. Les références les plus proches sont Roblox, Rec Room et Horizon Worlds, et non les moteurs 3D web. Même ces plateformes conservent toutefois l'essentiel de la création sur ordinateur. Ce qui rend notre approche viable sans éditeur piloté à la souris, c'est le constructeur IA, qui transforme « place ici un quai éclairé par des lanternes » en géométrie et en positionnement.

Vous ne pouvez pas simplement greffer cela sur un moteur généraliste, car il ne s'agit pas d'une fonctionnalité de rendu. C'est le principe fondateur de toute la pile technologique, depuis la possibilité de modifier le terrain à l'exécution jusqu'à la manière dont le réseau considère chaque objet comme quelque chose qu'une personne se tenant à proximité vient de créer.

Quand vous ne devriez pas faire comme nous

Voici la partie que les récits du genre « nous avons créé notre propre moteur » omettent généralement. Si vous voulez publier un jeu dans le navigateur ce trimestre, ne nous imitez pas. Utilisez PlayCanvas si vous voulez un éditeur dans le style de Unity et un pipeline géré. Utilisez Babylon si vous voulez un moteur complet incluant la physique et acceptez de travailler dans sa structure. Utilisez Three.js si vous recherchez un contrôle maximal, un minimum de contraintes conceptuelles et disposez d'une équipe capable de construire les couches supérieures. Réalisez un portage depuis Unity si vous possédez déjà un jeu Unity.

Écrire son propre moteur de rendu, son propre système physique et son propre système d'animation n'est le bon choix que lorsque le principe même de votre produit est incompatible avec les solutions existantes, lorsque ce que vous construisez n'est pas un jeu fonctionnant sur un moteur, mais un lieu qui se trouve être constitué d'un moteur. C'était notre cas. Ce n'est probablement pas le vôtre, et ce n'est pas un problème. L'intérêt d'une évaluation honnête est de savoir dans quelle situation vous vous trouvez avant d'écrire la première ligne de code.