Warum wir unsere eigene WebGPU-Engine entwickelt haben, statt PlayCanvas zu forken
Von Oleg Sidorkin, CTO und Mitgründer von Cinevva

Jeder technisch versierte Mensch, der sich Cinevva World ansieht, stellt innerhalb von fünf Minuten dieselbe Frage. Ihr seid ein kleines Team. Es gibt ausgereifte 3D-Engines fürs Web. Warum habt ihr euren eigenen Renderer, eure eigene Charakterphysik und euer eigenes Animationssystem geschrieben, statt auf PlayCanvas oder Babylon aufzubauen und schneller zu veröffentlichen?
Das ist eine berechtigte Frage, und „Not invented here“ ist die falsche Antwort darauf. Wir haben unsere Hausaufgaben gemacht. Wir haben die bestehenden Engines ausgeführt, ihren Quellcode gelesen und Prototypen auf Basis von zwei davon entwickelt, bevor wir uns entschieden haben. Dieser Beitrag ist die ehrliche Version dieser Entscheidung: worin die Standardlösungen wirklich gut sind, an welchen vier Stellen unsere Anforderungen so stark davon abwichen, dass sich eine Eigenentwicklung rechtfertigte, und in welchen Situationen du dich für eine dieser Lösungen entscheiden solltest, statt uns nachzueifern. Die Entwicklung selbst haben wir in einer fortlaufenden Engineering-Serie über eine offene Welt im Browser dokumentiert. Wo es zu einer der folgenden Aussagen ein Entwicklungsprotokoll gibt, verlinke ich darauf.
Die Optionen, die wir tatsächlich evaluiert haben
Vier verschiedene Dinge werden als „Web-Game-Engines“ bezeichnet, obwohl sie nicht dieselbe Art von Werkzeug sind.
Three.js ist eine Rendering-Bibliothek, keine Game-Engine. Sie bietet dir einen Szenengraphen, Materialien, Loader und einen Renderer und lässt dir ansonsten freie Hand. Es gibt keinen Editor, keine Physik, kein Entity-System und keine Vorgaben dafür, wie dein Spiel strukturiert sein soll. Das ist zugleich der Reiz und der Preis. Alles oberhalb des Renderers baust du selbst, dafür arbeitet nichts gegen dich. Three.js steht unter der MIT-Lizenz, verfügt über das größte Ökosystem in diesem Bereich und wenn du um zwei Uhr morgens auf einen obskuren Shader-Fehler stößt, wartet in irgendeinem Forum bereits eine Antwort.
Babylon.js ist eine vollständige Engine mit Szenengraph, Physikintegration (Havok), Asset-Pipeline und Web-Editor. Sie steht unter der MIT-Lizenz, wird von einem Team bei Microsoft unterstützt und ihre WebGPU-Entwicklung schreitet schnell voran. Wenn du eine Komplettlösung möchtest und gerne innerhalb der vorgegebenen Engine-Struktur arbeitest, ist sie eine gute Standardwahl.
PlayCanvas kommt einem „Unity fürs Web“ am nächsten. Zum Zeitpunkt dieses Beitrags liegt die Engine in Version 2.19.6 vor, die am 5. Juni 2026 veröffentlicht wurde, und die Engine selbst ist unter der MIT-Lizenz quelloffen. Was die meisten jedoch tatsächlich verwenden, ist der gehostete visuelle Editor, und dieser Editor ist ein kommerzielles Produkt, keine Open-Source-Software. PlayCanvas verwendet ein Entity-Component-System, Skripte werden in TypeScript oder JavaScript geschrieben, Assets durchlaufen eine serverseitige GLB-Pipeline und echte kommerzielle Spiele wurden damit veröffentlicht (unter anderem nutzt Snap PlayCanvas in der Produktion). Der Renderer läuft mit WebGL2 und verfügt über einen WebGPU-Pfad, der noch ausgereift wird und nicht der Standard ist. Dieses letzte Detail ist wichtiger, als es klingt, und ich komme später darauf zurück.
Unity WebGL ist überhaupt keine Web-Engine. Es ist ein Exportziel. Du entwickelst im Unity-Desktop-Editor und kompilierst das Projekt zu einem WebGL-Bundle. Es ist das richtige Werkzeug, wenn du bereits ein Unity-Spiel hast und es in den Browser bringen möchtest. Es ist das falsche Werkzeug, wenn „wird auf einem Mittelklasse-Smartphone sofort in einem Tab geladen“ eine zwingende Anforderung ist, denn die Laufzeitumgebung und das Downloadvolumen kommen als Ballast mit.
Jede dieser Optionen ist eine vernünftige Grundlage für ein normales Web-Spiel. Wir hatten kein normales Web-Spiel.
Entscheidung eins: WebGPU ist unser Ausgangspunkt, nicht unser Ziel
Der entscheidende Unterschied, der uns von allen Standardlösungen weggeführt hat, ist dieser: Für uns ist WebGPU eine Voraussetzung, keine Funktion, in die wir irgendwann hineinwachsen.
Unser Terrain ist keine statische Heightmap. Es ist eine Mischung aus einem gestreamten Heightmap-Feld und Marching-Cubes-Chunks, die auf einem Signed-Distance-Field basieren. Dadurch kann die Welt echte Höhlen und Überhänge besitzen und von Kreativen live modelliert werden. Die Modellierpinsel, die Verteilung der Vegetation und die Terrain-Vermaschung laufen alle als Compute-Shader. Nimmt man Compute weg, wird die Welt nicht bloß schlechter – sie läuft überhaupt nicht.
Das ist das genaue Gegenteil der heutigen Ausrichtung universeller Engines. Deren WebGPU-Unterstützung ist als progressive Verbesserung eines WebGL2-zentrierten Renderers konzipiert, mit einem Fallback für Browser, die WebGPU nicht unterstützen. Insbesondere PlayCanvas setzt primär auf WebGL2, während WebGPU noch in der Betaphase ist. Für PlayCanvas ist das die richtige Entscheidung, denn seine Aufgabe besteht darin, eine möglichst große Bandbreite an Spielen auf einer möglichst großen Bandbreite an Geräten auszuführen. Unsere Aufgabe ist enger gefasst, geht aber stärker in die Tiefe. Deshalb haben wir die gegenteilige Entscheidung getroffen: Ab Prototyp 13 setzten wir ausschließlich auf WebGPU und blickten nie zurück. Browser ohne WebGPU erhalten keine abgespeckte Version, sondern werden nicht unterstützt. Wir erfassen das als Reichweitenkennzahl, statt so zu tun, als wäre ein WebGL2-Fallback nur eine Konfigurationsoption entfernt. Das ist er nicht. Dafür müssten wir unsere Terrain- und Vegetationsstufen teilweise neu schreiben.
Auf einer WebGL2-zentrierten Engine aufzubauen hätte bedeutet, bei jeder Compute-Funktion gegen deren Fallback-Annahmen anzukämpfen oder für immer zwei Rendering-Pfade zu pflegen. Ein eigener Renderer erlaubte uns, Compute als Grundlage zu behandeln.
Entscheidung zwei: ein Charakter-Solver statt einer Physik-Engine
Der klassische Ansatz besteht darin, eine Physik-Engine einzubinden. Wir haben das ausprobiert. Ein früher Prototyp bestätigte, dass Rapier in einem Worker problemlos lief, und es fühlte sich gut an.
Trotzdem haben wir unsere eigene Lösung geschrieben, und im ausgelieferten Build findet sich weder Rapier noch Cannon oder Ammo. Der Grund ist der Funktionsumfang. Wir brauchen keine Starrkörper, Gelenke, Ragdolls oder Constraint-Solver. Wir müssen lediglich eine Kapsel korrekt über das Terrain bewegen und dafür sorgen, dass Gehen, Rutschen, Gleiten, Klettern und Schwimmen dieselbe gemeinsame Antwort auf die Frage verwenden: „Stehe ich auf dem Boden, auf welcher Oberfläche und in welchem Winkel?“ Eine universelle Physik-Engine erschwert das, statt es zu vereinfachen, weil diese Bewegungsmodi am Ende gegen ihre internen Federn und Dämpfer ankämpfen.
Unser Charakter-Controller ist daher eine austauschbare Mehrkanal-Zustandsmaschine. Jeder Modus ist eine kleine Einheit, die angibt, ob sie in diesem Frame die Kontrolle übernehmen möchte, und bei Erfolg Geschwindigkeit und Blickrichtung festlegt. Die Modi konkurrieren anhand ihrer Priorität über drei Kanäle hinweg: zuerst Ressourcen, dann Haltung und schließlich Fortbewegung. Sie alle lesen dieselbe Terrain-Abfrage. Je nach Chunk erfolgt die Kollision über eine Kapselabfrage gegen die Heightmap oder das Signed-Distance-Field.
Das Detail, auf das ich am stolzesten bin, ist völlig unspektakulär. Die Bodenerkennung durchsucht jede Oberfläche in der vertikalen Säule unter deinen Füßen und wählt die höchste aus, die sich auf oder unterhalb der Kapsel befindet, statt dem SDF-Gradienten zu vertrauen. Am Rand eines Überhangs ist die seitlich nächstgelegene Oberfläche die Felswand. Dadurch flackert eine gradientenbasierte Normale zwischen „Boden“ und „Wand“, was zu Phantomrutschen führt. Mit der Säulenabfrage wird das Stehen auf einem Vorsprung langweilig – und genau so soll es sein. Ein handelsüblicher Heightfield-Collider hätte uns das nicht automatisch geboten, weil er unser Terrain gar nicht sehen kann. Das Terrain befindet sich in unserem eigenen Format auf der GPU. Keine externe Engine kann Kollisionen damit berechnen, ohne dass wir bei jeder Änderung das gesamte Feld in ihr Collider-Format kopieren.
Entscheidung drei: Animationen, die zwischen Rigs übertragbar sind
Avatare verwenden das Synty-POLYGON-Rig und unsere Bewegungsclips stammen aus einer großen offenen Animationsbibliothek. Da Rig und Clips dieselben Knochennamen verwenden, ist im Normalfall kein Retargeting zur Laufzeit erforderlich – die Tracks werden einfach anhand ihrer Namen gebunden. Die vollständige Charakter-Pipeline haben wir im Beitrag über universelle Charaktere beschrieben.
Interessant wird es, wenn sie nicht übereinstimmen. Wir haben einen Retargeting-Durchlauf entwickelt, der ein Skelett auf ein anderes abbildet. Um ihn korrekt umzusetzen, mussten wir drei konkrete Probleme lösen. Zuerst müssen die Bind-Pose-Positionen angeglichen werden, weil eine A-Pose gegenüber einer T-Pose unbemerkt etwa dreißig Grad pro Gelenk hinzufügt. Root Motion und Schrittlänge werden mit zwei getrennten Verhältnissen skaliert: Hüfte zu Boden für die Vertikale und die Gesamtproportion für die Horizontale. Außerdem testen wir retargetete Clips mit einer festen Abtastrate gegen ihre Quelle, damit Regressionen sichtbar werden, bevor ein Spieler sie bemerkt. Dank dieser Pipeline können wir neue Animationsquellen und künftig auch von Kreativen bereitgestellte Charaktere hinzufügen, ohne jeden Clip von Hand korrigieren zu müssen.
Darüber liegt eine Animations-Zustandsmaschine, die in jedem Frame anhand des Bewegungszustands die passende Clip-Familie auswählt: die Sprungvariante nach Geschwindigkeit, die Stärke der Landung nach Aufprall, die Hangrichtung anhand des Skalarprodukts aus Geschwindigkeit und Terrain-Gradient, Stopps mit korrekter Fußphase, damit der Charakter nicht per Moonwalk zum Stillstand kommt, sowie eine Entprellzeit von hundert Millisekunden, damit ein Zusammenstoß mit einer Wand nicht zu einem flackernden Wechsel zwischen Gehen und Fallen führt. Nichts davon ist exotisch, aber es gehört zu den Dingen, die man nur erhält, wenn man die Ebene selbst kontrolliert.
Entscheidung vier: der Teil, den keine Engine mitliefert
Bei den anderen drei Entscheidungen geht es darum, wie die Welt läuft. Bei dieser geht es darum, was das Produkt überhaupt ist – und deshalb ist der Vergleich mit PlayCanvas letztlich ein Kategorienfehler.
PlayCanvas, Babylon, Unity und eine von Hand entwickelte Three.js-Anwendung gehen alle von demselben Ablauf aus: Du baust dein Spiel an einem Schreibtisch in einem 2D-Editor, betrachtest die Welt von außen und drückst dann auf „Play“, um eine separate Laufzeitversion zu veröffentlichen. Selbst bei der Bearbeitung innerhalb der Engine sitzt du an einem Arbeitsplatz und manipulierst eine Szene, auf die du von außen blickst.
Cinevva World kehrt das um. Du erschaffst Dinge aus dem Inneren der Welt heraus – als Avatar, der im selben Raum steht, in dem später auch deine Spieler stehen werden. Du beschreibst, was du möchtest, und siehst dabei zu, wie es erscheint. Erschaffen und Spielen sind eine durchgängige Sitzung, kein Build-Schritt mit anschließender Übergabe an eine Laufzeitumgebung. Die nächstliegenden Vergleichspunkte sind Roblox, Rec Room und Horizon Worlds, nicht 3D-Engines fürs Web. Und selbst bei diesen findet ein Großteil der Erstellung am Schreibtisch statt. Ohne mausgesteuerten Editor wird unser Ansatz durch den KI-Builder praktikabel, der „Baue hier einen von Laternen beleuchteten Steg“ in Geometrie und Platzierung umsetzt.
Das lässt sich nicht einfach an eine universelle Engine anbauen, denn es ist keine Rendering-Funktion. Es ist die Grundidee des gesamten Stacks – von der Bearbeitbarkeit des Terrains zur Laufzeit bis hin zum Umgang des Netzwerks mit jedem Objekt als etwas, das eine in der Nähe stehende Person gerade erschaffen hat.
Wann du nicht tun solltest, was wir getan haben
Hier kommt der Teil, den Beiträge aus dem Genre „Wir haben unsere eigene Engine gebaut“ normalerweise auslassen. Wenn du noch in diesem Quartal ein Browser-Spiel veröffentlichen möchtest, solltest du uns nicht nachahmen. Nutze PlayCanvas, wenn du einen Editor im Unity-Stil und eine verwaltete Pipeline möchtest. Nutze Babylon, wenn du eine vollständige Engine mit integrierter Physik suchst und gerne innerhalb ihrer Struktur arbeitest. Nutze Three.js, wenn du maximale Kontrolle und minimale Vorgaben möchtest und dein Team alles darüber selbst entwickeln kann. Portiere dein Projekt aus Unity, wenn du bereits ein Unity-Spiel hast.
Einen eigenen Renderer sowie eigene Physik- und Animationssysteme zu schreiben, ist nur dann die richtige Entscheidung, wenn die Grundidee deines Produkts mit keiner Standardlösung vereinbar ist – wenn du nicht einfach ein Spiel auf einer Engine entwickelst, sondern einen Ort, der zufällig aus einer solchen besteht. Bei uns war das der Fall. Bei dir ist es wahrscheinlich nicht so, und das ist völlig in Ordnung. Der Sinn einer ehrlichen Evaluierung besteht darin, zu wissen, welcher Fall auf dich zutrifft, bevor du die erste Zeile Code schreibst.