Skip to content

हमने PlayCanvas को fork करने के बजाय अपना WebGPU engine क्यों बनाया

लेखक Oleg Sidorkin, Cinevva के CTO और Co-Founder

A stylized low-poly world rendered by Cinevva's WebGPU engine: rolling hills, a cave carved into a cliff, a winding river, and an avatar mid-stride on a path at golden hour

जो भी तकनीकी इंसान Cinevva World को देखता है, वह पाँच मिनट के अंदर एक ही बात पूछता है। आपकी टीम छोटी है। पक्के web 3D engines पहले से मौजूद हैं। आपने PlayCanvas या Babylon पर खड़े होकर तेज़ी से shipping करने के बजाय अपना खुद का renderer, अपना character physics, अपना animation system क्यों लिखा?

यह एक जायज़ सवाल है, और "यहाँ नहीं बना तो हम नहीं लेंगे" इसका गलत जवाब है। हमने अपना होमवर्क किया। फैसला लेने से पहले हमने मौजूदा engines चलाए, उनका source पढ़ा, और उनमें से दो के ऊपर spikes ship किए। यह पोस्ट उसी फैसले का ईमानदार वर्ज़न है: तैयार विकल्प असल में किसमें अच्छे हैं, वे चार जगहें जहाँ हमारी ज़रूरतें इतनी ज़्यादा अलग हो गईं कि अपना बनाना सही लगा, और वे हालात जहाँ आपको हमारी नकल करने के बजाय इनमें से कोई एक चुनना चाहिए। हमने इस build को एक लंबी चलने वाली open-world-in-the-browser engineering series में दर्ज किया है, तो नीचे जहाँ किसी दावे के पीछे एक चलता हुआ log है, वहाँ मैं उसका link दूँगा।

जिन विकल्पों को हमने वाकई परखा

चार चीज़ों को "web game engines" कहा जाता है, और वे एक जैसी चीज़ें नहीं हैं।

Three.js एक rendering library है, game engine नहीं। यह आपको एक scene graph, materials, loaders, और एक renderer देता है, और फिर आपके रास्ते से हट जाता है। कोई editor नहीं, कोई physics नहीं, कोई entity system नहीं, आपके game की संरचना को लेकर कोई राय नहीं। यही इसका आकर्षण है और यही इसकी कीमत भी। renderer के ऊपर सब कुछ आप खुद बनाते हैं, पर कोई चीज़ आपसे नहीं लड़ती। यह MIT-licensed है, इस क्षेत्र में इसका ecosystem सबसे बड़ा है, और जब रात के 2 बजे आप किसी अनजान shader bug में फँसते हैं तो एक forum जवाब पहले से मौजूद होता है।

Babylon.js एक पूरा engine है जिसमें एक scene graph, एक physics integration (Havok), एक asset pipeline, और एक web editor है। यह MIT-licensed है, Microsoft की एक टीम इसके पीछे है, और इसका WebGPU काम तेज़ी से आगे बढ़ रहा है। अगर आप सब कुछ शामिल चाहते हैं और engine की संरचना के भीतर रहकर खुश हैं, तो यह एक मज़बूत डिफ़ॉल्ट है।

PlayCanvas "web के लिए Unity" के सबसे करीब है। इसे लिखते वक्त engine v2.19.6 पर है, जो 5 जून 2026 को रिलीज़ हुआ, और engine खुद MIT के तहत open source है। पर ज़्यादातर लोग असल में जो इस्तेमाल करते हैं वह है hosted visual editor, और वह editor एक commercial product है, open source नहीं। PlayCanvas एक entity-component system इस्तेमाल करता है, आप TypeScript या JavaScript में script करते हैं, assets एक server-side GLB pipeline से होकर जाते हैं, और असली commercial games इस पर ship हो चुके हैं (एक के लिए, Snap अपना production काम PlayCanvas पर चलाता है)। इसका renderer WebGL2 पर चलता है, और इसका WebGPU path अभी डिफ़ॉल्ट होने के बजाय पक रहा है। वह आखिरी बात जितनी लगती है उससे ज़्यादा मायने रखती है, और मैं उस पर वापस आऊँगा।

Unity WebGL कोई web engine है ही नहीं। यह एक export target है। आप Unity desktop editor में बनाते हैं और एक WebGL bundle में compile करते हैं। यह तब सही टूल है जब आपके पास पहले से एक Unity game हो और आप उसे एक browser में चाहते हों, और तब गलत टूल है जब "एक mid-range phone पर एक tab में तुरंत load हो जाए" एक सख्त ज़रूरत हो, क्योंकि runtime और download का वज़न साथ में चला आता है।

इनमें से कोई भी एक सामान्य web game के लिए एक वाजिब नींव है। हमारे पास एक सामान्य web game नहीं था।

फैसला एक: WebGPU हमारी फर्श है, हमारी आखिरी रेखा नहीं

जो बँटवारा हमें हर तैयार समाधान से हटाता है वह यह है। हमारे लिए WebGPU एक ज़रूरत है, कोई ऐसी सुविधा नहीं जिसमें हम धीरे-धीरे बढ़ेंगे।

हमारा terrain एक स्थिर heightmap नहीं है। यह एक streamed heightmap field और signed-distance field से समर्थित marching-cubes chunks का एक hybrid है, ताकि world में असली caves और overhangs हो सकें, और creators इसे live sculpt कर सकें। sculpt brushes, foliage scatter, और terrain meshing सब compute shaders की तरह चलते हैं। compute हटा दो तो world बिगड़ता नहीं, वह चलता ही नहीं।

यह ठीक उसके उलट है जहाँ general-purpose engines आज बैठे हैं। उनका WebGPU support एक WebGL2-first renderer के ऊपर progressive enhancement की तरह बनाया गया है, और जिन browsers में यह नहीं है उनके लिए एक fallback path के साथ। खास तौर पर PlayCanvas WebGL2-first है और इसका WebGPU अभी beta में है। उनके लिए यह सही फैसला है, क्योंकि उनका काम है games के सबसे चौड़े संभव मैट्रिक्स को devices के सबसे चौड़े संभव मैट्रिक्स पर चलाना। हमारा काम संकरा और गहरा है, इसलिए हमने उलटा फैसला लिया: हम spike 13 पर WebGPU-only हो गए और फिर कभी पीछे मुड़कर नहीं देखा। WebGPU के बिना browsers को घटाया नहीं जाता, वे असमर्थित हैं, और हम इसे एक reach संख्या की तरह track करते हैं, यह दिखावा करने के बजाय कि एक WebGL2 fallback बस एक config flag दूर है। वह नहीं है। वह हमारे terrain और foliage stages का एक आंशिक rewrite होगा।

एक WebGL2-first engine पर बनाने का मतलब होता या तो हर compute feature पर उसकी fallback मान्यताओं से लड़ना, या हमेशा के लिए दो rendering paths बनाए रखना। renderer का मालिक होने से हमें compute को बेसलाइन की तरह बरतने का मौका मिला।

फैसला दो: एक character solver, एक physics engine नहीं

किताबी चाल है एक physics engine लाकर डाल देना। हमने वह आज़माया। एक शुरुआती spike ने एक worker में Rapier को चलते हुए validate किया, और वह ठीक लगा।

फिर भी हमने अपना खुद का लिखा, और shipped build में कहीं भी Rapier, Cannon, या Ammo नहीं है। वजह है scope। हमें rigid bodies, joints, ragdolls, या एक constraint solver की ज़रूरत नहीं है। हमें एक capsule चाहिए जो terrain के खिलाफ सही ढंग से चले, और हमें walking, sliding, gliding, climbing, और swimming को "मैं grounded हूँ या नहीं, किस surface पर, किस कोण पर" के एक साझा जवाब पर सहमत होना चाहिए। एक general physics engine इसे आसान नहीं, मुश्किल बनाता है, क्योंकि वे modes आखिर में उसके भीतरी springs और dampers से लड़ने लगते हैं।

तो हमारा character controller एक pluggable multi-channel state machine है। हर mode एक छोटी unit है जो बताती है कि क्या वह इस frame में control चाहती है और, अगर वह जीतती है, तो velocity और facing लिखती है। वे तीन channels के पार प्राथमिकता से तय करती हैं, resource फिर stance फिर locomotion, और वे सब एक ही terrain query पढ़ती हैं। Collision chunk के हिसाब से heightmap या signed-distance field के खिलाफ एक capsule probe है।

जिस ब्योरे पर मुझे सबसे ज़्यादा गर्व है वह बेरंग है। Ground detection आपके पैरों के नीचे की ऊर्ध्वाधर column में हर surface को scan करता है और SDF gradient पर भरोसा करने के बजाय capsule के बराबर या नीचे वाली सबसे ऊँची surface चुनता है। एक overhang के किनारे पर बगल में सबसे नज़दीकी surface cliff का चेहरा होती है, तो एक gradient-आधारित normal "floor" और "wall" के बीच टिमटिमाता है और आपको phantom sliding मिलती है। column query एक ledge पर खड़ा होना उबाऊ बना देती है, जो बिलकुल वही है जो आप चाहते हैं। एक तैयार heightfield collider हमें यह मुफ्त में नहीं देता, क्योंकि वह तो हमारे terrain को देख ही नहीं सकता। terrain हमारे format में GPU पर रहता है। कोई बाहरी engine इसके खिलाफ collide नहीं कर सकता बिना हमारे हर edit पर पूरे field को उसके collider format में कॉपी किए।

फैसला तीन: ऐसा animation जो rigs के पार सफर करे

Avatars Synty POLYGON rig इस्तेमाल करते हैं, और हमारे motion clips एक बड़ी open animation library से आते हैं। चूँकि rig और clips bone names साझा करते हैं, आम मामले में runtime पर किसी retargeting की ज़रूरत नहीं होती, tracks बस name से bind हो जाते हैं। हमने पूरी character pipeline को universal characters में लिखा है।

दिलचस्प काम वह मामला है जहाँ वे मेल नहीं खाते। हमने एक retargeting pass बनाया जो एक skeleton को दूसरे पर map करता है, और इसे सही करने का मतलब था तीन खास समस्याएँ हल करना। आप पहले bind poses को align करते हैं, क्योंकि एक T-pose के खिलाफ एक A-pose चुपचाप हर joint पर लगभग तीस डिग्री जोड़ देती है। आप root motion और stride को दो अलग अनुपातों से scale करते हैं, ऊर्ध्वाधर के लिए hip-to-floor और क्षैतिज के लिए कुल अनुपात। और आप retargeted clips को उनके source के खिलाफ एक तय sample rate पर test करते हैं, ताकि regressions एक player के सामने आने से पहले दिख जाएँ। वही pipeline है जो हमें नए animation sources, और आखिरकार creator-supplied characters, जोड़ने देती है बिना हर clip को हाथ से ठीक किए।

उसके ऊपर एक animation state machine बैठता है जो हर frame में motion state से सही clip family चुनता है: speed के हिसाब से jump variant, impact के हिसाब से landing की तीव्रता, terrain gradient के खिलाफ velocity के dot से slope की दिशा, foot-phase-सही stops ताकि आप रुकते वक्त moonwalk न करें, और एक सौ-millisecond का debounce ताकि एक दीवार से टकराने पर आप walk और fall के बीच न टिमटिमाएँ। इसमें से कुछ भी अनोखा नहीं है, पर यह वैसी चीज़ है जो आपको सिर्फ इस layer का मालिक होने से मिलती है।

फैसला चार: वह हिस्सा जो कोई engine ship नहीं करता

बाकी तीन फैसले इस बारे में हैं कि world कैसे चलता है। यह इस बारे में है कि product क्या है, और यही वजह है कि PlayCanvas से तुलना आखिर में एक category की गलती है।

PlayCanvas, Babylon, Unity, और एक हाथ से बना Three.js app सब एक ही आकार मान लेते हैं: आप अपना game एक डेस्क पर, एक 2D editor में बनाते हैं, world को बाहर से देखते हुए, और फिर आप play दबाते हैं और एक अलग runtime ship करते हैं। यहाँ तक कि उनका in-engine editing भी एक workstation पर बैठे आप होते हैं जो एक scene को देखते हुए उससे छेड़छाड़ कर रहे होते हैं।

Cinevva World इसे उलट देता है। आप world के भीतर से, एक avatar के रूप में उसी जगह खड़े होकर जहाँ आपके players खड़े होंगे, यह बताकर कि आप क्या चाहते हैं और उसे प्रकट होते हुए देखकर बनाते हैं। Creation और play एक लगातार चलने वाला session हैं, एक runtime से जुड़ा कोई build step नहीं। सबसे करीबी संदर्भ बिंदु Roblox, Rec Room, और Horizon Worlds हैं, web 3D engines नहीं, और वे भी ज़्यादातर creation को एक डेस्क पर ही रखते हैं। जो चीज़ इसे एक mouse-चालित editor के बिना संभव बनाती है वह है AI builder, जो "यहाँ एक lantern से रोशन dock रखो" को geometry और placement में बदल देता है।

आप इसे एक general-purpose engine पर जोड़ नहीं सकते, क्योंकि यह कोई rendering feature नहीं है। यह पूरे stack की बुनियादी मान्यता है, इस बात से कि terrain runtime पर कैसे editable है, इस बात तक कि network हर object को कैसे ऐसी चीज़ की तरह बरतता है जिसे पास खड़े किसी इंसान ने अभी बनाया हो।

आपको कब वह नहीं करना चाहिए जो हमने किया

यह वह हिस्सा है जिसे "हमने अपना engine बनाया" वाली पोस्टें आम तौर पर छोड़ देती हैं। अगर आप इसी तिमाही एक browser game ship करना चाहते हैं, तो हमारी नकल मत करिए। PlayCanvas इस्तेमाल करिए अगर आप एक Unity-शैली का editor और एक managed pipeline चाहते हैं। Babylon इस्तेमाल करिए अगर आप physics सहित एक पूरा engine चाहते हैं और उसकी संरचना के भीतर खुश हैं। Three.js इस्तेमाल करिए अगर आप ज़्यादा से ज़्यादा control और कम से कम राय चाहते हैं और आपके पास इसके ऊपर बनाने वाली टीम है। Unity से port करिए अगर आपके पास पहले से एक Unity game है।

अपना खुद का renderer, physics, और animation लिखना सिर्फ तभी सही फैसला है जब आपके product की बुनियादी मान्यता तैयार समाधानों के साथ बेमेल हो, जब आप जो बना रहे हैं वह किसी engine पर एक game न होकर एक ऐसी जगह हो जो संयोग से एक engine से बनी है। हमारे लिए यह सच था। आपके लिए शायद सच नहीं है, और यह ठीक है। मूल्यांकन ईमानदारी से करने का मकसद यही है कि पहली लाइन लिखने से पहले आप जान लें कि आप किस मामले में हैं।