<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title><![CDATA[Cinevva Blog]]></title>
        <link>https://app.cinevva.com</link>
        <description><![CDATA[Pembaruan produk, catatan kreator, dan eksperimen.]]></description>
        <lastBuildDate>Sun, 16 Aug 2026 04:06:16 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>scripts/build-rss.mjs</generator>
        <copyright>Copyright 2024-present Cinevva</copyright>
        <item>
            <title><![CDATA[Menyimulasikan runtime yang berkata tidak: cara kami membuat sandbox browser agar bertindak seperti WeChat]]></title>
            <link>https://app.cinevva.com/id/blog/2026-07-19-sandboxing-wechat-strict-mode</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-07-19-sandboxing-wechat-strict-mode</guid>
            <pubDate>Sun, 19 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Kreator game AI kami kini menghasilkan game yang dapat di-porting ke WeChat, tetapi aturan dalam prompt hanyalah saran. Jadi, kami membangun sandbox mode ketat ke dalam pratinjau: skrip yang membuat browser melempar error pada kondisi yang juga akan ditolak WeChat, lalu mengirimkan pelanggaran langsung kembali ke loop debugging AI itu sendiri. Berikut desainnya, daftar racunnya, dan empat pengecualian yang paling banyak memberi kami pelajaran.]]></description>
            <content:encoded><![CDATA[<h1>Menyimulasikan runtime yang berkata tidak: cara kami membuat sandbox browser agar bertindak seperti WeChat</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<img src="https://cdn.cinevva.com/blog/wechat-strict-sandbox-hero.jpg" alt="Sebuah adegan game 3D kecil di dalam kubah kaca transparan, dengan ikon alat yang dicoret melayang di luar kaca" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Kami baru-baru ini merilis <a href="/id/news/2026-07-19-wechat-mini-game-mode">mode mini game WeChat</a> di Game Creator kami: profil build yang menjaga game buatan AI tetap berada dalam subset platform web yang dapat bertahan ketika di-porting ke runtime WeChat. Profil ini berupa serangkaian aturan pembuatan. Tanpa UI DOM, tanpa Pointer Lock, audio hanya mp3, dan tanpa kode dinamis. Model mengikuti aturan tersebut sebagaimana model biasanya mengikuti aturan, yaitu: biasanya.</p>
<p>“Biasanya” tidak cukup ketika setiap pelanggaran tidak terlihat di browser tetapi berakibat fatal setelah diekspor. Game dengan bilah kesehatan HTML berjalan sempurna di pratinjau kami, tetapi hanya menampilkan layar kosong di WeChat karena mini game WeChat sama sekali tidak memiliki DOM. Jadi, kami membangun sesuatu yang mengubah aturan tersebut dari sekadar saran menjadi hukum fisika: sandbox mode ketat yang membuat browser itu sendiri menolak melakukan hal-hal yang tidak dapat dilakukan WeChat. Tulisan ini membahas cara kerjanya.</p>
<h2>Keputusan inti: simulasikan ketiadaan, bukan keberadaan</h2>
<p>Pendekatan yang paling jelas adalah mengemulasikan WeChat: mengimplementasikan <code>wx.createCanvas</code>, <code>wx.onTouchStart</code>, <code>wx.setStorageSync</code>, lalu menjalankan game terhadap permukaan API <code>wx.*</code> yang diemulasikan. Kami memilih arah sebaliknya, dan alasannya terletak pada bentuk pipeline ekspor kami.</p>
<p>Game dalam mode WeChat tetap ditulis menggunakan API browser. Saat pengemasan, sebuah adaptor (dengan pendekatan weapp-adapter yang menjadi standar komunitas) memetakan API browser tersebut ke <code>wx.*</code>. Artinya, game kami tidak pernah memanggil <code>wx.*</code> secara langsung, sehingga emulator <code>wx</code> akan menguji jalur kode yang sebenarnya tidak ada. Penyebab port gagal bukanlah ketiadaan <code>wx.*</code> di browser. Penyebabnya adalah <em>keberadaan</em> API browser yang tidak memiliki padanan di WeChat dan diam-diam digunakan selama proses pembuatan. <code>document.createElement('div')</code>. <code>requestPointerLock()</code>. IndexedDB. File <code>.ogg</code> yang dapat didekode dengan baik di Chrome tetapi tidak akan pernah bisa di WeChat pada iOS.</p>
<p>Karena itu, sandbox menyimulasikan ketiadaan. Segala sesuatu yang tidak dimiliki WeChat dihapus, diracuni, atau ditandai dalam pratinjau, sehingga sejak frame pertama game dikembangkan di dalam irisan kemampuan kedua platform.</p>
<h2>Tempatnya berada: service worker yang sudah tersedia</h2>
<p>Pratinjau editor kami memiliki jalur penyajian yang tidak biasa sehingga penerapan ini nyaris tanpa biaya. Game di editor tidak disajikan dari jaringan. Sebuah service worker mencegat permintaan <code>/game/*</code> dan menyajikan file dari IndexedDB, sehingga iframe pratinjau dapat dimuat ulang secara instan tanpa perjalanan bolak-balik ke server. Worker tersebut sudah menyuntikkan dua file virtual ke setiap halaman game: skrip penangkap error yang meneruskan output konsol dan crash ke editor, serta pemeriksa adegan secara langsung.</p>
<p>Sandbox menjadi file virtual ketiga, <code>_wechat-strict.js</code>, yang disuntikkan ke <code>&lt;head&gt;</code> halaman tepat setelah skrip penangkap dan sebelum kode game apa pun dijalankan. Urutan ini sangat krusial karena dua alasan. Sandbox harus berjalan setelah skrip penangkap agar panggilan <code>console.error</code> miliknya sudah terhubung dan diteruskan ke editor, serta sebelum modul game agar racun sudah terpasang ketika baris pertama kode game dieksekusi.</p>
<p>Aktivasinya menggunakan trik satu baris. Toggle WeChat di kreator disimpan dalam <code>localStorage</code>, dan iframe pratinjau memiliki origin yang sama dengan editor, sehingga harness cukup membaca flag tersebut secara langsung:</p>
<pre><code class="language-js">try {
  if (localStorage.getItem('cinevva-gc-profile') !== 'wechat-minigame') return;
} catch (e) { return; }
</code></pre>
<p>Untuk setiap game non-WeChat, skrip ini hanya melakukan satu perbandingan string lalu keluar lebih awal. Tidak ada flag build, perjalanan bolak-balik ke server, maupun state yang perlu disinkronkan dengan service worker.</p>
<h2>Daftar racun dan taksonomi dua tingkat</h2>
<p>Tidak setiap pelanggaran layak mendapat respons yang sama, sehingga harness membedakan dua tingkat. API yang <em>tidak tersedia</em> di WeChat akan melempar error karena itulah yang terjadi setelah ekspor, dan crash saat pembuatan merupakan pratinjau yang jujur atas crash saat peninjauan. Hal-hal yang <em>tersedia tetapi akan bermasalah kemudian</em> ditandai sebagai error konsol yang mencolok tanpa mengubah perilakunya, karena memblokirnya justru akan menyembunyikan keadaan game yang sebenarnya dari orang yang sedang mengiterasinya.</p>
<p>Tingkat lempar error: pembuatan elemen UI HTML apa pun melalui <code>createElement</code> maupun <code>createElementNS</code> (Three.js membuat canvas melalui varian NS, sehingga kedua jalur memerlukan gerbang yang sama), <code>eval</code>, <code>new Function</code>, <code>requestPointerLock</code>, dan pendaftaran service worker. Setiap error yang dilempar menyertakan cara memperbaikinya di dalam pesan:</p>
<pre><code class="language-js">throw violate(&quot;document.createElement('&quot; + tag + &quot;') — Mini game WeChat tidak memiliki DOM. &quot; +
  &quot;Gambar UI di canvas (canvas 2D offscreen -&gt; THREE.CanvasTexture pada quad screen-space) &quot; +
  &quot;dan lakukan hit-test ketukan sendiri.&quot;);
</code></pre>
<p>Tingkat penandaan: membaca <code>indexedDB</code> (mengembalikan <code>undefined</code>, persis seperti WeChat, ditambah error yang mengarahkan ke <code>localStorage</code>), audio dalam format apa pun yang tidak dapat didekode oleh WeChat iOS (diperiksa di tiga tempat: konstruktor <code>Audio</code>, setter <code>src</code> pada prototipe elemen media, dan URL yang diambil), permintaan jaringan ke origin apa pun selain milik game atau CDN aset kami (di WeChat, origin tersebut memerlukan domain yang masuk daftar izin dan terdaftar ICP), serta kemunculan Tone.js dalam bentuk apa pun.</p>
<p>Ada juga audit pascapemuatan yang berjalan sesaat setelah halaman stabil: audit ini menelusuri <code>&lt;body&gt;</code> dan melaporkan elemen HTML apa pun yang berasal dari markup milik game, bukan dari pembuatan dinamis. HUD statis dapat lolos dari gerbang <code>createElement</code>, jadi gerbang tersebut saja tidak cukup.</p>
<p>Setiap laporan dideduplikasi berdasarkan pesan dan dibatasi maksimal lima puluh per sesi. Bug loop terbalik yang membuat satu div per frame hanya menghasilkan satu error, bukan banjir pesan yang menenggelamkan sinyal penting.</p>
<h2>Empat pengecualian yang paling banyak memberi kami pelajaran</h2>
<p>Membangun sandbox sebagian besar berarti memutuskan apa yang <em>tidak</em> boleh diracuni, dan setiap pengecualian yang kami buat berasal dari alat kami sendiri yang rusak selama pengembangan.</p>
<p><strong>Debugger kami berjalan menggunakan eval.</strong> Alat <code>execute_js</code> milik kreator, yang digunakan AI untuk memeriksa game yang sedang berjalan, mengevaluasi kode melalui handler pesan milik skrip penangkap, yang memanggil <code>eval</code>. Meracuni <code>eval</code> secara naif akan membutakan AI itu sendiri. Solusinya: sebelum meracuni, harness menyimpan fungsi asli pada properti non-enumerable, lalu handler skrip penangkap menggunakannya sebagai fallback:</p>
<pre><code class="language-js">Object.defineProperty(window, '__cinevvaRealEval', { value: window.eval, enumerable: false });
window.eval = function () { throw violate('eval() dilarang dalam mini game WeChat.'); };
// skrip penangkap, saat menerima pesan:
returnValue = (window.__cinevvaRealEval || eval)(e.data.code);
</code></pre>
<p>Kode game yang mencoba menggunakan <code>eval</code> tetap berhenti. Debugger tidak.</p>
<p><strong>Perekam juga membuat elemen.</strong> Perekam reel kami disuntikkan ke iframe game sebagai <code>&lt;script&gt;</code> yang dibuat dengan <code>document.createElement</code> milik iframe itu sendiri, dan perekam mengunduh video yang selesai melalui klik sintetis pada <code>&lt;a&gt;</code>. Memblokir tag tersebut akan merusak perekaman secara khusus dan hanya dalam mode WeChat. Karena itu, <code>script</code> tetap diizinkan dan <code>a</code> memunculkan peringatan tanpa melempar error. Game yang benar-benar menyertakan tautan tetap akan ditandai, sementara alat kami tetap berfungsi.</p>
<p><strong>Event keyboard tetap tersedia.</strong> AI memverifikasi kontrol menggunakan alat yang menyintesis penekanan tombol dan membaca kembali perubahan state game. Menonaktifkan input keyboard untuk menyimulasikan ponsel akan menghancurkan loop verifikasi kontrol yang mendeteksi bug kamera terbalik. Pendekatan touch-first diterapkan melalui aturan pembuatan dan skema kontrol profil, bukan oleh sandbox.</p>
<p><strong>WebGL2 tetap tersedia, dan alasannya layak dibahas dalam bagian tersendiri di bawah.</strong> Draf daftar racun memblokir <code>getContext('webgl2')</code> untuk memaksakan rendering “aman untuk WebGL1” yang diwajibkan profil. Namun, Three.js <a href="https://github.com/mrdoob/three.js/releases/tag/r163">menghapus dukungan WebGL1 sepenuhnya pada r163</a>, sementara kami menetapkan r181: memblokir WebGL2 akan membuat setiap game 3D dalam mode ini menjadi kosong. Aturan rendering profil tersebut tidak koheren karena ditulis berdasarkan pemahaman usang tentang platform. Audit sandbox justru mengaudit spesifikasi sandbox itu sendiri, dan ketika kami menelusuri persoalan tersebut lebih jauh, kami menemukan sesuatu yang penting.</p>
<h2>Pertanyaan tentang WebGL2, dijawab dengan semestinya</h2>
<p>Membiarkan pembuatan context apa adanya memunculkan pertanyaan lanjutan yang jelas: jika engine kami memerlukan WebGL2, apakah game akan rusak pada perangkat WeChat yang hanya memiliki WebGL1? Penelusuran atas pertanyaan tersebut menghasilkan gambaran paling jelas yang kami miliki tentang batas minimum rendering platform, jadi berikut penjelasannya beserta sumber.</p>
<p>Di Android, runtime mini game WeChat menyediakan WebGL2 pada setiap base library modern, dan perangkat keras GLES3 yang mendasarinya pada praktiknya tersedia secara universal. iOS adalah persoalan sebenarnya. Dokumentasi teknis WeChat sendiri untuk <a href="https://wechat-miniprogram.github.io/minigame-unity-webgl-transform/Design/WebGL2.html">dukungan WebGL2</a> dan <a href="https://developers.weixin.qq.com/minigame/dev/guide/performance/perf-high-performance-plus.html">mode high-performance+</a> menjelaskan bahwa pada iPhone, WebGL2 hanya tersedia dengan benar dalam runtime high-performance+, yang memerlukan klien WeChat terbaru (8.0.45 atau lebih baru, dengan versi lebih tinggi pada iOS 14) dan pada praktiknya membutuhkan iOS 15.5 atau lebih baru. Mode high-performance biasa menjalankan WebGL2 “dengan lebih banyak masalah”, menurut deskripsi Tencent sendiri, sedangkan runtime iOS normal sama sekali tidak memilikinya.</p>
<p>Bagian yang benar-benar berbahaya adalah bentuk kegagalannya. Dalam lingkungan yang tidak didukung, <code>getContext('webgl2')</code> dapat mengembalikan context yang truthy tetapi rusak, bukan null, sebuah perilaku yang telah <a href="https://developers.weixin.qq.com/community/develop/doc/000aee72868a381d6c261686651c00">diminta langsung oleh developer agar diperbaiki Tencent</a>. Game yang memercayai nilai kembalian tersebut tidak akan gagal dengan bersih. Game itu akan merender gambar kacau atau layar hitam tanpa pesan.</p>
<p>Jadi, kami menanganinya dalam tiga lapisan. Sandbox membiarkan pembuatan context WebGL2 apa adanya karena meracuninya berarti melawan engine kami sendiri. Profil pembuatan kini mewajibkan boot gate di setiap game: pembuatan renderer dibungkus dengan try/catch, lalu dilanjutkan dengan pemeriksaan fungsional (<code>typeof gl.createVertexArray === 'function'</code>, kemampuan khusus WebGL2 yang tidak akan dimiliki context palsu), dengan pesan ramah “silakan perbarui WeChat” yang digambar di canvas ketika gagal, alih-alih layar kosong. Ini adalah pola yang sama dengan mini game hasil konversi Unity, sehingga di penggunaan nyata Anda melihat permintaan upgrade, bukan layar hitam. Dan ketika exporter kami tersedia, exporter tersebut akan menetapkan mode high-performance+ di <code>game.json</code> agar jalur yang mampu menjalankannya menjadi jalur default.</p>
<p>Berapa besar pengguna yang terdampak oleh batas minimum WebGL2? Pengguna dengan versi di bawah sekitar iOS 15.5 atau klien WeChat yang lebih lama dari 8.0.45—persentase satu digit rendah pada 2026, tetapi terkonsentrasi pada perangkat lama, dan dampaknya lebih penting bagi genre tertentu dibandingkan genre lainnya. Jika data distribusi nyata kelak menunjukkan bahwa kelompok kecil tersebut layak dikejar, kami menyimpan jalan keluar murah sebagai cadangan: menetapkan profil WeChat ke three r162, rilis terakhir yang mendukung WebGL1. Game profil hanya menggunakan API inti yang stabil, sehingga downgrade tersebut cukup berupa perubahan satu baris pada import map, dan sengaja belum kami gunakan sampai data menuntutnya.</p>
<h2>Menutup loop bersama model</h2>
<p>Inilah bagian yang membuat pembangunan ini layak dilakukan untuk produk yang mengutamakan AI. Setelah setiap build, agen kreator memanggil alat yang membaca konsol game dan menunggu proses boot selesai. Skrip penangkap meneruskan <code>console.error</code> ke aliran tersebut. Jadi, pelanggaran <code>[wechat-strict]</code> bukanlah peringatan yang mungkin dilewati manusia saat menggulir. Pelanggaran itu masuk ke kanal yang sama persis dengan yang sudah diperiksa model sebelum menyatakan build selesai, pada giliran yang sama, dengan cara perbaikan yang dijelaskan langsung dalam pesannya.</p>
<p>Profil pembuatan menutup celah terakhir dengan satu instruksi: perlakukan setiap pesan <code>[wechat-strict]</code> sebagai bug yang menggagalkan build, perbaiki penyebabnya, dan jangan pernah mencoba mendeteksi atau melewati harness. Game yang hanya berjalan ketika sandbox dimatikan adalah game yang akan gagal setelah diekspor, dan model diberi tahu persis tentang hal tersebut.</p>
<p>Pada dasarnya, sandbox mengubah masalah kepatuhan yang kabur (“apakah model mengikuti keempat belas aturan?”) menjadi loop debugging yang sudah dikuasai sistem (“konsol menampilkan error, perbaiki”).</p>
<h2>Hal-hal yang tidak dapat disimulasikan browser</h2>
<p>Bagian kejujuran. Sandbox ini menangkap pelanggaran pada permukaan API, yang menurut perkiraan kami mencakup sebagian besar penyebab kegagalan port. Sandbox ini tidak dapat mendeteksi: performa pada ponsel sungguhan, iOS yang menjalankan JavaScript tanpa JIT, keunikan implementasi WebGL milik WeChat, atau perbedaan perilaku codec selain yang dapat diketahui dari ekstensi file. Semua itu memerlukan runtime asli.</p>
<p>Karena itu, sandbox adalah lingkar pertama dari tiga. Lingkar kedua, setelah exporter kami menghasilkan proyek WeChat DevTools, adalah simulator resmi yang dijalankan secara headless melalui DevTools CLI dan miniprogram-automator: boot paket hasil ekspor, pastikan frame pertama dirender, lalu skripkan satu ketukan. Lingkar ketiga adalah jalur perangkat resmi, yaitu kode QR pratinjau dan debugging jarak jauh pada ponsel fisik, tempat berbagai fakta yang tidak dapat diungkap oleh apa pun selain perangkat asli muncul. Setiap lingkar lebih lambat dan lebih akurat daripada lingkar sebelumnya, dan tugas masing-masing adalah membuat kebutuhan untuk masuk ke lingkar berikutnya menjadi jarang.</p>
<p>Jika ingin mencoba mode ini, gunakan toggle “mode mini game WeChat” di <a href="/id/create">Game Creator</a>. Untuk konteks pasar dan regulasi seputar semua ini, lihat <a href="/id/blog/2026-07-19-wechat-mini-games-guide-for-developers-outside-china">panduan lapangan kami untuk menjangkau setengah miliar pemain WeChat</a>.</p>
<h2>Referensi</h2>
<ul>
<li><a href="https://developers.weixin.qq.com/minigame/dev/guide/runtime/js-support.html">Dokumentasi resmi WeChat: dukungan JavaScript dalam mini game</a></li>
<li><a href="https://developers.weixin.qq.com/minigame/en/dev/guide/best-practice/adapter.html">Dokumentasi resmi WeChat: lapisan adaptor</a></li>
<li><a href="https://developers.weixin.qq.com/minigame/dev/guide/performance/perf-high-performance-plus.html">Dokumentasi resmi WeChat: mode high-performance+</a></li>
<li><a href="https://wechat-miniprogram.github.io/minigame-unity-webgl-transform/Design/WebGL2.html">Dokumentasi rekayasa WeChat: dukungan rendering WebGL2 dalam mini game</a></li>
<li><a href="https://github.com/wechat-miniprogram/minigame-unity-webgl-transform/blob/main/Design/iOSOptimization.md">Dokumentasi rekayasa WeChat: mode high-performance dan high-performance+ di iOS</a></li>
<li><a href="https://developers.weixin.qq.com/community/develop/doc/000aee72868a381d6c261686651c00">Komunitas pengembang WeChat: konteks webgl2 yang rusak seharusnya mengembalikan null</a></li>
<li><a href="https://developers.weixin.qq.com/miniprogram/en/dev/devtools/auto/">Dokumentasi resmi WeChat: miniprogram-automator</a></li>
<li><a href="https://github.com/mrdoob/three.js/releases/tag/r163">Catatan rilis Three.js r163 (dukungan WebGL1 dihapus)</a></li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Mini game WeChat: pasar game instan terbesar yang tidak bisa langsung Anda tuju]]></title>
            <link>https://app.cinevva.com/id/blog/2026-07-19-wechat-mini-games-guide-for-developers-outside-china</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-07-19-wechat-mini-games-guide-for-developers-outside-china</guid>
            <pubDate>Sun, 19 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[500 juta pemain bulanan, pasar senilai $5,6 miliar yang berlipat ganda dalam setahun, dan platform yang tidak dapat dijangkau game web Anda hanya dengan sebuah URL. Apa sebenarnya mini game WeChat, regulasi yang akan Anda hadapi sebagai developer di luar Tiongkok, satu-satunya jalur monetisasi yang tidak memerlukan lisensi, dan bagaimana mode mini game baru Cinevva berperan di dalamnya.]]></description>
            <content:encoded><![CDATA[<h1>Mini game WeChat: pasar game instan terbesar yang tidak bisa langsung Anda tuju</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Salah Satu Pendiri Cinevva</em></p>
<img src="https://cdn.cinevva.com/blog/wechat-mini-games-market-hero.jpg" alt="Ponsel pintar yang menampilkan sebuah mini game di depan gerbang dengan stempel persetujuan, dokumen bercap, dan koin di sampingnya" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Jika Anda membuat game web, ada pasar dengan setengah miliar pemain bulanan yang tidak dapat dijangkau game Anda, sebaik apa pun dukungan selulernya. Pasar itu berada di dalam WeChat, pendapatannya hampir berlipat ganda tahun lalu, dan untuk memasukinya diperlukan port teknis sekaligus proses regulasi yang belum pernah didengar oleh kebanyakan developer Barat.</p>
<p>Kami baru saja merilis bagian pertama dari solusi kami: <a href="/id/news/2026-07-19-wechat-mini-game-mode">mode mini game WeChat</a> eksperimental di Cinevva Game Creator. Artikel ini menyajikan kisah lengkapnya: apa sebenarnya platform ini, apa saja aturannya, dan seperti apa jalur yang realistis bagi developer di luar Tiongkok.</p>
<h2>Pasarnya, dalam angka yang mudah diremehkan</h2>
<p>WeChat adalah aplikasi komunikasi utama di Tiongkok, dengan total lebih dari 1,4 miliar pengguna aktif bulanan. Mini game tersedia di dalamnya sebagai pengalaman yang dapat langsung dimainkan dengan satu ketukan: tanpa instalasi, tanpa toko aplikasi, dan dapat diluncurkan dari pesan obrolan, pencarian, atau tautan yang dibagikan. Pada 2025, Tencent mengumumkan bahwa platform mini game telah melampaui 500 juta pengguna aktif bulanan, dengan lebih dari satu miliar pemain terdaftar dan sekitar 500.000 developer.</p>
<p>Uang yang beredar juga nyata. Pasar mini game Tiongkok menghasilkan 39,8 miliar yuan pada 2024, sekitar $5,6 miliar, naik 99% dibandingkan tahun sebelumnya. Sekitar 69% berasal dari pembelian dalam aplikasi dan 31% dari iklan. Ingat pembagian ini, karena porsi iklan ternyata sangat penting bagi developer asing.</p>
<p>Sebagai perbandingan: pendapatan mini game dalam satu tahun tersebut sebanding dengan keseluruhan pasar game web global yang menjadi tempat beroperasinya platform seperti Poki, CrazyGames, dan <a href="http://itch.io">itch.io</a>. Ini bukan pasar khusus berukuran kecil. Ini adalah semesta paralel dengan aturannya sendiri.</p>
<h2>Mengapa game web Anda tidak bisa langsung di-port</h2>
<p>Mini game WeChat terlihat seperti game web dan ditulis dalam JavaScript, sehingga asumsi wajarnya adalah proses port dapat diselesaikan dalam satu akhir pekan. Kenyataannya tidak demikian, dan alasannya bersifat struktural.</p>
<p>Mini game tidak berjalan di browser. Game tersebut berjalan di runtime milik WeChat yang menyediakan canvas, WebGL, dan serangkaian API <code>wx.*</code>. Tidak ada DOM maupun CSS. Setiap tombol, bilah kesehatan, menu, dan dialog dalam game harus digambar di canvas dan menjalani hit testing oleh kode Anda sendiri. Jika UI game Anda menggunakan HTML, UI tersebut tidak akan ada di WeChat.</p>
<p>Model inputnya berbeda. Tidak ada Pointer Lock maupun mouse, sehingga kamera FPS bergaya desktop harus diubah agar sudut pandang dikendalikan dengan gestur seret. Perangkat utamanya tidak memiliki keyboard. Jika game Anda tidak sepenuhnya dapat dimainkan hanya dengan sentuhan, game tersebut tidak dapat dimainkan.</p>
<p>Paket utama dibatasi hingga 4 MB, sedangkan ukuran total dengan subpaket dibatasi hingga 20 MB. Semua yang dijalankan game Anda harus berada di dalam paket yang telah ditinjau tersebut. Ini membawa kita ke aturan yang membentuk keseluruhan platform: WeChat melarang kode yang dieksekusi secara dinamis. Tidak boleh ada <code>eval</code>, <code>new Function</code>, pengunduhan JavaScript saat runtime, dan Tencent secara aktif menolak aplikasi yang menyematkan interpreter JS untuk mengakali pembatasan tersebut. Setiap game adalah artefak tertutup yang telah ditinjau.</p>
<p>Aturan terakhir itulah yang membuat “aplikasi portal” untuk menayangkan game web secara streaming ke WeChat tidak akan pernah ada, baik milik kami maupun siapa pun. Setiap game harus melalui peninjauan sebagai mini game mandiri. Alat apa pun yang ingin membantu Anda di sini harus membantu menghasilkan paket yang bersih, mandiri, dan hanya menggunakan canvas. Itulah batasan desain yang menjadi landasan mode baru kami.</p>
<h2>Realitas regulasi</h2>
<p>Sekarang bagian yang sama sekali tidak berkaitan dengan kode. Tiongkok mengatur game sebagai media yang diterbitkan, dan persyaratannya bertumpuk dalam beberapa lapisan. Tidak ada satu pun yang dirahasiakan, tetapi hampir tidak ada yang menjelaskannya secara gamblang di luar Tiongkok. Jadi, inilah penjelasannya.</p>
<p><strong>Pendaftaran ICP.</strong> Sejak akhir 2023, setiap mini program dan mini game harus menyelesaikan pendaftaran ICP (pendaftaran kepada otoritas Tiongkok yang dilakukan melalui platform WeChat). Prosesnya biasanya memakan waktu satu hingga tiga minggu.</p>
<p><strong>Bukti hak cipta untuk setiap judul.</strong> Setiap game memerlukan registrasi hak cipta perangkat lunak atau sertifikasi hak cipta elektronik yang lebih cepat. Jalur elektronik memakan waktu sekitar sepuluh hingga lima belas hari per game. Biaya ini berlaku untuk setiap judul, yang perlu diperhitungkan jika Anda berencana merilis banyak game kecil.</p>
<p><strong>Banhao, jika Anda memungut pembayaran.</strong> Setiap game dengan pembelian dalam aplikasi memerlukan lisensi penerbitan game dari National Press and Publication Administration, yang umum disebut banhao. Ada dua fakta penting bagi Anda sebagai developer asing. Pertama, hanya perusahaan Tiongkok yang dapat mengajukan permohonan. Kedua, judul impor menjalani jalur persetujuan terpisah yang lebih lambat, secara historis memakan waktu enam hingga delapan bulan jika prosesnya berjalan. Dalam praktiknya, developer di luar Tiongkok hanya dapat menerbitkan game yang dimonetisasi melalui penerbit lokal berlisensi yang mengajukan game tersebut, memegang lisensinya, dan mengoperasikannya.</p>
<p><strong>Pengecualian untuk game gratis dengan iklan.</strong> Game gratis tanpa pembayaran dalam bentuk apa pun tidak memerlukan banhao. Game tersebut tetap dapat menghasilkan uang melalui komponen iklan milik WeChat. Dan ingat, iklan menyumbang 31% pendapatan mini game pada 2024, atau lebih dari $1,7 miliar. Inilah satu-satunya jalur yang dapat ditempuh developer kecil tanpa mitra perusahaan Tiongkok, dan begitulah sebagian besar segmen long tail di pasar ini beroperasi.</p>
<p>Ringkasan apa adanya: merilis mini game gratis yang didukung iklan memerlukan urusan administrasi selama beberapa minggu. Merilis game yang dimonetisasi adalah proyek pengembangan bisnis selama beberapa bulan, dengan mitra yang harus Anda pilih secara cermat.</p>
<h2>Cara mode mini game Cinevva menangani semua ini</h2>
<p>Kami tidak dapat mengurus dokumen Anda. Namun, kami dapat memastikan bahwa game itu sendiri tidak pernah menjadi penghambat, mulai dari prompt pertama.</p>
<p>Dengan mode mini game WeChat aktif, Game Creator membuat game dalam subset yang portabel: UI yang digambar di canvas alih-alih HTML, kontrol yang mengutamakan sentuhan dengan gestur seret untuk mengubah sudut pandang alih-alih pointer lock, rendering yang disesuaikan dengan kemampuan ponsel kelas menengah disertai layar fallback yang baik saat WebGL2 sesungguhnya tidak tersedia, batas aset yang ketat dengan audio khusus mp3, tanpa impor dinamis, tanpa pemuatan kode saat runtime, serta penyimpanan progres yang dipetakan ke API penyimpanan WeChat. Game tersebut tetap berjalan di browser seperti game Cinevva lainnya, sehingga Anda dapat membuat, menguji, dan membagikannya seperti biasa. Game itu hanya tetap berada dalam subset yang dapat bertahan melalui proses port.</p>
<p>Eksportir yang menghasilkan proyek WeChat DevTools siap buka dari salah satu game ini masih dalam pengembangan. Kami sengaja menyusun urutannya seperti ini. Eksportir dapat mengemas kode Anda, tetapi tidak dapat menghapus HUD berbasis HTML atau merancang ulang kontrol yang hanya menggunakan mouse. Portabilitas ditentukan oleh cara game dibuat, sehingga mode ini harus hadir terlebih dahulu.</p>
<p>Jika Anda telah membaca <a href="/id/guides/wechat-mini-game-engines">panduan mesin mini game</a> atau <a href="/id/guides/publish-wechat-douyin-mini-games">panduan penerbitan untuk WeChat dan Douyin</a>, inilah pemikiran yang sama yang diterapkan pada proses pembuatan: port termurah adalah port yang tidak perlu Anda lakukan.</p>
<h2>Strategi realistis bagi developer di luar Tiongkok</h2>
<p>Inilah yang benar-benar akan kami lakukan untuk judul pertama. Buat game yang kecil dengan sesi singkat, karena itulah yang dihargai platform ini: game populer di sini adalah game yang mendorong pemain untuk mencoba sekali lagi, bukan kisah epik. Rancang dengan orientasi potret sebagai prioritas dan hanya menggunakan kontrol sentuh. Rilis secara gratis dengan iklan agar Anda tidak memasuki wilayah banhao sembari mempelajari apakah pemain Tiongkok benar-benar menginginkan game Anda. Urus sendiri pendaftaran ICP dan sertifikasi hak cipta elektronik; prosesnya memang membosankan, tetapi masih dapat ditangani. Hanya setelah game terbukti memiliki retensi yang baik dan Anda melihat potensi IAP yang nyata, mulailah pembicaraan dengan penerbit sambil membawa data, karena negosiasi dengan penerbit akan berjalan sangat berbeda ketika game Anda sudah memiliki audiens.</p>
<p>Itulah strategi yang ingin didukung oleh mode baru ini: membuat proses menghasilkan calon game hampir tanpa biaya, sehingga Anda mampu mencari tahu apa yang berhasil sebelum mulai mengeluarkan biaya untuk regulasi.</p>
<p>Jika Anda berencana memasuki pasar ini, kami benar-benar ingin mendengar dari Anda selagi mode ini masih dikembangkan. <a href="/id/contact">Hubungi kami</a> atau mulailah membuat game di <a href="/id/create">Game Creator</a>.</p>
<h2>Referensi</h2>
<ul>
<li><a href="https://www.pocketgamer.biz/wechat-mini-games-crosses-500m-monthly-active-users-as-tencent-shifts-focus-to-retention/">PocketGamer.biz: Mini Game WeChat melampaui 500 juta pengguna aktif bulanan</a></li>
<li><a href="https://www.ichongqing.info/2025/07/02/wechat-mini-games-hits-1b-users-becomes-global-magnet-for-game-developers/">iChongqing: Mini Game WeChat mencapai 1 miliar pengguna</a></li>
<li><a href="https://www.oreateai.com/blog/2025-wechat-mini-game-ecosystem-development-report-indepth-analysis-of-market-trends-and-typical-cases/7f0b62beb192f52409ae047d0bbae184">Oreate: Laporan perkembangan ekosistem mini game WeChat 2025 (data pasar 2024)</a></li>
<li><a href="https://developers.weixin.qq.com/minigame/dev/guide/runtime/js-support.html">Dokumentasi resmi WeChat: dukungan JavaScript dan larangan kode dinamis</a></li>
<li><a href="https://developers.weixin.qq.com/minigame/en/dev/guide/best-practice/adapter.html">Dokumentasi resmi WeChat: lapisan adaptor untuk kode bergaya browser</a></li>
<li><a href="https://nikopartners.com/game-regulations-in-china-everything-you-need-to-know/">Niko Partners: regulasi game di Tiongkok</a></li>
<li><a href="https://clearlaunch.dev/regulations/china-game-approval">ClearLaunch: persyaratan dan penegakan persetujuan game Tiongkok (banhao)</a></li>
<li><a href="https://appinchina.co/blog/the-complete-guide-to-wechat-mini-games/">AppInChina: panduan lengkap mini game WeChat</a></li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Rekor laba, rekor PHK: bagaimana developer game benar-benar kembali direkrut pada 2026]]></title>
            <link>https://app.cinevva.com/id/blog/2026-07-02-game-industry-layoffs-getting-rehired</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-07-02-game-industry-layoffs-getting-rehired</guid>
            <pubDate>Thu, 02 Jul 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Industri game menghasilkan $195,6 miliar tahun lalu dan tetap memangkas sepertiga tenaga kerjanya. Berikut data sebenarnya tentang PHK, alasan pasar kerja menjadi begitu kejam, dan satu hal yang benar-benar membuat orang kembali direkrut.]]></description>
            <content:encoded><![CDATA[<h1>Rekor laba, rekor PHK: bagaimana developer game benar-benar kembali direkrut pada 2026</h1>
<p><em>Oleh <a href="/id/about">Mariana Muntean</a>, CEO Cinevva</em></p>
<p>Industri game menghasilkan sekitar <strong>$195,6 miliar</strong> pada 2025. Tahun terbaiknya sepanjang masa. Dalam periode yang sama, kira-kira <strong>satu dari tiga developer kehilangan pekerjaan</strong>.</p>
<p>Baca lagi kedua kalimat itu. Keduanya seharusnya tidak mungkin terjadi bersamaan, tetapi inilah kenyataannya. Jika Anda terkena PHK dalam dua tahun terakhir, Anda sudah tahu bahwa secara angka situasi ini tidak terasa seperti kemerosotan ekonomi. Rasanya seperti diberi tahu bahwa kapal baik-baik saja sementara Andalah yang terlempar ke laut.</p>
<p>Saya pernah menjadi developer indie. Saya menyaksikan teman-teman memasang banner &quot;open to work&quot; tiga kali dalam delapan belas bulan. Jadi, ini bukan opini sensasional dari seseorang yang hanya mengamati dari pinggir lapangan. Mari kita lihat apa yang sebenarnya terjadi, lalu membahas bagian yang paling penting jika Anda sedang mencari pekerjaan sekarang: apa yang benar-benar membuat orang kembali direkrut.</p>
<h2>Angkanya lebih buruk daripada kesannya</h2>
<p>Gelombang PHK dimulai pada 2022 dan tidak pernah benar-benar berhenti. Ini bukan sekadar satu kuartal yang buruk. Ini adalah penataan ulang struktural selama empat tahun.</p>
<table>
<thead>
<tr>
<th>Tahun</th>
<th>Pekerjaan di industri game yang dipangkas</th>
</tr>
</thead>
<tbody>
<tr>
<td>2022</td>
<td>~8.500</td>
</tr>
<tr>
<td>2023</td>
<td>~10.500</td>
</tr>
<tr>
<td>2024</td>
<td>~14.600 (puncaknya)</td>
</tr>
<tr>
<td>2025</td>
<td>~9.200</td>
</tr>
<tr>
<td>2026</td>
<td>berada di atas 2025, diproyeksikan ~11.580</td>
</tr>
</tbody>
</table>
<p>Artinya, sekitar <strong>44.000 hingga 55.000 pekerjaan hilang</strong> selama periode tersebut, tergantung pelacak mana yang Anda percayai (<a href="https://en.wikipedia.org/wiki/2022%E2%80%932026_video_game_industry_layoffs">Wikipedia</a>, <a href="https://gamesbeat.com/global-gamings-workforce-grew-0-6-in-4-years-but-north-americas-shrank-11-5-amir-satvat/">GamesBeat</a>). Laporan State of the Game Industry 2026 dari GDC, yang menyurvei lebih dari 2.300 profesional, menemukan bahwa <strong>28% developer di seluruh dunia kehilangan pekerjaan dalam dua tahun terakhir, dan angkanya mencapai 33% di AS</strong> (<a href="https://www.gamesindustry.biz/gdc-survey-reveals-layoffs-up-6-36-of-industry-using-ai-and-overwhelming-support-for-unionisation-in-the-us">GamesIndustry.biz</a>). Separuh responden mengatakan bahwa perusahaan tempat mereka bekerja saat ini atau terakhir kali melakukan PHK dalam dua belas bulan terakhir.</p>
<p>Amerika Utara mengalami dampak terburuk. Pelacakan tenaga kerja Amir Satvat, yang paling mendekati sensus berkelanjutan di industri ini, menunjukkan bahwa jumlah tenaga kerja regional menyusut sementara jumlah tenaga kerja global nyaris tidak berubah. Sekitar <strong>19% pekerja industri game di Amerika Utara terdampak</strong> (<a href="https://gamesbeat.com/global-gamings-workforce-grew-0-6-in-4-years-but-north-americas-shrank-11-5-amir-satvat/">GamesBeat</a>).</p>
<p>Berikut statistik yang menjelaskan mengapa pencarian kerja terasa mustahil bahkan setelah perekrutan &quot;pulih&quot;. Satvat memperkirakan sekitar <strong>288.000 orang sedang mencari pekerjaan di industri game</strong> selama periode ini. Lulusan baru, veteran yang terkena PHK, dan orang yang beralih karier, semuanya melamar ke kumpulan lowongan terbatas yang sama. Saat Anda mengirimkan CV untuk suatu lowongan sekarang, Anda tidak bersaing dengan belasan orang. Anda bersaing dengan satu stadion penuh.</p>
<h2>Mengapa tahun dengan rekor pendapatan tetap berujung PHK</h2>
<p>Pendapatannya tidak menghilang. Pendapatan itu terkonsentrasi. Segelintir game live-service raksasa menyerap porsi yang sangat besar, yang berarti lebih sedikit proyek baru berisiko, lebih sedikit tim baru, dan lebih sedikit proyek skala menengah yang dahulu menyerap talenta. Investasi swasta dalam industri game turun lebih dari separuh pada 2025 (<a href="https://respawn.outlookindia.com/gaming/gaming-news/record-profits-record-layoffs-inside-gamings-2026-paradox">Outlook Respawn</a>). Studio merespons sebagaimana biasanya: membatalkan proyek, memangkas anggaran, dan mengalihkan pekerjaan kepada kontraktor.</p>
<p>Jadi, labanya nyata, penderitaannya pun nyata, dan keduanya mengarah pada penyebab yang sama. Fakta itu tidak banyak menghibur ketika Andalah yang terus menyegarkan kotak masuk, tetapi ada hal berguna yang bisa dipetik. Ini bukan pasar yang hanya menunggu untuk kembali seperti pada 2021. Orang-orang yang berhasil direkrut kembali juga tidak menunggu hal itu. Mereka beradaptasi dengan cara kerja perekrutan saat ini.</p>
<h2>Pasar kerja mengalami masalah autentisitas</h2>
<p>Bicaralah dengan siapa pun yang menyaring kandidat saat ini, dan Anda akan mendengar keluhan yang sama. Mereka kewalahan. Lowongan pekerjaan menerima ratusan lamaran dalam hitungan jam, dan sebagian besar seolah ditulis oleh orang yang sama, karena dalam arti tertentu semuanya memang dibuat dengan alat yang sama.</p>
<p>Para perekrut memberi tahu TechRound bahwa bagian tersulitnya bukan mendeteksi penggunaan AI, melainkan banjir &quot;konten yang dioptimalkan dengan baik tetapi minim konteks&quot; yang membuat mereka nyaris mustahil menemukan orang yang benar-benar memahami peran tersebut (<a href="https://techround.co.uk/news/linkedin-ai-slop-content-recruitment-process/">TechRound</a>). LinkedIn sendiri kini mengatakan bahwa mereka mendeteksi konten generik tulisan AI dengan akurasi sekitar 94% dan diam-diam membatasi jangkauannya (<a href="https://techround.co.uk/news/linkedin-ai-slop-content-recruitment-process/">TechRound</a>).</p>
<p>Balik sudut pandangnya, dan ini menjadi kabar terbaik dalam seluruh artikel ini. Ketika semuanya terdengar sama, kemampuan untuk menyampaikan hal-hal spesifik menjadi kekuatan super. Di tengah feed berisi presentasi mengilap yang seragam, manusia yang menunjukkan karya dan pemikiran nyata bukan sekadar tampil menonjol. Mereka menjadi satu-satunya sinyal di tengah kebisingan.</p>
<h2>Bukti selalu mengalahkan polesan</h2>
<p>Khusus untuk posisi di industri game, hal yang benar-benar membawa perubahan bukanlah PDF yang lebih cantik. Melainkan bukti yang dapat dialami seseorang. Seorang perekrut dengan pengalaman 12 tahun menyampaikannya secara lugas: build yang dapat dimainkan atau demo reel lebih bermanfaat bagi Anda daripada hampir semua hal lain dalam lamaran.</p>
<p>Itulah pergeserannya. CV memberi tahu perekrut bahwa Anda memahami desain. Cuplikan yang dapat dimainkan membuat mereka merasakannya dalam 30 hingga 90 detik. Anda tidak dapat memalsukan mekanik yang berfungsi semudah memalsukan satu poin di CV. Anda tidak dapat memalsukan level yang bisa dijelajahi, shader yang berjalan secara real-time, rig yang benar-benar bergerak, atau cue audio interaktif yang dipetakan ke adegan nyata. Interaktivitas adalah bukti yang tahan diperiksa karena di baliknya ada seseorang yang mampu mempertanggungjawabkan setiap keputusan.</p>
<p>Dan bagian terakhir itulah yang sebenarnya diuji oleh perekrut. Cara yang mereka gunakan untuk mendeteksi portofolio yang dipoles dengan AI sederhana: tanyakan prosesnya, bukan hasil akhirnya. Seseorang yang membuat studi kasus dengan AI dapat menjelaskan isi tulisannya, tetapi tidak mampu menjelaskan keputusan di baliknya. Karena itu, semua portofolio terkuat pada 2026 memiliki empat hal yang sama:</p>
<table>
<thead>
<tr>
<th>Lapisan</th>
<th>Pertanyaan yang dijawab</th>
</tr>
</thead>
<tbody>
<tr>
<td>Konteks</td>
<td>Brief, platform, dan batasan nyata (anggaran, tenggat, batasan teknologi)</td>
</tr>
<tr>
<td>Kontribusi</td>
<td>Bagian yang Anda tangani sendiri dibandingkan dengan bagian yang dikerjakan tim</td>
</tr>
<tr>
<td>Keputusan</td>
<td>Kompromi yang Anda buat serta apa yang Anda pertahankan, ubah, dan tolak</td>
</tr>
<tr>
<td>Hasil</td>
<td>Hasil terukur dan dapat diverifikasi oleh orang lain</td>
</tr>
</tbody>
</table>
<p>Bagian &quot;dipertahankan, diubah, dan ditolak&quot; itulah yang dilewatkan kebanyakan orang, padahal bagian itu membuktikan selera. Selera adalah hal yang paling sulit dipalsukan, dan justru itulah yang dibeli studio: seseorang yang mampu memilih ide tepat dari sepuluh ide yang sama-sama masuk akal. Lewati penutup &quot;Saya belajar banyak&quot;. Tunjukkan keputusan yang Anda ambil dan alasan keputusan itu lebih baik bagi pemain.</p>
<h2>Sedikit tentang AI, karena industri ini berhak untuk marah</h2>
<p>Saya menjalankan platform yang menggunakan alat AI, dan saya tidak akan berpura-pura bahwa ketegangan ini tidak ada. Survei GDC yang sama menemukan bahwa <strong>52% developer kini menganggap AI generatif berdampak negatif terhadap industri, naik dari 18% dua tahun lalu</strong>, dan penolakan terkuat datang dari seniman, penulis, serta programmer (<a href="https://www.gamesindustry.biz/gdc-survey-reveals-layoffs-up-6-36-of-industry-using-ai-and-overwhelming-support-for-unionisation-in-the-us">GamesIndustry.biz</a>). Ketika Anda baru saja terkena PHK dan diberi tahu bahwa sebuah model mungkin bisa mengerjakan sebagian pekerjaan lama Anda, ucapan &quot;pakai saja AI untuk portofoliomu&quot; terasa seperti tamparan, bukan saran.</p>
<p>Jadi, saya akan mengatakannya dengan jelas. Tidak ada orang yang akan direkrut dengan menyerahkan sesuatu buatan mesin kepada perekrut jika mereka sendiri tidak mampu menjelaskannya. Karya tersebut harus menjadi milik Anda. Keputusan Anda, keahlian Anda, tanggung jawab Anda. Jika Anda memang menggunakan sebuah alat dalam suatu proyek, katakan dengan terbuka, lalu tunjukkan penilaian Anda di atasnya: apa yang Anda pertahankan, apa yang Anda buang, dan mengapa keputusan Anda lebih baik bagi pemain. Manajer perekrutan memercayai orang yang memperlakukan alat seperti pekerja magang yang membutuhkan arahan, bukan orang yang bersembunyi di baliknya. Kejujuran tentang proses Anda terbaca sebagai profesionalisme, dan profesionalisme sering kali sekadar berarti &quot;Saya memikirkan konsekuensinya sebelum menerbitkannya.&quot;</p>
<h2>Tempat menaruh bukti</h2>
<p>Satu hal praktis, karena begitu banyak percakapan ini dimulai di LinkedIn. Feed sangat membatasi jangkauan tautan eksternal, tetapi bagian Featured di profil Anda tidak. Itulah satu-satunya tempat yang mengubah tautan menjadi kartu pratinjau yang rapi tanpa penalti, dan posisinya tepat di bagian atas profil, tempat pertama yang dilihat perekrut. Sematkan tiga hingga lima karya, letakkan karya terbaik terlebih dahulu, dan ingat bahwa kebanyakan orang melihatnya melalui ponsel. Awali dengan sesuatu yang dapat dibuka dan dialami dalam hitungan detik.</p>
<p>Pastikan cepat dan jujur. Demo yang dimuat dalam waktu kurang dari dua detik dan menunjukkan satu ide yang jelas lebih baik daripada proyek ambisius yang tersendat-sendat atau menampilkan galat 404. Perekrut yang meninjau tiga puluh portofolio dalam satu sore tidak akan menunggu, dan tautan rusak mencerminkan kebiasaan kerja yang buruk.</p>
<h2>Mengapa kami peduli</h2>
<p>Di Cinevva, kami membuat game berbasis browser yang bisa langsung dimainkan. Artinya, banyak hal yang kami buat kebetulan sama persis dengan kebutuhan portofolio modern: karya nyata yang dapat dibuka dan dimainkan perekrut melalui satu tautan, tanpa unduhan dan tanpa instalasi. Kami memperhatikan masalah ini dengan serius karena orang-orang yang terdampak adalah bagian dari komunitas kami. Jika Anda terkena PHK, keterampilan Anda tidak menguap begitu saja. Pasarnya menjadi lebih bising, dan cara Anda membuktikan kemampuan telah berubah.</p>
<p>Pertanyaan lama adalah &quot;Anda pernah bekerja di mana?&quot; Pertanyaan barunya adalah &quot;tunjukkan sesuatu yang bisa saya mainkan, lalu jelaskan mengapa Anda membuatnya seperti itu.&quot; Pertanyaan kedua lebih sulit dimanipulasi dan lebih menguntungkan bagi orang-orang yang benar-benar mampu mengerjakan pekerjaannya. Jika Anda termasuk di antaranya, pasar ini memang kejam, tetapi tidak tertutup. Pasar ini menunggu bukti yang dapat dipercaya.</p>
<hr>
<h2>Sumber</h2>
<ul>
<li><a href="https://www.gamesindustry.biz/gdc-survey-reveals-layoffs-up-6-36-of-industry-using-ai-and-overwhelming-support-for-unionisation-in-the-us">State of the Game Industry GDC 2026: PHK, AI, dan serikat pekerja</a></li>
<li><a href="https://gamesbeat.com/global-gamings-workforce-grew-0-6-in-4-years-but-north-americas-shrank-11-5-amir-satvat/">GamesBeat: Tenaga kerja industri game global tumbuh 0,6% dalam 4 tahun, Amerika Utara menyusut</a></li>
<li><a href="https://en.wikipedia.org/wiki/2022%E2%80%932026_video_game_industry_layoffs">Wikipedia: PHK industri video game 2022–2026</a></li>
<li><a href="https://respawn.outlookindia.com/gaming/gaming-news/record-profits-record-layoffs-inside-gamings-2026-paradox">Outlook Respawn: Rekor laba, rekor PHK</a></li>
<li><a href="https://www.gamedeveloper.com/business/industry-layoffs-are-seemingly-slowing-but-the-damage-has-already-been-done">Game Developer: PHK melambat, tetapi kerusakan sudah terjadi</a></li>
<li><a href="https://techround.co.uk/news/linkedin-ai-slop-content-recruitment-process/">TechRound: LinkedIn menghadapi lonjakan konten sampah AI</a></li>
</ul>
<hr>
<p><strong>Terkait:</strong></p>
<ul>
<li><a href="/id/blog/2026-01-18-skills-over-degrees">Pasar kerja sedang berubah: dari kredensial menuju keterampilan</a></li>
<li><a href="/id/blog/2026-01-18-ai-controversy-and-post-ai-economy">Kontroversi AI, kepercayaan, dan ekonomi pasca-AI untuk industri game</a></li>
<li><a href="/id/blog/2026-02-10-the-intuitive-mind">Pikiran intuitif di era AI</a></li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Game Browser Gratis Terbaik untuk Dimainkan Sekarang (Tanpa Unduhan)]]></title>
            <link>https://app.cinevva.com/id/blog/2026-06-30-best-free-browser-games-no-download</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-06-30-best-free-browser-games-no-download</guid>
            <pubDate>Tue, 30 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Daftar pilihan game browser terbaik yang dapat langsung Anda mainkan tanpa mengunduh atau menginstal. Game indie berperingkat teratas dari genre teka-teki, roguelike, cerita, dan ritme.]]></description>
            <content:encoded><![CDATA[<h1>Game Browser Gratis Terbaik untuk Dimainkan Sekarang (Tanpa Unduhan)</h1>
<p><em>Oleh <a href="/id/about">Mariana Muntean</a>, CEO Cinevva</em></p>
<p>Oke, jadi kami benar-benar tidak berniat menghabiskan seminggu penuh di <a href="http://itch.io">itch.io</a>. Apa yang awalnya sekadar riset singkat berubah menjadi... yah, sekitar jam kedua belas kami berhenti menghitung. Tujuan utamanya adalah menemukan game yang bisa langsung dimainkan — tanpa unduhan, tanpa installer yang terus bekerja di latar belakang. Anda mengeklik, langsung masuk. Selesai.</p>
<p>Inilah game-game yang lolos seleksi.</p>
<h2>Pengalaman Interaktif Berperingkat Teratas</h2>
<div class="showcase-card">
<img src="/img/showcases/anxiety.png" alt="Tangkapan layar Adventures With Anxiety" loading="lazy">
<p><strong>Adventures With Anxiety!</strong> — Cerita Interaktif
Lebih dari 6.500 penilaian dengan rata-rata 4,9. Gila juga sesuatu yang memaksa Anda menghadapi kecemasan ternyata punya penggemar sebanyak ini, bukan? Game ini membuat tidak nyaman dengan cara terbaik — jenis pengalaman yang terus teringat. <a href="https://ncase.itch.io/anxiety">Mainkan di sini</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/wbwwb.png" alt="Tangkapan layar We Become What We Behold" loading="lazy">
<p><strong>We Become What We Behold</strong> — Komentar Sosial
7.600 penilaian dengan skor 4,8/5. Sepuluh menit untuk menamatkannya. Berhari-hari untuk berhenti memikirkannya. <a href="https://ncase.itch.io/wbwwb">Mainkan di sini</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/six-cats-under.png" alt="Tangkapan layar Six Cats Under" loading="lazy">
<p><strong>Six Cats Under</strong> — Petualangan Teka-Teki
Nyaman dan cerdas. Visualnya bekerja sangat keras di sini, dan itu justru menjadi keunggulannya. Skor 4,8/5 dari lebih dari 6.400 orang. <a href="https://teambeanloop.itch.io/six-cats-under">Mainkan di sini</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/friday-night-funkin.gif" alt="Tangkapan layar Friday Night Funkin" loading="lazy">
<p><strong>Friday Night Funkin'</strong> — Game Ritme
Sekarang game ini sudah ada di mana-mana. Lebih dari 11.700 penilaian, dengan skor 4,7/5. <a href="https://ninja-muffin24.itch.io/funkin">Mainkan di sini</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/sort-the-court.png" alt="Tangkapan layar Sort the Court" loading="lazy">
<p><strong>Sort the Court!</strong> — Simulasi Kerajaan
Tugas Anda hanya satu: berkata ya atau tidak. Kedengarannya tidak seberapa. Lalu dua jam lenyap sementara Anda masih mengelola sebuah kerajaan kecil. <a href="https://graebor.itch.io/sort-the-court">Mainkan di sini</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/dragonsweeper.png" alt="Tangkapan layar Dragonsweeper" loading="lazy">
<p><strong>Dragonsweeper</strong> — Roguelike Teka-Teki
Ambil Minesweeper, lalu padukan dengan sistem RPG. Skor 4,9/5 — ini mungkin benar-benar game terbaik dalam seluruh daftar ini. <a href="https://danielben.itch.io/dragonsweeper">Mainkan di sini</a></p>
</div>
<h2>Roguelike &amp; Strategi (Dapat Dimainkan di Browser)</h2>
<div class="showcase-card">
<img src="/img/showcases/backpack-hero.png" alt="Tangkapan layar Backpack Hero" loading="lazy">
<p><strong>Backpack Hero</strong> — Roguelike Inventaris
Versi browsernya gratis. Versi berbayar menambahkan lebih banyak konten, tetapi build web gratisnya sudah sangat lengkap. <a href="https://thejaspel.itch.io/backpack-hero">Mainkan di sini</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/vampire-survivors.png" alt="Tangkapan layar Vampire Survivors" loading="lazy">
<p><strong>Vampire Survivors</strong> — Bullet Heaven
Hanya demo — satu tahap, tujuh karakter. Tetap cukup untuk memahami mengapa game ini menyita waktu luang semua orang. <a href="https://poncle.itch.io/vampire-survivors">Mainkan di sini</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/dome-romantik.gif" alt="Tangkapan layar Dome Romantik" loading="lazy">
<p><strong>Dome Romantik</strong> — Pertahanan Tambang
Berawal sebagai proyek game jam. Menjadi Dome Keeper. Lalu menjadi sangat populer. Prototipe aslinya masih tetap seru dimainkan. <a href="https://bippinbits.itch.io/dome-romantik">Mainkan di sini</a></p>
</div>
<h2>Mengapa Memilih Game-Game Ini?</h2>
<p>Setiap tautan sudah diuji. Bukan sekadar dilihat sekilas — kami benar-benar duduk dan memainkan semuanya. Game-game ini dimuat tanpa masalah. Tidak ada keanehan di browser. Ribuan penilaian berasal dari orang-orang yang sama sekali tidak perlu menyentuh tombol unduh; mereka cukup mengeklik dan langsung bermain. Jalur tanpa hambatan dari &quot;hmm, menarik&quot; hingga benar-benar bermain itu? Kebanyakan orang meremehkan seberapa besar pengaruhnya.</p>
<h2>Jelajahi Lebih Banyak Game Web</h2>
<p>Masih ingin lebih banyak?</p>
<ul>
<li><a href="https://itch.io/games/top-rated/html5">Game HTML5 berperingkat teratas di itch.io</a></li>
<li><a href="https://itch.io/games/top-rated/genre-platformer/html5">Game platformer HTML5 terbaik</a></li>
<li><a href="https://itch.io/games/top-rated/html5/year-2024">Game dari 2024-2025</a></li>
</ul>
<h2>Game Indie Pilihan (Perlu Diunduh)</h2>
<p>Beberapa game hebat tidak dapat dijalankan di browser. Game-game ini layak mendapatkan langkah ekstra:</p>
<div class="showcase-card">
<img src="/img/showcases/slice-dice.png" alt="Tangkapan layar Slice & Dice" loading="lazy">
<p><strong>Slice &amp; Dice</strong> — Roguelike Dadu
Berjalan di Windows, Mac, dan Android. <a href="https://tann.itch.io/slice-dice">Dapatkan di itch.io</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/stacklands.png" alt="Tangkapan layar Stacklands" loading="lazy">
<p><strong>Stacklands</strong> — Pembangun Desa Berbasis Kartu
Untuk Windows dan Mac. <a href="https://sokpop.itch.io/stacklands">Dapatkan di itch.io</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/luck-be-a-landlord.png" alt="Tangkapan layar Luck be a Landlord" loading="lazy">
<p><strong>Luck be a Landlord</strong> — Roguelike Mesin Slot
Terdengar seperti sekadar gimmick. Ternyata bukan. Ada strategi sungguhan di balik tampilan mesin slot tersebut. <a href="https://trampolinetales.itch.io/luck-be-a-landlord">itch.io</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/patricks-parabox.png" alt="Tangkapan layar Patrick's Parabox" loading="lazy">
<p><strong>Patrick's Parabox</strong> — Teka-Teki Rekursif
Bersiaplah membuat otak Anda terasa sakit. Bersiaplah untuk tetap menyukainya. <a href="https://patricktraynor.itch.io/patricks-parabox">itch.io</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/dome-keeper.jpg" alt="Tangkapan layar Dome Keeper" loading="lazy">
<p><strong>Dome Keeper</strong> — Pertahanan Tambang
Versi penuh dari prototipe game jam yang kami sebutkan tadi. <a href="https://store.steampowered.com/app/1637320/Dome_Keeper/">Temukan di Steam</a></p>
</div>
<div class="showcase-card">
<img src="/img/showcases/brotato.jpg" alt="Tangkapan layar Brotato" loading="lazy">
<p><strong>Brotato</strong> — Penyintas Arena
<a href="https://store.steampowered.com/app/1942280/Brotato/">Tersedia di Steam</a></p>
</div>
<hr>
<p>Inilah sesuatu yang patut direnungkan jika Anda membuat game: <strong>build browser tidak menempatkan apa pun di antara pemain dan karya Anda</strong>. Tidak ada unduhan yang mengantre lalu terlupakan. Tidak ada layar instalasi yang harus dilewati. Satu klik dan mereka sudah mulai membentuk opini tentang karya Anda. Kedekatan seketika semacam itu jarang dibicarakan — padahal dampaknya mengubah segalanya.</p>
<p>Menginginkan hal yang sama untuk game Anda sendiri? Anda dapat membuatnya langsung di browser dengan <a href="/id/create">alat pembuat game Cinevva</a>, dan game yang kami unggulkan akan tampil di <a href="/id/arcade">Arcade komunitas</a>.</p>
<ul>
<li><a href="/id/creators">Untuk kreator game</a></li>
<li><a href="/id/tutorials/ship-web-game-fast">Buat game web yang dimuat dengan cepat</a></li>
</ul>
<style>
.showcase-card {
  margin: 1.5rem 0;
  padding: 1rem;
  border-radius: 8px;
  background: var(--vp-c-bg-soft);
}

.showcase-card img {
  max-width: 100%;
  height: auto;
  border-radius: 6px;
  margin-bottom: 0.75rem;
  display: block;
}

@media (min-width: 640px) {
  .showcase-card {
    display: grid;
    grid-template-columns: 200px 1fr;
    gap: 1rem;
    align-items: start;
  }
  
  .showcase-card img {
    margin-bottom: 0;
    width: 200px;
  }
}
</style>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Engine game web pada 2026: PlayCanvas vs Three.js vs Babylon.js vs Unity WebGL]]></title>
            <link>https://app.cinevva.com/id/blog/2026-06-09-web-game-engines-2026-comparison</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-06-09-web-game-engines-2026-comparison</guid>
            <pubDate>Tue, 09 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Perbandingan terkini dan jujur mengenai cara-cara utama untuk membuat game 3D di browser pada 2026: PlayCanvas (v2.20), Three.js, Babylon.js, dan Unity WebGL. Apa itu masing-masing, untuk siapa, dukungan WebGL2 vs WebGPU, lisensi, dan cara memilihnya.]]></description>
            <content:encoded><![CDATA[<h1>Engine game web pada 2026: PlayCanvas vs Three.js vs Babylon.js vs Unity WebGL</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Salah Satu Pendiri Cinevva</em></p>
<img src="https://cdn.cinevva.com/blog/web-engines-2026-hero.jpg" alt="Jendela browser yang menampilkan adegan 3D, bertransisi dari mesh wireframe putih di sebelah kiri menjadi lanskap low-poly penuh warna yang telah dirender di sebelah kanan" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Jika Anda ingin merilis game 3D yang berjalan di browser pada 2026, ada empat pilihan arus utama dan beberapa pilihan yang lebih baru. Semuanya sering dikelompokkan sebagai &quot;engine game web&quot;, tetapi sebenarnya merupakan alat yang benar-benar berbeda dan menyelesaikan masalah yang berbeda pula. Salah memilih dapat menghabiskan waktu Anda berbulan-bulan. Ini adalah perbandingan terkini yang telah diperiksa faktanya, ditulis oleh orang-orang yang membangun engine 3D web sebagai pekerjaan sehari-hari dan telah mengevaluasi semua pilihan ini sebelum membangun engine kami sendiri.</p>
<p>Kami akan membahas setiap pilihan, apa sebenarnya alat tersebut, untuk siapa alat itu ditujukan, serta apa kelemahannya, lalu memberikan panduan keputusan singkat di bagian akhir. Jika kami menyebutkan nomor versi, informasinya akurat per Juli 2026.</p>
<blockquote>
<p>Mencari gambaran lengkap? Artikel ini berfokus pada empat pilihan 3D arus utama. Untuk peringkat dan perbandingan seluruh 11 engine web (termasuk pilihan 2D seperti Phaser, Defold, dan Construct), lihat panduan <a href="/id/guides/web-game-engines-comparison">engine game web terbaik untuk 2026</a> kami.</p>
</blockquote>
<h2>Perbandingan singkat</h2>
<table>
<thead>
<tr>
<th></th>
<th>PlayCanvas</th>
<th>Three.js</th>
<th>Babylon.js</th>
<th>Unity WebGL</th>
<th>Cinevva</th>
</tr>
</thead>
<tbody>
<tr>
<td>Jenisnya</td>
<td>Engine lengkap + editor ter-hosting</td>
<td>Pustaka rendering</td>
<td>Engine lengkap + editor</td>
<td>Engine desktop, ekspor web</td>
<td>Platform dunia berbasis AI</td>
</tr>
<tr>
<td>Arsitektur</td>
<td>Entitas-komponen (ECS)</td>
<td>Graf adegan</td>
<td>Graf adegan + komponen</td>
<td>GameObject/komponen</td>
<td>Graf adegan + builder AI</td>
</tr>
<tr>
<td>Scripting</td>
<td>TypeScript / JavaScript</td>
<td>JavaScript (bagian lain Anda bangun sendiri)</td>
<td>TypeScript / JavaScript</td>
<td>C# (dikompilasi menjadi Wasm)</td>
<td>Bahasa alami + kode</td>
</tr>
<tr>
<td>Renderer</td>
<td>WebGL2, WebGPU sedang dimatangkan</td>
<td>WebGL2, WebGPU terus berkembang</td>
<td>WebGL2, WebGPU semakin maju</td>
<td>WebGL2 (ekspor)</td>
<td>Hanya WebGPU</td>
</tr>
<tr>
<td>Editor</td>
<td>Ter-hosting, komersial</td>
<td>Tidak ada</td>
<td>Berbasis web, gratis</td>
<td>Desktop, komersial</td>
<td>Di dalam dunia, imersif</td>
</tr>
<tr>
<td>Fisika</td>
<td>Ammo / integrasi</td>
<td>Sediakan sendiri</td>
<td>Havok bawaan</td>
<td>Bawaan (PhysX)</td>
<td>Solver karakter khusus</td>
</tr>
<tr>
<td>Lisensi</td>
<td>Engine MIT, editor proprietari</td>
<td>MIT</td>
<td>Apache 2.0</td>
<td>Proprietari</td>
<td>Proprietari</td>
</tr>
<tr>
<td>Paling cocok untuk</td>
<td>Game browser bergaya produksi studio</td>
<td>3D khusus, kendali penuh</td>
<td>Game dengan fitur lengkap sejak awal</td>
<td>Mem-porting game Unity yang sudah ada</td>
<td>Pembuatan game AI di dalam dunia</td>
</tr>
</tbody>
</table>
<p>Bagian selanjutnya dari artikel ini menjelaskan tabel tersebut.</p>
<h2>PlayCanvas</h2>
<p>PlayCanvas adalah pilihan web yang paling mendekati alur kerja bergaya Unity. Engine-nya bersifat sumber terbuka di bawah lisensi MIT dan berada pada versi v2.20.6 per Juli 2026. PlayCanvas menggunakan sistem entitas-komponen, logika game ditulis dalam TypeScript atau JavaScript, dan aset diproses melalui pipeline sisi server yang menghasilkan GLB. Game komersial sungguhan berjalan di atasnya, dan perusahaan-perusahaan besar menggunakannya dalam produksi, dengan Snap sebagai salah satu contoh publik.</p>
<p>Ada dua kesalahpahaman tentang PlayCanvas yang perlu diluruskan. Pertama, meskipun engine-nya berlisensi MIT, editor visual ter-hosting yang benar-benar digunakan sebagian besar tim merupakan produk komersial, bukan sumber terbuka. Anda dapat menggunakan engine-nya secara bebas tanpa editor tersebut, tetapi alur kerja editor-plus-cloud adalah bagian yang berbayar. Kedua, PlayCanvas mengutamakan WebGL2. PlayCanvas memiliki jalur WebGPU, tetapi jalur tersebut masih dalam proses pematangan dan belum menjadi renderer default, jadi jangan memilih PlayCanvas saat ini jika Anda mengharapkan compute shader WebGPU yang siap produksi.</p>
<p>Bidang yang benar-benar dipimpin PlayCanvas adalah 3D Gaussian splatting. Editor dan viewer SuperSplat-nya, yang dijadikan sumber terbuka oleh tim tersebut, termasuk perangkat terbaik yang tersedia untuk merekam dan merilis adegan splat di web, dengan streaming berbasis WebGPU untuk hasil pemindaian berukuran besar. Jika lingkungan hasil pemindaian fotorealistis adalah fokus Anda, itu merupakan alasan nyata untuk memulai dari sini.</p>
<p><strong>Pilih PlayCanvas jika</strong> Anda menginginkan editor seperti Unity dan pipeline aset terkelola untuk browser, serta sedang merilis jenis game yang biasa dibuat oleh studio. <strong>Cari pilihan lain jika</strong> Anda membutuhkan komputasi WebGPU saat ini, atau ingin menghindari editor komersial ter-hosting.</p>
<h2>Three.js</h2>
<p>Three.js bukanlah engine game. Three.js adalah pustaka rendering, dan sejauh ini merupakan pustaka yang paling banyak digunakan di bidang ini. Three.js menyediakan graf adegan, kamera, lampu, material, geometri, loader, dan renderer, lalu berhenti sampai di situ. Tidak ada editor, fisika, sistem entitas, maupun ketentuan tentang cara menyusun game. Anda menambahkan semuanya sendiri atau mengambilnya dari ekosistem.</p>
<p>Kompromi itu adalah inti keseluruhan ceritanya. Anda mendapatkan kendali maksimal dan komunitas terbesar dalam 3D web, dengan konsekuensi harus membangun atau merangkai sendiri segala sesuatu di atas renderer. Renderer WebGPU-nya terus berkembang dan sudah dapat digunakan saat ini, meskipun seperti pilihan lainnya, jalur WebGL2 masih menjadi pilihan default yang matang. Three.js berlisensi MIT.</p>
<p><strong>Pilih Three.js jika</strong> Anda menginginkan kendali penuh, fondasi minimal, dan memiliki kemampuan rekayasa untuk membangun sistem game di atasnya. <strong>Cari pilihan lain jika</strong> Anda menginginkan editor dan sistem game yang sudah disediakan.</p>
<h2>Babylon.js</h2>
<p>Babylon.js adalah engine lengkap berlisensi Apache 2.0 dan didukung oleh sebuah tim di Microsoft. Tidak seperti Three.js, Babylon.js dilengkapi komponen-komponen yang biasanya harus Anda rangkai sendiri: model komponen, integrasi engine fisika Havok, editor berbasis web gratis, dan pipeline aset. Pengembangan WebGPU-nya berlangsung cepat dan termasuk yang paling maju di antara engine serbaguna, meskipun WebGL2 tetap dipertahankan sebagai jalur dengan kompatibilitas luas. Babylon.js 9.0 (Maret 2026) semakin memperkuat keunggulan tersebut dengan clustered lighting pada kedua backend, pencahayaan volumetrik yang dibangun menggunakan compute shader WebGPU, dan dukungan bayangan untuk 3D Gaussian splat.</p>
<p>Jika pola pikir Anda adalah &quot;Saya menginginkan engine lengkap, fisika yang sudah disertakan, dan tidak keberatan bekerja mengikuti konvensinya&quot;, Babylon merupakan pilihan default yang kuat dan bisa dibilang pilihan gratis dengan fitur terlengkap di bidang ini.</p>
<p><strong>Pilih Babylon.js jika</strong> Anda menginginkan fitur yang lengkap sejak awal, fisika bawaan, dan editor gratis. <strong>Cari pilihan lain jika</strong> Anda menginginkan ukuran dependensi yang kecil atau secara khusus menginginkan alur kerja ter-hosting bergaya Unity.</p>
<h2>Unity WebGL</h2>
<p>Unity WebGL bukanlah engine web, melainkan target ekspor. Anda membuat game dalam editor desktop Unity menggunakan C#, lalu mengompilasinya menjadi bundel WebGL yang berjalan di browser melalui WebAssembly. Hal itu menjadikannya jawaban yang jelas untuk satu kasus tertentu: Anda sudah memiliki game Unity dan menginginkan versi browser-nya.</p>
<p>Untuk proyek yang mengutamakan web sejak awal, ada biaya nyata yang harus ditanggung. Ukuran runtime dan unduhannya signifikan, waktu mulai lebih lambat daripada engine web native, dan performa browser seluler merupakan masalah yang sudah dikenal. Unity bersifat proprietari dan hasil WebGL-nya menargetkan WebGL2. Terdapat backend WebGPU eksperimental di Unity 6, tetapi secara default dinonaktifkan dan belum siap untuk produksi.</p>
<p><strong>Pilih Unity WebGL jika</strong> Anda memiliki proyek Unity yang sudah ada untuk dibawa ke browser, atau tim Anda memang sudah terbiasa sepenuhnya dengan Unity. <strong>Cari pilihan lain jika</strong> pemuatan instan pada ponsel kelas menengah merupakan persyaratan mutlak, atau Anda memulai dari nol dengan pendekatan yang mengutamakan web.</p>
<h2>Posisi pembuatan berbasis AI dan di dalam dunia</h2>
<p>Semua pilihan di atas memiliki satu asumsi yang sama: developer membuat game di meja kerja, menggunakan editor, lalu merilis runtime. Asumsi itu tepat untuk sebagian besar proyek, dan jika hal tersebut menggambarkan proyek Anda, pilihlah salah satu dari empat pilihan di atas.</p>
<p>Namun, perlu diketahui bahwa asumsi tersebut bukan lagi satu-satunya pilihan karena kategori baru mulai bermunculan. Kami membangun Cinevva, sebuah platform dunia khusus WebGPU yang memungkinkan game dibuat dari dalam dunia itu sendiri. Alih-alih membuka editor, Anda menjadi avatar yang berdiri di dalam ruang tersebut, lalu mendeskripsikan apa yang Anda inginkan, dan builder AI mengubahnya menjadi medan, objek, dan perilaku selagi Anda berdiri di sana. Pembuatan dan bermain terjadi dalam sesi yang sama. Di balik layar, hal tersebut mengharuskan kami menggunakan WebGPU secara eksklusif dengan medan berbasis compute shader, menulis solver karakter khusus alih-alih engine fisika serbaguna, serta membangun sistem animasi dan retargeting, yang kami bahas dalam <a href="/id/blog/2026-06-08-why-we-built-our-own-webgpu-engine">alasan kami membangun engine WebGPU sendiri</a>.</p>
<p>Ini bukan pengganti PlayCanvas atau Babylon. Jika Anda adalah developer yang sedang membuat game tertentu, keduanya adalah alat yang tepat. Cinevva ditujukan untuk sasaran berbeda, yaitu memungkinkan orang yang bukan developer engine membuat dan membagikan ruang yang dapat dimainkan hanya dengan mendeskripsikannya. Kami menyebutkannya di sini karena pertanyaan &quot;engine game web mana yang sebaiknya saya gunakan&quot; kini semakin memiliki jawaban kelima yang sama sekali bukan engine.</p>
<h2>Matriks fitur lengkap</h2>
<p>Tabel singkat di atas memuat poin-poin utamanya. Berikut adalah versi terperinci yang dikelompokkan berdasarkan subsistem. Ada beberapa catatan jujur tentang cara membacanya. &quot;Sediakan sendiri&quot; berarti Anda harus menyediakannya sendiri, yaitu engine tidak menyertakannya, tetapi ekosistem atau kode Anda sendiri dapat menambahkannya. Hal ini paling relevan untuk Three.js, yang memang dirancang sebagai pustaka rendering, sehingga &quot;Sediakan sendiri&quot; di sana merupakan bagian dari filosofinya, bukan kekurangan. &quot;Hanya ekspor&quot; untuk Unity berarti kemampuan tersebut tersedia di editor desktop dan disertakan ke dalam build WebGL, bukan merupakan fitur native web. Sel kompetitor mencerminkan kemampuan siap pakai dan perilaku yang terdokumentasi dengan baik per pertengahan 2026. Sel Cinevva mencerminkan apa yang berjalan dalam build yang telah kami rilis, dengan &quot;direncanakan&quot; menandai apa yang sudah dirancang tetapi belum dibangun.</p>
<h3>Rendering</h3>
<table>
<thead>
<tr>
<th>Fitur</th>
<th>Cinevva</th>
<th>PlayCanvas</th>
<th>Three.js</th>
<th>Babylon.js</th>
<th>Unity WebGL</th>
</tr>
</thead>
<tbody>
<tr>
<td>Renderer utama</td>
<td>Hanya WebGPU</td>
<td>WebGL2 (WebGPU beta)</td>
<td>WebGL2 (WebGPU berkembang)</td>
<td>WebGL2 (WebGPU maju)</td>
<td>WebGL2 (ekspor)</td>
</tr>
<tr>
<td>Compute shader dalam produksi</td>
<td>Ya (dependensi inti)</td>
<td>Beta</td>
<td>Melalui WebGPU</td>
<td>Ya (WebGPU)</td>
<td>Hanya ekspor, terbatas</td>
</tr>
<tr>
<td>Pembuatan shader</td>
<td>Node TSL + komputasi</td>
<td>Potongan shader / GLSL</td>
<td>GLSL + node (TSL)</td>
<td>Material node / GLSL / WGSL</td>
<td>ShaderLab / HLSL</td>
</tr>
<tr>
<td>Clustered / forward+ lighting</td>
<td>Ya (froxel)</td>
<td>Ya</td>
<td>Sediakan sendiri</td>
<td>Ya</td>
<td>Ya</td>
</tr>
<tr>
<td>Awan volumetrik dan cuaca</td>
<td>Ya</td>
<td>Sediakan sendiri</td>
<td>Sediakan sendiri</td>
<td>Sebagian</td>
<td>Sediakan sendiri</td>
</tr>
<tr>
<td>Perangkat 3D Gaussian splatting</td>
<td>Direncanakan</td>
<td>Ya (SuperSplat, terdepan)</td>
<td>Komunitas</td>
<td>Ya</td>
<td>Plugin</td>
</tr>
</tbody>
</table>
<h3>Dunia dan medan</h3>
<table>
<thead>
<tr>
<th>Fitur</th>
<th>Cinevva</th>
<th>PlayCanvas</th>
<th>Three.js</th>
<th>Babylon.js</th>
<th>Unity WebGL</th>
</tr>
</thead>
<tbody>
<tr>
<td>Streaming dunia besar bawaan</td>
<td>Ya (chunk 64 m)</td>
<td>Sediakan sendiri</td>
<td>Sediakan sendiri</td>
<td>Sediakan sendiri</td>
<td>Hanya ekspor</td>
</tr>
<tr>
<td>Sistem medan</td>
<td>Heightmap hibrida + marching-cubes/SDF</td>
<td>Sediakan sendiri</td>
<td>Sediakan sendiri</td>
<td>Ekstensi</td>
<td>Bawaan (desktop)</td>
</tr>
<tr>
<td>Pemahatan medan saat runtime</td>
<td>Ya (GPU)</td>
<td>Sediakan sendiri</td>
<td>Sediakan sendiri</td>
<td>Sediakan sendiri</td>
<td>Tidak (saat pengeditan)</td>
</tr>
<tr>
<td>Gua dan ceruk (topologi 3D sejati)</td>
<td>Ya (marching cubes)</td>
<td>Sediakan sendiri</td>
<td>Sediakan sendiri</td>
<td>Sediakan sendiri</td>
<td>Sediakan sendiri</td>
</tr>
<tr>
<td>Dedaunan dan rumput dengan instancing GPU</td>
<td>Ya</td>
<td>Ya</td>
<td>Sediakan sendiri</td>
<td>Ya</td>
<td>Ya</td>
</tr>
</tbody>
</table>
<h3>Fisika dan karakter</h3>
<table>
<thead>
<tr>
<th>Fitur</th>
<th>Cinevva</th>
<th>PlayCanvas</th>
<th>Three.js</th>
<th>Babylon.js</th>
<th>Unity WebGL</th>
</tr>
</thead>
<tbody>
<tr>
<td>Engine fisika</td>
<td>Solver kinematik khusus</td>
<td>Integrasi Ammo</td>
<td>Sediakan sendiri (Rapier/Cannon/Ammo)</td>
<td>Havok bawaan</td>
<td>PhysX bawaan</td>
</tr>
<tr>
<td>Dinamika rigid-body</td>
<td>Tidak (sesuai rancangan)</td>
<td>Ya</td>
<td>Sediakan sendiri</td>
<td>Ya</td>
<td>Ya</td>
</tr>
<tr>
<td>Pengontrol karakter</td>
<td>Ya (FSM multimode)</td>
<td>Templat / Ammo</td>
<td>Sediakan sendiri</td>
<td>Ya</td>
<td>Bawaan</td>
</tr>
<tr>
<td>Tabrakan terintegrasi dengan medan (SDF)</td>
<td>Ya</td>
<td>Tidak</td>
<td>Sediakan sendiri</td>
<td>Tidak</td>
<td>Tidak</td>
</tr>
</tbody>
</table>
<h3>Animasi</h3>
<table>
<thead>
<tr>
<th>Fitur</th>
<th>Cinevva</th>
<th>PlayCanvas</th>
<th>Three.js</th>
<th>Babylon.js</th>
<th>Unity WebGL</th>
</tr>
</thead>
<tbody>
<tr>
<td>Animasi skeletal</td>
<td>Ya</td>
<td>Ya</td>
<td>Ya</td>
<td>Ya</td>
<td>Ya</td>
</tr>
<tr>
<td>Blend / state machine</td>
<td>Ya (FSM resolver)</td>
<td>Ya (graf status animasi)</td>
<td>Mixer (blending sediakan sendiri)</td>
<td>Ya</td>
<td>Ya (Mecanim)</td>
</tr>
<tr>
<td>Retargeting kerangka</td>
<td>Ya (pipeline)</td>
<td>Terbatas</td>
<td>Komunitas</td>
<td>Sebagian</td>
<td>Ya (humanoid)</td>
</tr>
<tr>
<td>Kinematika invers</td>
<td>Direncanakan</td>
<td>Terbatas</td>
<td>Komunitas</td>
<td>Ya</td>
<td>Ya</td>
</tr>
</tbody>
</table>
<h3>Multiplayer dan backend</h3>
<table>
<thead>
<tr>
<th>Fitur</th>
<th>Cinevva</th>
<th>PlayCanvas</th>
<th>Three.js</th>
<th>Babylon.js</th>
<th>Unity WebGL</th>
</tr>
</thead>
<tbody>
<tr>
<td>Multiplayer bawaan</td>
<td>Ya (otoritatif di edge)</td>
<td>Sediakan sendiri (Photon/Colyseus)</td>
<td>Sediakan sendiri</td>
<td>Sediakan sendiri</td>
<td>Sediakan sendiri (Netcode, bukan native web)</td>
</tr>
<tr>
<td>Dunia bersama yang persisten</td>
<td>Ya (Durable Objects per chunk)</td>
<td>Sediakan sendiri</td>
<td>Sediakan sendiri</td>
<td>Sediakan sendiri</td>
<td>Sediakan sendiri</td>
</tr>
<tr>
<td>Obrolan suara spasial</td>
<td>Ya (WebRTC + HRTF)</td>
<td>Sediakan sendiri</td>
<td>Sediakan sendiri</td>
<td>Sediakan sendiri</td>
<td>Sediakan sendiri</td>
</tr>
</tbody>
</table>
<h3>Pembuatan dan authoring</h3>
<table>
<thead>
<tr>
<th>Fitur</th>
<th>Cinevva</th>
<th>PlayCanvas</th>
<th>Three.js</th>
<th>Babylon.js</th>
<th>Unity WebGL</th>
</tr>
</thead>
<tbody>
<tr>
<td>Editor</td>
<td>Di dalam dunia, imersif</td>
<td>Bergaya desktop ter-hosting (komersial)</td>
<td>Tidak ada (minimal)</td>
<td>Berbasis web (gratis)</td>
<td>Desktop (komersial)</td>
</tr>
<tr>
<td>Pembuatan berwujud di dalam dunia</td>
<td>Ya</td>
<td>Tidak</td>
<td>Tidak</td>
<td>Tidak</td>
<td>Tidak</td>
</tr>
<tr>
<td>Pembuatan dengan bahasa alami / AI</td>
<td>Ya (builder AI)</td>
<td>Tidak</td>
<td>Tidak</td>
<td>Tidak</td>
<td>Tidak</td>
</tr>
<tr>
<td>Scripting</td>
<td>Bahasa alami + JS</td>
<td>TypeScript / JS</td>
<td>JavaScript</td>
<td>TypeScript / JS</td>
<td>C#</td>
</tr>
</tbody>
</table>
<h3>Aset dan distribusi</h3>
<table>
<thead>
<tr>
<th>Fitur</th>
<th>Cinevva</th>
<th>PlayCanvas</th>
<th>Three.js</th>
<th>Babylon.js</th>
<th>Unity WebGL</th>
</tr>
</thead>
<tbody>
<tr>
<td>Pipeline aset sisi server</td>
<td>Ya (GLB + LOD + KTX2 + Draco)</td>
<td>Ya (GLB)</td>
<td>Hanya loader</td>
<td>Alat impor</td>
<td>Ya</td>
</tr>
<tr>
<td>Pembuatan aset AI bawaan</td>
<td>Ya (3D, gambar, audio, musik)</td>
<td>Tidak</td>
<td>Tidak</td>
<td>Tidak</td>
<td>Tidak</td>
</tr>
<tr>
<td>Pencarian aset terfederasi</td>
<td>Ya (sebelas penyedia)</td>
<td>Toko aset</td>
<td>Tidak</td>
<td>Tidak</td>
<td>Toko aset</td>
</tr>
<tr>
<td>Berjalan di browser, tanpa instalasi</td>
<td>Ya</td>
<td>Ya</td>
<td>Ya</td>
<td>Ya</td>
<td>Ya (berat)</td>
</tr>
<tr>
<td>Lisensi engine</td>
<td>Platform proprietari</td>
<td>Engine MIT, editor proprietari</td>
<td>MIT</td>
<td>Apache 2.0</td>
<td>Proprietari</td>
</tr>
</tbody>
</table>
<p>Pola dalam matriks tersebut adalah inti ceritanya. Engine serbaguna menyebarkan kekuatannya secara horizontal; masing-masing mampu melakukan sebagian besar hal dengan baik dan menyerahkan dunia, backend, serta alur pembuatan kepada Anda. Cinevva memusatkan kekuatannya secara vertikal; Cinevva melakukan lebih sedikit hal, tetapi menguasai seluruh jalur dari renderer hingga dunia bersama yang Anda buat dari dalam. Tidak ada bentuk yang secara mutlak lebih baik. Keduanya menjawab pertanyaan yang berbeda.</p>
<h2>Cara memilih</h2>
<p>Cocokkan alat dengan situasi Anda, bukan dengan daftar centang fitur.
Jika Anda sudah memiliki game Unity, ekspor dengan Unity WebGL dan terima konsekuensi ukuran hasil ekspornya. Jika Anda adalah studio yang menginginkan alur kerja berbasis editor untuk game browser, gunakan PlayCanvas. Jika Anda menginginkan engine gratis yang lengkap dengan sistem fisika bawaan, gunakan Babylon.js. Jika Anda menginginkan kendali penuh dan memiliki tim untuk mengembangkan game di atas renderer dasar, gunakan Three.js. Dan jika tujuan Anda bukan membuat satu game, melainkan memungkinkan orang berkreasi dan bermain di dunia bersama dengan mendeskripsikan berbagai hal, itulah kategori yang kami geluti, dan Anda dapat <a href="/id/">mencoba Cinevva</a>.</p>
<p>Apa pun pilihan Anda, lakukan evaluasi dengan purwarupa nyata sebelum berkomitmen. Masing-masing engine ini mampu menopang game sungguhan, dan biaya beralih di tengah jalan adalah waktu berbulan-bulan yang tidak Anda gunakan untuk merilis game.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Mengapa kami membangun mesin WebGPU sendiri alih-alih melakukan fork PlayCanvas]]></title>
            <link>https://app.cinevva.com/id/blog/2026-06-08-why-we-built-our-own-webgpu-engine</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-06-08-why-we-built-our-own-webgpu-engine</guid>
            <pubDate>Mon, 08 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Three.js, Babylon.js, PlayCanvas, Unity WebGL: kami mengevaluasi semuanya sebelum menulis renderer sendiri. Inilah keunggulan masing-masing, empat keputusan yang membuat kami meninggalkan solusi siap pakai, dan situasi ketika Anda sama sekali tidak seharusnya melakukan apa yang kami lakukan.]]></description>
            <content:encoded><![CDATA[<h1>Mengapa kami membangun mesin WebGPU sendiri alih-alih melakukan fork PlayCanvas</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Salah Satu Pendiri Cinevva</em></p>
<img src="https://cdn.cinevva.com/blog/why-webgpu-engine-hero.jpg" alt="Dunia low-poly bergaya yang dirender oleh mesin WebGPU Cinevva: perbukitan bergelombang, gua yang terbentuk di dalam tebing, sungai berkelok-kelok, dan avatar yang sedang melangkah di jalan setapak saat suasana keemasan menjelang senja" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Setiap orang teknis yang melihat Cinevva World menanyakan hal yang sama dalam waktu lima menit. Tim Anda kecil. Mesin 3D web yang matang sudah tersedia. Mengapa Anda menulis renderer, fisika karakter, dan sistem animasi sendiri, alih-alih memanfaatkan PlayCanvas atau Babylon agar bisa merilis lebih cepat?</p>
<p>Itu pertanyaan yang wajar, dan sindrom &quot;bukan buatan sendiri&quot; bukanlah jawaban yang tepat. Kami melakukan riset. Kami menjalankan mesin-mesin yang sudah ada, membaca kode sumbernya, dan membuat purwarupa di atas dua di antaranya sebelum mengambil keputusan. Tulisan ini adalah versi jujur dari keputusan tersebut: apa yang benar-benar dikuasai oleh opsi siap pakai, empat bagian tempat kebutuhan kami menyimpang cukup jauh sehingga layak dibangun sendiri, serta situasi ketika Anda sebaiknya memilih salah satunya daripada meniru kami. Proses pembangunannya sendiri kami dokumentasikan dalam <a href="/id/blog/2026-02-25-open-world-browser-series-guide">seri rekayasa dunia terbuka di browser</a> yang berlangsung panjang, jadi jika sebuah pernyataan di bawah memiliki catatan implementasi yang mendukungnya, saya akan menautkannya.</p>
<h2>Opsi yang benar-benar kami evaluasi</h2>
<p>Ada empat hal yang disebut &quot;mesin game web,&quot; dan semuanya bukan jenis perangkat yang sama.</p>
<p><strong>Three.js</strong> adalah pustaka rendering, bukan mesin game. Three.js memberi Anda scene graph, material, loader, dan renderer, lalu membiarkan Anda bekerja sesuka hati. Tidak ada editor, fisika, sistem entitas, maupun ketentuan tentang cara game Anda harus disusun. Itulah daya tarik sekaligus biayanya. Anda membangun sendiri segala sesuatu di atas renderer, tetapi tidak ada yang menghalangi Anda. Lisensinya MIT, ekosistemnya adalah yang terbesar di bidang ini, dan ketika Anda menemukan bug shader yang tidak lazim pada pukul 2 pagi, biasanya sudah ada jawaban yang menunggu di forum.</p>
<p><strong>Babylon.js</strong> adalah mesin lengkap dengan scene graph, integrasi fisika (Havok), pipeline aset, dan editor web. Lisensinya MIT, didukung oleh tim di Microsoft, dan pengembangan WebGPU-nya bergerak cepat. Jika Anda menginginkan solusi lengkap dan nyaman bekerja dalam struktur mesin tersebut, Babylon.js adalah pilihan awal yang kuat.</p>
<p><strong>PlayCanvas</strong> adalah hal yang paling mendekati &quot;Unity untuk web.&quot; Saat tulisan ini dibuat, mesinnya berada di v2.19.6, yang dirilis pada 5 Juni 2026, dan mesin itu sendiri bersifat sumber terbuka di bawah lisensi MIT. Namun, yang sebenarnya digunakan oleh kebanyakan orang adalah editor visual yang di-host, dan editor tersebut merupakan produk komersial, bukan sumber terbuka. PlayCanvas menggunakan sistem entitas-komponen, Anda menulis skrip dalam TypeScript atau JavaScript, aset diproses melalui pipeline GLB sisi server, dan game komersial sungguhan telah dirilis dengannya (salah satunya, Snap menjalankan proyek produksi menggunakan PlayCanvas). Renderer-nya berjalan dengan WebGL2, sedangkan jalur WebGPU-nya masih dalam tahap pematangan dan belum menjadi pilihan default. Detail terakhir itu lebih penting daripada kelihatannya, dan saya akan membahasnya lagi nanti.</p>
<p><strong>Unity WebGL</strong> sebenarnya bukan mesin web. Ini adalah target ekspor. Anda membangun di editor desktop Unity lalu mengompilasinya menjadi bundle WebGL. Ini adalah alat yang tepat jika Anda sudah memiliki game Unity dan ingin menghadirkannya di browser, tetapi alat yang keliru jika &quot;langsung dimuat di tab pada ponsel kelas menengah&quot; merupakan persyaratan mutlak, karena runtime dan besarnya unduhan ikut terbawa.</p>
<p>Semua opsi ini merupakan fondasi yang masuk akal untuk game web biasa. Game web kami tidak biasa.</p>
<h2>Keputusan pertama: WebGPU adalah titik awal kami, bukan garis finis</h2>
<p>Perbedaan yang membuat kami meninggalkan semua solusi siap pakai adalah ini. Bagi kami, WebGPU merupakan persyaratan, bukan fitur yang akan kami gunakan kelak.</p>
<p>Terrain kami bukan heightmap statis. Terrain ini merupakan perpaduan antara bidang heightmap yang dialirkan dan chunk marching cubes yang didukung oleh signed-distance field, sehingga dunia dapat memiliki gua dan bagian tebing menjorok yang nyata, serta kreator dapat memahatnya secara langsung. Kuas pemahat, penyebaran vegetasi, dan pembuatan mesh terrain semuanya berjalan sebagai compute shader. Hilangkan komputasi, dan dunia ini bukan sekadar mengalami penurunan kualitas—dunia ini tidak akan berjalan.</p>
<p>Itu berkebalikan dengan posisi mesin serbaguna saat ini. Dukungan WebGPU mereka dirancang sebagai peningkatan progresif di atas renderer yang mengutamakan WebGL2, dengan jalur fallback untuk browser yang tidak mendukungnya. Secara khusus, PlayCanvas mengutamakan WebGL2, sementara WebGPU masih dalam versi beta. Itu merupakan keputusan yang tepat bagi mereka karena tugas mereka adalah menjalankan sebanyak mungkin jenis game di sebanyak mungkin perangkat. Tugas kami lebih sempit dan lebih mendalam, jadi kami mengambil keputusan sebaliknya: kami sepenuhnya beralih ke WebGPU pada purwarupa ke-13 dan tidak pernah menoleh ke belakang. Browser tanpa WebGPU tidak mendapatkan versi dengan kualitas lebih rendah, melainkan tidak didukung, dan kami mencatatnya sebagai angka jangkauan alih-alih berpura-pura bahwa fallback WebGL2 hanya membutuhkan perubahan satu opsi konfigurasi. Kenyataannya tidak demikian. Itu akan menjadi penulisan ulang sebagian dari tahap terrain dan vegetasi kami.</p>
<p>Membangun di atas mesin yang mengutamakan WebGL2 berarti kami harus melawan asumsi fallback-nya pada setiap fitur komputasi atau selamanya memelihara dua jalur rendering. Dengan memiliki renderer sendiri, kami dapat menjadikan komputasi sebagai fondasi dasar.</p>
<h2>Keputusan kedua: solver karakter, bukan mesin fisika</h2>
<p>Langkah yang lazim adalah memasukkan mesin fisika. Kami mencobanya. Purwarupa awal memvalidasi Rapier yang berjalan dalam worker, dan hasilnya terasa cukup baik.</p>
<p>Kami tetap menulis solusi sendiri, dan tidak ada Rapier, Cannon, maupun Ammo di mana pun dalam versi yang dirilis. Alasannya adalah cakupan. Kami tidak membutuhkan rigid body, joint, ragdoll, atau constraint solver. Kami membutuhkan satu kapsul yang bergerak dengan benar terhadap terrain, serta membutuhkan berjalan, meluncur di permukaan, melayang, memanjat, dan berenang agar semuanya menyepakati satu jawaban yang sama untuk pertanyaan &quot;apakah saya berpijak, di permukaan apa, dan pada sudut berapa.&quot; Mesin fisika serbaguna justru membuat hal itu lebih sulit, bukan lebih mudah, karena mode-mode tersebut akhirnya harus melawan pegas dan peredam internalnya.</p>
<p>Jadi, pengontrol karakter kami adalah <a href="/id/blog/2026-05-15-open-world-browser-part-29-pluggable-character">state machine multikanal yang dapat dipasang-lepas</a>. Setiap mode adalah unit kecil yang menyatakan apakah ia ingin mengambil kendali pada frame ini dan, jika menang, menetapkan kecepatan serta arah hadap. Semuanya bersaing berdasarkan prioritas di tiga kanal—resource, lalu stance, kemudian locomotion—dan semuanya membaca kueri terrain yang sama. Tabrakan menggunakan probe kapsul terhadap heightmap atau signed-distance field, tergantung pada chunk-nya.</p>
<p>Detail yang paling saya banggakan justru tidak glamor. Deteksi pijakan memindai setiap permukaan dalam kolom vertikal di bawah kaki Anda dan memilih permukaan tertinggi yang berada tepat pada atau di bawah kapsul, alih-alih memercayai gradien SDF. Di tepi bagian tebing yang menjorok, permukaan terdekat secara horizontal adalah sisi tebing, sehingga normal berbasis gradien berubah-ubah antara &quot;lantai&quot; dan &quot;dinding&quot; dan membuat Anda seolah-olah meluncur tanpa sebab. Kueri kolom membuat berdiri di tepian terasa biasa saja, dan memang itulah yang diinginkan. Collider heightfield siap pakai tidak akan memberi kami kemampuan itu secara cuma-cuma karena sejak awal ia tidak dapat melihat terrain kami. Terrain tersebut berada di GPU dalam format kami sendiri. Tidak ada mesin eksternal yang dapat menangani tumbukan terhadapnya tanpa mengharuskan kami menyalin seluruh bidang ke dalam format collider mesin itu setiap kali terjadi pengeditan.</p>
<h2>Keputusan ketiga: animasi yang dapat dipindahkan antar-rig</h2>
<p>Avatar menggunakan rig Synty POLYGON, dan klip gerakan kami berasal dari pustaka animasi terbuka yang besar. Karena rig dan klip tersebut memiliki nama tulang yang sama, kasus umum tidak memerlukan retargeting saat runtime; track cukup di-bind berdasarkan nama. Kami menulis keseluruhan pipeline karakter dalam <a href="/id/blog/2026-05-10-open-world-browser-part-25-universal-characters">karakter universal</a>.</p>
<p>Pekerjaan yang menarik muncul ketika keduanya tidak cocok. Kami membangun tahap retargeting yang memetakan satu skeleton ke skeleton lain, dan agar hasilnya tepat, kami harus menyelesaikan tiga masalah khusus. Pertama, Anda menyelaraskan bind pose karena A-pose yang dipasangkan dengan T-pose secara diam-diam menambahkan sekitar tiga puluh derajat pada setiap joint. Kedua, Anda menskalakan root motion dan langkah menggunakan dua rasio berbeda: pinggul-ke-lantai untuk arah vertikal dan proporsi keseluruhan untuk arah horizontal. Ketiga, Anda menguji klip hasil retargeting terhadap sumbernya pada sample rate tetap agar regresi terlihat sebelum pemain menemukannya. Pipeline itulah yang memungkinkan kami menambahkan sumber animasi baru, dan kelak karakter buatan kreator, tanpa memperbaiki setiap klip secara manual.</p>
<p>Di atasnya terdapat state machine animasi yang memilih kelompok klip yang tepat pada setiap frame berdasarkan status gerakan: variasi lompatan berdasarkan kecepatan, tingkat kerasnya pendaratan berdasarkan benturan, arah lereng dari dot product antara kecepatan dan gradien terrain, penghentian yang disesuaikan dengan fase kaki agar karakter tidak berjalan mundur seperti moonwalk saat berhenti, serta debounce seratus milidetik agar benturan dengan dinding tidak membuat animasi berkedip antara berjalan dan jatuh. Tidak satu pun dari hal ini terasa eksotis, tetapi inilah jenis kemampuan yang hanya Anda peroleh dengan memiliki sendiri lapisan tersebut.</p>
<h2>Keputusan keempat: bagian yang tidak disediakan oleh mesin mana pun</h2>
<p>Tiga keputusan lainnya membahas cara dunia ini berjalan. Keputusan ini membahas produk yang sebenarnya kami bangun, dan inilah alasan mengapa perbandingan dengan PlayCanvas pada akhirnya merupakan kekeliruan kategori.</p>
<p>PlayCanvas, Babylon, Unity, dan aplikasi Three.js buatan sendiri semuanya mengasumsikan pola yang sama: Anda membuat game di meja kerja, dalam editor 2D, melihat dunia dari luar, lalu menekan tombol play dan merilis runtime terpisah. Bahkan pengeditan di dalam mesinnya tetap berarti Anda berada di workstation sambil memanipulasi scene yang sedang Anda lihat.</p>
<p>Cinevva World membalikkan pola tersebut. Anda berkreasi dari dalam dunia, sebagai avatar yang berdiri di ruang yang sama dengan tempat para pemain akan berdiri, dengan mendeskripsikan apa yang Anda inginkan dan menyaksikannya muncul. Kreasi dan permainan merupakan satu sesi berkelanjutan, bukan tahap build yang dijembatani ke runtime. Referensi yang paling mendekati adalah Roblox, Rec Room, dan Horizon Worlds, bukan mesin 3D web, dan bahkan platform-platform tersebut masih melakukan sebagian besar proses kreasi dari meja kerja. Hal yang membuat pendekatan ini memungkinkan tanpa editor berbasis mouse adalah pembangun AI, yang mengubah &quot;letakkan dermaga dengan penerangan lentera di sini&quot; menjadi geometri dan penempatan.</p>
<p>Anda tidak bisa sekadar menambahkan kemampuan itu ke mesin serbaguna karena ini bukan fitur rendering. Ini adalah premis seluruh stack, mulai dari cara terrain dapat diedit saat runtime hingga cara jaringan memperlakukan setiap objek sebagai sesuatu yang baru saja dibuat oleh seseorang yang berdiri di dekatnya.</p>
<h2>Kapan Anda tidak seharusnya melakukan apa yang kami lakukan</h2>
<p>Inilah bagian yang biasanya dilewatkan oleh tulisan bertema &quot;kami membangun mesin sendiri.&quot; Jika Anda ingin merilis game browser pada kuartal ini, jangan tiru kami. Gunakan PlayCanvas jika Anda menginginkan editor bergaya Unity dan pipeline terkelola. Gunakan Babylon jika Anda menginginkan mesin lengkap yang sudah menyertakan fisika dan Anda nyaman dengan strukturnya. Gunakan Three.js jika Anda menginginkan kendali maksimal dengan ketentuan minimal dan memiliki tim yang mampu membangun di atasnya. Lakukan port dari Unity jika Anda sudah memiliki game Unity.</p>
<p>Menulis renderer, fisika, dan animasi sendiri hanya merupakan pilihan yang tepat ketika premis produk Anda tidak kompatibel dengan solusi siap pakai—ketika hal yang Anda bangun bukanlah game yang berjalan di atas sebuah mesin, melainkan sebuah tempat yang kebetulan tersusun darinya. Hal itu berlaku bagi kami. Kemungkinan besar hal itu tidak berlaku bagi Anda, dan tidak ada masalah dengan itu. Tujuan evaluasi yang jujur adalah mengetahui Anda berada dalam situasi yang mana sebelum menulis baris pertama.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Dunia yang kosong adalah dunia yang menyedihkan: pelajaran dari setiap platform kreator yang bertahan atau tumbang]]></title>
            <link>https://app.cinevva.com/id/blog/2026-06-06-how-creator-worlds-live-or-die</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-06-06-how-creator-worlds-live-or-die</guid>
            <pubDate>Sat, 06 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Kami membangun AI yang dapat mendirikan bangunan utuh di dunia 3D bersama hanya dari satu kalimat. Sebelum membukanya untuk semua orang, kami mempelajari peluncuran setiap platform serupa yang dapat kami temukan. Kuburannya sangat luas, yang bertahan hanya sedikit, dan garis pemisah di antara keduanya jauh lebih tegas daripada yang pernah diakui oleh segala gegap gempita. Berikut kisah-kisahnya, angka-angkanya, dan hal-hal yang kami lakukan secara berbeda.]]></description>
            <content:encoded><![CDATA[<h1>Dunia yang kosong adalah dunia yang menyedihkan: pelajaran dari setiap platform kreator yang bertahan atau tumbang</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<figure style="margin:1.5rem 0">
<img src="/img/blog/ai-builder-hero.webp" alt="AI Builder Cinevva membangun rumah dua lantai dari perintah obrolan" style="width:100%;border-radius:10px">
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">AI Builder kami. Seseorang mengetik "bangun lantai dua", lalu AI memasang pelat lantai, mendirikan dinding, dan menawarkan tangga serta atap sebagai langkah berikutnya—semuanya di dalam dunia yang dapat dimasuki orang lain.</figcaption>
</figure>
<p>Sekarang kami dapat menciptakan dunia, dan yang saya maksud bukan sekadar video demo. Gambar di atas adalah editor kami. Seseorang mengetik &quot;bangun lantai dua&quot; ke dalam kotak obrolan, lalu menyaksikan AI memasang pelat lantai, mendirikan dinding depan, samping, dan belakang, serta menawarkan untuk melanjutkan dengan tangga dan atap. Bukan properti, bukan tekstur, melainkan struktur utuh yang langsung ditempatkan ke dalam dunia yang dapat dimasuki orang lain. Pipeline kami juga sudah dapat membuat komponen-komponennya: model 3D, musik, suara, dan material.</p>
<p>Jadi, kami hampir siap membuka Cinevva World untuk publik. Namun sebelum melakukannya, saya membaca berita kematian para pendahulunya.</p>
<p>Sebab, inilah kebenaran yang tidak nyaman tentang apa yang sedang kami bangun. Selama lima belas tahun, tim-tim yang sangat cerdas dan didanai dengan sangat baik telah mencoba membuat dunia kreatif bersama berhasil. Beberapa di antaranya tumbuh menjadi salah satu karya terbesar yang pernah dibangun manusia. Sebagian besar sudah mati. Kesenjangan antara kedua hasil itu bukanlah bakat maupun uang, karena beberapa yang sudah mati memiliki keduanya jauh lebih banyak daripada yang mungkin akan pernah kami miliki. Kesenjangan itu terletak pada sejumlah kecil keputusan yang hampir tidak pernah berhasil diambil dengan benar pada percobaan pertama. Inilah yang saya temukan.</p>
<h2>Kuburan</h2>
<p>Mari mulai dari kegagalan, karena kisahnya lebih jujur daripada kisah kesuksesan. Para pemenang menulis ulang sejarah mereka menjadi narasi yang rapi. Dari pihak yang kalah, memo internal bocor.</p>
<h3>Meta Horizon Worlds: ruang kosong termahal yang pernah dibangun</h3>
<p>Meta menghabiskan puluhan miliar dolar untuk pertaruhannya pada metaverse. Reality Labs membukukan <a href="https://www.cnbc.com/2026/03/18/meta-horizon-worlds-metaverse-vr.html">kerugian operasional sebesar $6,02 miliar hanya dalam satu kuartal</a>, yang dilaporkan pada awal 2026, dan telah merugi miliaran dolar setiap kuartal selama bertahun-tahun. Produk andalannya adalah Horizon Worlds. Inilah yang mereka dapatkan dengan uang sebesar itu.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/mNbz7-ejnZw" title="Horizon Worlds - Trailer Resmi" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Horizon Worlds dari Meta, trailer resmi. Platform yang dibangun Meta dengan biaya miliaran dolar ini menghentikan dukungan VR pada Juni 2026 agar dapat bertahan sebagai aplikasi seluler.</figcaption>
</figure>
<p>Sebuah memo internal yang bocor, seperti diberitakan oleh <a href="https://fortune.com/2022/10/07/metas-horizon-world-quality-poor-not-even-employees-using-says-metaverse-vp-leaked-memo/amp/">Fortune</a> dan <a href="https://ryanschultz.com/2022/10/07/leaked-internal-memos-from-meta-detail-problems-with-horizon-worlds-and-horizon-workrooms/">Ryan Schultz</a>, mengungkapkan bahwa hanya sekitar 9 persen dunia buatan kreator yang pernah dikunjungi oleh 50 orang atau lebih. Sebagian besar sama sekali tidak dikunjungi selain oleh pembuatnya sendiri. Salah satu memo merangkum masalah engagement itu dalam sebuah kalimat yang seharusnya ditato pada setiap pendiri perusahaan di bidang ini: <a href="https://kotaku.com/meta-facebook-horizon-worlds-vr-mark-zuckerberg-1849669048">&quot;dunia yang kosong adalah dunia yang menyedihkan.&quot;</a> Para peneliti yang ingin menyurvei pengguna aktif hanya dapat menemukan 514 orang, karena basis pemainnya memang sekecil itu.</p>
<p>Angka retensinya lebih buruk lagi. Data yang bocor menunjukkan bahwa <a href="https://mixed-news.com/en/horizon-worlds-leak-only-1-in-10-users-return-web-launch-coming/">hanya sekitar 1 dari 10 pengguna yang kembali</a> setelah bulan pertama mereka. Meta diam-diam memangkas targetnya sendiri untuk 2022, dari 500.000 pengguna bulanan menjadi 200.000, dan bahkan setelah itu platform tersebut memiliki lebih sedikit pengguna serentak daripada VRChat dan lebih sedikit daripada Second Life, sebuah game dari 2003. Dasbor pengujian internal menunjukkan bahwa karyawan Meta sendiri tidak menggunakannya, sehingga manajemen mulai meminta pertanggungjawaban para manajer atas login mingguan. Seorang VP menempatkan tim dalam &quot;karantina kualitas&quot; selama sisa tahun tersebut dan mengakui secara tertulis bahwa mereka sedang mengerjakan produk yang belum menemukan kecocokan produk-pasar.</p>
<p>Pada Maret 2026, Meta <a href="https://www.cnbc.com/2026/03/18/meta-horizon-worlds-metaverse-vr.html">mengumumkan akan menghentikan dukungan VR sepenuhnya</a> dan mengubah Horizon Worlds menjadi aplikasi yang hampir sepenuhnya berfokus pada perangkat seluler—sebuah pintu masuk bagi orang-orang tanpa headset yang, menurut gambaran mereka sendiri, berfungsi seperti Roblox. Metaverse termahal yang pernah dibangun mengakhiri hidupnya dengan mencoba menjadi sesuatu yang semestinya sudah dibangunnya sejak hari pertama.</p>
<p>Pelajarannya bukanlah &quot;VR hadir terlalu dini&quot;, meskipun memang demikian. Pelajarannya adalah bahwa modal sebanyak apa pun tidak dapat mengisi dunia yang kosong. Kepadatan konten bukanlah sesuatu yang dapat dibeli dengan anggaran pemasaran. Jika dunia-dunianya kosong, orang akan pergi, dan ketika orang-orang pergi, dunia-dunia itu akan tetap kosong. Siklus itu melahap Meta hidup-hidup.</p>
<h3>Decentraland dan The Sandbox: kota hantu bernilai miliaran dolar</h3>
<p>Pada Oktober 2022, satu titik data membuat dunia kripto gempar. <a href="https://www.coindesk.com/web3/2022/10/07/its-lonely-in-the-metaverse-decentralands-38-daily-active-users-in-a-13b-ecosystem">DappRadar melaporkan</a> bahwa Decentraland memiliki 38 pengguna aktif harian. The Sandbox memiliki 522. Pada saat itu, masing-masing proyek tersebut memiliki kapitalisasi pasar sekitar $1,3 miliar.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/Zg5vcdEeLOA" title="Teaser Resmi The Sandbox" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">The Sandbox, teaser resmi. The Sandbox dan Decentraland masing-masing memiliki valuasi sekitar $1,3 miliar ketika jumlah pengguna harian mereka hanya berkisar dari ratusan hingga ribuan kecil.</figcaption>
</figure>
<p>Proyek-proyek tersebut membantahnya, dan nuansanya justru lebih penting daripada bahan olok-oloknya. Angka 38 hanya menghitung dompet unik yang melakukan transaksi on-chain dalam sehari—yang disebut DappRadar sebagai &quot;pembayar&quot;—bukan orang-orang yang masuk dan berkeliling tanpa menyentuh blockchain. Decentraland menanggapinya dengan menyatakan bahwa platform tersebut memiliki <a href="https://blockworks.com/news/metaverse-platforms-set-the-record-straight-about-daily-active-users">56.697 pengguna bulanan yang login</a> dan, menurut perkiraan lain, sekitar 8.000 pengguna harian. The Sandbox mengklaim memiliki 39.000 pengguna harian selama satu musim alfa, dengan retensi hari ke-14 sebesar 40 persen.</p>
<p>Namun renungkan kesenjangan itu sejenak, karena itulah angka terpenting dalam seluruh esai ini. Bahkan dengan menggunakan angka yang paling menguntungkan sekalipun, Anda mendapatkan valuasi miliaran dolar yang paling banter ditopang oleh beberapa ribu pengguna harian. Sebagai perbandingan, riset tersebut menemukan bahwa Roblox yang tidak berbasis blockchain memiliki <a href="https://blockworks.com/news/metaverse-platforms-set-the-record-straight-about-daily-active-users">52 juta pengguna aktif harian, tetapi hanya 11,3 juta pengguna berbayar bulanan</a> dalam periode yang sama. Kebanyakan orang di dunia virtual gratis jarang atau bahkan tidak pernah bertransaksi. Fakta itu berlaku dua arah. Artinya, olok-olok tentang 38 pengguna aktif harian tidaklah adil, sekaligus berarti bahwa valuasi miliaran dolar tersebut hanyalah fantasi. Keduanya mengukur angka yang salah. Valuasinya mengukur spekulasi token. Olok-oloknya mengukur transaksi dompet. Tak satu pun mengukur apakah ada orang yang bersenang-senang.</p>
<p>Itulah jebakan metrik semu dalam bentuknya yang paling murni. Akun terdaftar, kapitalisasi pasar token, total pasar yang dapat dijangkau, impresi media: tak satu pun memberi tahu Anda apakah dunia Anda hidup. Satu-satunya angka yang dapat menjawabnya adalah berapa banyak orang yang kembali, dan apakah orang-orang yang membuat sesuatu terus berkarya.</p>
<h3>Dreams: alat terindah yang tak mampu membuat orang bertahan</h3>
<p>Media Molecule, studio di balik LittleBigPlanet, menghabiskan hampir satu dekade untuk membangun Dreams, sebuah alat kreasi yang begitu mendalam hingga orang-orang membuat game yang dapat dimainkan, film pendek animasi, dan album musik di dalamnya. Para kritikus menyukainya. Namun pada <a href="https://www.pushsquare.com/news/2023/07/dreams-live-service-ending-as-media-molecule-couldnt-find-a-sustainable-path">September 2023, studio tersebut mengakhiri layanan aktifnya</a>, dengan terus terang mengatakan bahwa mereka tidak dapat menemukan model bisnis yang berkelanjutan.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/2ltgkcoQzow" title="Dreams | Trailer Tanggal Rilis | PS4" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Dreams, karya Media Molecule. Sebuah alat kreasi yang dicintai banyak orang, tetapi layanan aktifnya berakhir pada 2023 tanpa pernah memberi kreator cara untuk menghasilkan satu sen pun.</figcaption>
</figure>
<p>Evaluasi pascakegagalannya merupakan daftar panjang luka yang mereka timbulkan sendiri. Saya mengatakan itu dengan rasa hormat yang sangat besar, karena kami pun dapat melakukan setiap kesalahan yang sama. Dreams <a href="https://www.pushsquare.com/news/2023/07/dreams-live-service-ending-as-media-molecule-couldnt-find-a-sustainable-path">tidak pernah memungkinkan kreator memonetisasi karya mereka</a>. Toko dalam game yang dijanjikan tidak pernah dirilis. Tidak ada kosmetik, tidak ada battle pass, tidak ada apa-apa. Kreator serius—orang-orang yang dapat mengubah sebuah alat menjadi platform—tidak punya alasan untuk menginvestasikan waktu bertahun-tahun ketika tidak ada manfaat yang dapat mereka peroleh. Dreams diluncurkan khusus untuk PS4, tanpa versi PC dan tanpa build native PS5 saat peluncuran, yang sangat membatasi calon penggunanya. Selain itu, co-founder <a href="https://icon-era.com/threads/media-molecule-co-founders-biggest-regret-with-dreams-was-not-focusing-on-multiplayer-understands-new-ip-is-more-of-a-game-than-a-creative-tool.11724/">Mark Healey kemudian mengatakan bahwa penyesalan terbesarnya adalah tidak berfokus pada multipemain</a>, dan tim tersebut akhirnya memahami bahwa kreasi mereka lebih cocok menjadi game daripada alat kreatif.</p>
<p>Baca lagi bagian terakhir itu. Studio UGC paling berbakat di dunia akhirnya menyimpulkan bahwa produk tersebut semestinya menjadi game terlebih dahulu dan alat kreasi setelahnya. Itulah satu-satunya kalimat terpenting dalam seluruh kajian ini, dan kita akan kembali membahasnya.</p>
<h3>Bagian lain dari pemakaman</h3>
<p>Polanya berulang dengan konsistensi yang suram.</p>
<p><a href="https://www.gamedeveloper.com/business/crayta-to-shut-down-after-launch-platform-stadia-bites-the-dust">Crayta</a>, platform pembuatan UGC kolaboratif, ditutup pada Maret 2023 dan para pengguna kehilangan semua yang telah mereka buat. Pengembangnya diakuisisi Meta pada 2021, tetapi platform tersebut tetap dimatikan. Penyebab langsungnya: Crayta diluncurkan di Google Stadia, dan ketika Stadia mati, Crayta ikut mati. Ketergantungan pada platform ibarat pistol terisi yang diarahkan ke kepala Anda sendiri.</p>
<figure style="margin:1.5rem 0">
<img src="https://cdn.cinevva.com/blog/lived-or-died-crayta.webp" alt="Crayta, platform pembuatan game kolaboratif" loading="lazy" style="width:100%;border-radius:10px">
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Crayta diluncurkan di Google Stadia. Ketika Stadia ditutup pada 2023, Crayta ikut tumbang, dan para kreator kehilangan semua yang telah mereka buat. Cuplikan dari trailer.</figcaption>
</figure>
<p>Project Spark, alat pembuat game UGC milik Microsoft, ditutup bertahun-tahun sebelumnya dengan alur yang sama: alat yang canggih, tetapi tidak cukup banyak orang yang bertahan. Sansar, penerus Second Life berbasis VR dari Linden Lab, dijual setelah gagal menemukan audiens. High Fidelity, perusahaan metaverse kedua dari pendiri Second Life sendiri, Philip Rosedale, beralih sepenuhnya dari dunia virtual.</p>
<figure style="margin:1.5rem 0">
<img src="https://cdn.cinevva.com/blog/lived-or-died-secondlife.webp" alt="Second Life, dunia virtual buatan pengguna dari Linden Lab" loading="lazy" style="width:100%;border-radius:10px">
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Second Life, dunia buatan Linden Lab dari 2003, masih beroperasi setelah lebih dari dua dekade. Kedua penerus VR-nya, Sansar dan High Fidelity milik Philip Rosedale, sama-sama gagal. Cuplikan dari trailer.</figcaption>
</figure>
<p>Dan dalam sebuah sinyal yang tidak dapat diabaikan karena sedang terjadi saat ini, Rec Room <a href="https://www.uploadvr.com/vrchat-statement-after-rec-room-and-horizon-worlds-fold/">mengumumkan bahwa layanan tersebut akan ditutup efektif mulai 1 Juni 2026</a>, seraya menyatakan bahwa mereka tidak pernah mencapai profitabilitas berkelanjutan.</p>
<p>Para pendiri perusahaan metaverse, yang membangun metaverse, tidak mampu bertahan di metaverse mereka sendiri. Fakta itu seharusnya menakutkan bagi siapa pun yang mengira bahwa rendering adalah bagian tersulitnya.</p>
<figure style="margin:1.5rem 0">
<img src="https://cdn.cinevva.com/blog/lived-or-died-recroom.webp" alt="Rec Room, dunia UGC sosial lintas platform" loading="lazy" style="width:100%;border-radius:10px">
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Rec Room, salah satu dunia kreasi sosial terbesar, menjangkau lebih dari 150 juta pemain sepanjang masa operasinya, tetapi tetap ditutup pada 1 Juni 2026 karena tidak pernah berhasil mengubah jangkauan tersebut menjadi bisnis yang berkelanjutan. Cuplikan dari trailer.</figcaption>
</figure>
<h2>Mereka yang bertahan, dan apa yang benar-benar menyelamatkan mereka</h2>
<p>Sekarang, yang masih hidup. Hal yang menarik untuk dipelajari adalah tak satu pun dari mereka menang dengan cara yang Anda duga, dan beberapa justru menang meski melanggar aturan yang diikuti oleh mereka yang gagal.</p>
<h3>Roblox: kesuksesan instan yang membutuhkan dua belas tahun</h3>
<p>Semua orang menyebut Roblox sebagai model. Hampir tidak ada yang meniru apa yang sebenarnya terjadi, karena yang sebenarnya terjadi adalah dua belas tahun terlihat seperti sebuah kegagalan.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/LTnMKjXEnMY" title="ROBLOX - Trailer Game" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Roblox. Platform ini menarik sekitar 100 orang pada 2006 dan membutuhkan dua belas tahun untuk mencapai pertumbuhan eksponensial, semuanya berkat kebebasan yang diberikan kepada komunitas untuk membuat game.</figcaption>
</figure>
<p>Versi beta Roblox pada 2006 menarik <a href="https://www.howtheygrow.co/p/how-roblox-grows">sekitar 100 penggemar teknologi dengan puncak pengguna serentak sebanyak 30 hingga 40 orang</a>. Setelah itu, platform ini terus maju dengan susah payah selama lebih dari satu dekade. Jumlah penggunanya meningkat dari 9 juta pada awal 2016 menjadi 90 juta pada 2019, lalu 214 juta pada 2023. Pendirinya, David Baszucki, menolak meninggalkan visi konten buatan pengguna bahkan ketika Minecraft melesat melewatinya pada 2009. Ia menganggapnya sebagai proses panjang yang disengaja, dan satu keputusan yang paling menentukan adalah membiarkan komunitas membuat semua game alih-alih membuatnya sendiri secara internal. Keputusan itu menghapus biaya konten dan mengubah setiap kreator menjadi mesin pertumbuhan.</p>
<p>Namun, inilah bagian yang dilewatkan oleh para peniru buta, dan alasan saya selalu membuka sumber kedua. <a href="https://www.matthewball.co/all/roblox2024">Analisis mendalam Matthew Ball pada 2024</a> menunjukkan bahwa Roblox tetap beroperasi dengan kerugian besar bahkan pada skala masif, dengan margin operasi sekitar negatif 38 persen, sementara hanya 6 persen pengguna membeli mata uangnya dalam satu bulan tertentu dan pendapatan per pengguna hanya sebagian kecil dari platform konsol. Roblox adalah game terbesar di dunia dan masih kesulitan menghasilkan uang. Roda pertumbuhannya nyata, tetapi kondisi ekonominya berat. Siapa pun yang mengatakan bahwa platform kreator adalah mesin pencetak uang sedang berusaha menjual sesuatu kepada Anda.</p>
<p>Namun, pelajaran yang lebih dalam terpampang jelas dalam angka-angka pengguna tersebut. Mayoritas besar dari ratusan juta pengguna Roblox tidak pernah membuat apa pun. Mereka datang untuk <em>memainkan</em> katalog berisi puluhan juta game buatan orang lain. Katalog itu membutuhkan satu dekade dan ekonomi pembayaran pengembang untuk tumbuh. Roblox bukanlah alat kreasi yang kebetulan dimainkan orang. Roblox adalah tempat bermain yang kebetulan digunakan oleh sebagian kecil orang untuk berkreasi. Urutan itu menentukan segalanya.</p>
<h3>Minecraft: dunia yang tidak mungkin kosong</h3>
<p>Minecraft tidak pernah menghadapi masalah dunia kosong, dan memahami alasannya adalah inti dari semuanya.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/MmB9b5njVbA" title="Trailer Resmi Minecraft" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Minecraft, trailer resmi. Mode bertahan hidup prosedural membuat dunianya tidak pernah kosong dan tidak pernah membutuhkan konten pengguna agar layak dimainkan.</figcaption>
</figure>
<p>Minecraft diluncurkan sebagai game bertahan hidup dengan generasi prosedural. Dunianya membangun dirinya sendiri tanpa batas, dan sejak menit pertama Anda tidak hanya menatap kanvas kosong sambil bertanya-tanya harus berbuat apa. Malam segera tiba dan sesuatu akan membunuh Anda, jadi Anda menggali. Game ini menyenangkan bagi satu orang, tanpa pengguna lain dan tanpa konten buatan pengguna, selamanya, karena generator proseduralnya merupakan mesin konten yang tidak pernah habis. Mod, server, peta khusus, seluruh ekosistem kreatif—semuanya tumbuh <em>di atas</em> sebuah game yang sudah mampu menjual dirinya sendiri. Mode kreatif hadir setelah jutaan orang telanjur terpikat oleh mode bertahan hidup. Promosi dari mulut ke mulut dan YouTube menyelesaikan sisanya.</p>
<p>Minecraft memecahkan masalah cold-start dengan tidak pernah mengalaminya. Itulah jalan pintasnya, dan kita akan mencurinya.</p>
<h3>Game browser: distribusi sebagai satu-satunya benteng pertahanan</h3>
<p>Lalu ada genre yang paling dekat dengan mekanisme distribusi kita sebenarnya, yaitu game browser tanpa unduhan.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/oznO3GGzu2s" title="Trailer Krunker.io" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Krunker, game FPS browser dalam tradisi .io. Seluruh benteng pertahanan genre ini adalah distribusi: sebuah tautan yang memuat game lengkap tanpa perlu mengunduh.</figcaption>
</figure>
<p><a href="https://news.viverse.com/post/what-are-io-games">Agar.io meraih sekitar 5 juta pemain harian hanya dalam hitungan minggu</a> setelah peluncurannya pada 2015. <a href="http://Slither.io">Slither.io</a> mencatat 68 juta unduhan seluler dan 67 juta permainan melalui browser. Risetnya menyatakan alasannya secara gamblang: <a href="https://news.viverse.com/post/what-are-io-games">&quot;benteng persaingan untuk genre .io adalah distribusinya sendiri, bukan mekanik gamenya.&quot;</a> Anda mengeklik sebuah tautan dan langsung bermain. Tanpa instalasi, tanpa akun, tanpa toko aplikasi. <a href="https://medium.com/the-megacool-blog/9-growth-hacks-from-viral-hit-game-agar-io-7d8f71f70a0c">Proses onboarding Agar.io hanya membutuhkan satu klik</a>: ketik nama, tekan mainkan, dan Anda sudah masuk. Game ini menyebar melalui aplikasi percakapan sebagaimana video menyebar di TikTok.</p>
<p>Namun, hadiah ini menyimpan mata pisau, dan kita pun bisa terluka olehnya. Tanpa unduhan berarti tanpa komitmen. Minimnya hambatan yang memudahkan seseorang masuk juga memudahkannya pergi, karena menutup tab tidak membutuhkan pengorbanan apa pun. Viralitas browser itu nyata, tetapi secara bawaan juga dangkal. Game .io bertahan karena langsung terasa menyenangkan dalam sepuluh detik pertama. Dunia browser yang mati mudah dimasuki tanpa hambatan, tetapi tidak memberi alasan untuk bertahan setelah Anda tiba.</p>
<h3>Among Us, Figma, Townscaper, VRChat: empat cara lain untuk menang</h3>
<p>Empat contoh singkat, karena masing-masing menunjukkan pengungkit yang berbeda.</p>
<p><a href="https://www.esports.net/news/how-among-us-blew-up-online-two-years-after-release/">Among Us</a> diluncurkan pada 2018 dan tidak menghasilkan apa-apa secara komersial selama dua tahun. Para pengembangnya nyaris meninggalkannya. Kemudian, pada September 2020, <a href="https://howtomarketagame.com/2020/09/14/among-us-the-4-lessons-of-their-viral-success/">rangkaian streamer yang semakin lama semakin besar</a> menemukannya, berpuncak pada siaran Sodapoppin selama beberapa jam, dan game itu menjadi fenomena global. Dorongan awalnya datang dari penempatan di halaman depan <a href="http://itch.io">itch.io</a> dan audiens Korea yang kemudian menyumbang separuh penjualannya. Pelajarannya: ledakan popularitas dapat terjadi bertahun-tahun setelah peluncuran, dari kanal yang tidak Anda rencanakan, asalkan Anda bertahan cukup lama untuk ditemukan.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/NSJ4cESNQfE" title="Trailer Peluncuran Among Us di Steam" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Among Us. Game ini hampir tidak diperhatikan selama dua tahun sebelum rangkaian streamer mengubahnya menjadi fenomena global pada 2020.</figcaption>
</figure>
<p><a href="https://review.firstround.com/the-5-phases-of-figmas-community-led-growth-from-stealth-to-enterprise/">Figma</a> berada dalam mode tertutup selama sekitar tiga tahun, diluncurkan secara gratis, lalu menunggu dua tahun lagi sebelum mulai mengenakan biaya. Momen aktivasinya adalah fitur multipemain: saat seorang desainer menyadari bahwa orang lain sedang menyunting berkas yang sama. Dan inilah bagian yang penting. Paket gratis Figma awalnya membatasi Anda hanya sampai 2 kolaborator, yang justru mencekik momen ajaib yang menjual produknya. Mereka memperbaikinya dengan menghapus batas jumlah kolaborator agar orang benar-benar dapat merasakan keunggulan tersebut. Mereka merintis komunitas dengan menyasar langsung para pemengaruh desain di Twitter. Pelajarannya: temukan momen “aha” Anda, lalu singkirkan setiap penghalang antara pengguna baru dan momen tersebut.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/n5gJgkO2Dg0" title="Presentasi Utama Peluncuran Produk Figma" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Figma. Momen aktivasinya adalah fitur multipemain, jadi Figma menghapus batas kolaborator pada paket gratis yang justru menghalangi daya tarik utama produknya.</figcaption>
</figure>
<p><a href="https://www.gamedeveloper.com/game-platforms/how-townscaper-works-a-story-four-games-in-the-making">Townscaper</a> adalah mainan kreatif kecil yang menjadi hit berkat tangkapan layar. Pengembangnya menyaksikan jumlah pengikut Twitter-nya melonjak dari sekitar 20.000 menjadi 90.000 hanya dengan mengunggah klip selama pengembangan, dan membaca hal itu sebagai sinyal awal bahwa gamenya akan berhasil. Pelajarannya: jika karya Anda indah dan orang-orang membagikannya tanpa diminta bahkan sebelum diluncurkan, itulah validasi paling nyata yang bisa diperoleh.</p>
<figure style="margin:1.5rem 0">
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:10px">
<iframe src="https://www.youtube-nocookie.com/embed/hqq25n6cQqo" title="Trailer Peluncuran Townscaper" loading="lazy" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen style="position:absolute;top:0;left:0;width:100%;height:100%"></iframe>
</div>
<figcaption style="color:#9aa7b4;font-size:0.85rem;margin-top:0.5rem">Townscaper, trailer peluncuran. Mainan kreatif tanpa tujuan yang menyebar berkat tangkapan layar yang dibagikan orang tanpa diminta.</figcaption>
</figure>
<p>Dan <a href="https://www.uploadvr.com/vrchat-statement-after-rec-room-and-horizon-worlds-fold/">VRChat</a>, pada bulan-bulan yang sama ketika proyek bernilai miliaran dolar milik Meta dan Rec Room sama-sama tumbang, mencetak rekor hampir 160.000 pengguna serentak. Platform ini digerakkan oleh komunitas dan kreator, serta sama sekali tidak mendapat pendanaan sebesar proyek-proyek yang mati di sekitarnya. VRChat mengaitkan kelangsungan hidupnya dengan loyalitas dan kreativitas komunitas, bukan modal. Pelajarannya, sebagaimana dinyatakan oleh penyintas itu sendiri: semangat kreator yang aktif bertahan lebih lama daripada uang.</p>
<h2>Apa yang sebenarnya membedakan mereka yang hidup dari yang mati</h2>
<p>Letakkan kisah-kisah ini berdampingan dan polanya tampak sangat jelas.</p>
<table>
<thead>
<tr>
<th>Platform</th>
<th>Taruhannya</th>
<th>Hasil akhirnya</th>
<th>Pelajarannya</th>
</tr>
</thead>
<tbody>
<tr>
<td>Minecraft</td>
<td>Mode bertahan hidup prosedural, menyenangkan untuk satu pemain</td>
<td>Game terlaris sepanjang masa, lebih dari 350 juta kopi</td>
<td>Jangan pernah memiliki dunia kosong</td>
</tr>
<tr>
<td>Roblox</td>
<td>Game buatan komunitas ditambah pembayaran kreator</td>
<td>Lebih dari 80 juta pengguna harian dalam dua belas tahun</td>
<td>Jadilah tempat bermain terlebih dahulu, alat kreasi kemudian</td>
</tr>
<tr>
<td>Game .io</td>
<td>Permainan browser sekali klik tanpa unduhan</td>
<td>Jutaan pemain dalam hitungan minggu</td>
<td>Distribusi adalah benteng pertahanan, komitmennya dangkal</td>
</tr>
<tr>
<td>Figma</td>
<td>Paket gratis, multipemain waktu nyata</td>
<td>Tawaran akuisisi sekitar $20 miliar</td>
<td>Singkirkan setiap penghalang menuju momen “aha”</td>
</tr>
<tr>
<td>Among Us</td>
<td>Game sosial murah dan kesabaran</td>
<td>3,8 juta pengguna serentak, terlambat dua tahun</td>
<td>Bertahanlah cukup lama agar dapat ditemukan</td>
</tr>
<tr>
<td>Townscaper</td>
<td>Mainan indah yang layak ditangkap layarnya</td>
<td>Sekitar 380 ribu penjualan, penyebaran organik</td>
<td>Pembagian tanpa diminta adalah sinyal paling nyata</td>
</tr>
<tr>
<td>VRChat</td>
<td>Energi komunitas dan kreator</td>
<td>Sekitar 160 ribu pengguna serentak pada 2026</td>
<td>Semangat bertahan lebih lama daripada modal</td>
</tr>
<tr>
<td>Horizon Worlds</td>
<td>Modal miliaran dolar, mengutamakan VR</td>
<td>VR ditutup pada 2026, sekitar 1 dari 10 pengguna kembali</td>
<td>Uang tidak dapat mengisi dunia yang kosong</td>
</tr>
<tr>
<td>Decentraland / Sandbox</td>
<td>Ekonomi token sebelum ada game</td>
<td>Valuasi sekitar $1,3 miliar, ratusan pengguna harian</td>
<td>Valuasi bukanlah audiens</td>
</tr>
<tr>
<td>Dreams</td>
<td>Alat yang mendalam, tanpa ekonomi, tanpa multipemain</td>
<td>Layanan live berakhir pada 2023</td>
<td>Bayar kreator, luncurkan multipemain, jadilah sebuah game</td>
</tr>
<tr>
<td>Crayta</td>
<td>Platform UGC yang bergantung pada Stadia</td>
<td>Ditutup bersama Stadia pada 2023</td>
<td>Jangan pernah membangun di atas platform yang dapat mengusir Anda</td>
</tr>
<tr>
<td>Project Spark / Sansar</td>
<td>Alat canggih, tanpa alasan untuk kembali</td>
<td>Ditutup atau beralih arah</td>
<td>Alat tanpa game tidak menciptakan kebiasaan harian</td>
</tr>
</tbody>
</table>
<p>Hal yang membunuh dunia kreatif adalah ruangan kosong. Horizon Worlds, Decentraland, Dreams, Crayta, Project Spark, Sansar—semuanya mati dengan cara yang sama: tidak cukup orang, tidak cukup konten, tidak cukup alasan untuk kembali, dalam lingkaran yang terus memperburuk dirinya sendiri. Masalah cold-start adalah pertarungan bos. Semua yang lain hanyalah level tutorial.</p>
<p>Hal yang menyelamatkan mereka adalah adanya alasan untuk eksis sebelum kerumunan datang. Minecraft memiliki mode bertahan hidup prosedural. Roblox memiliki game-game yang dirintis dengan sabar selama satu dekade. Game .io menawarkan keseruan dalam sepuluh detik. Setiap penyintas sudah layak mendapat waktu Anda bahkan dengan katalog kosong. Setiap korban hanyalah wadah indah yang menunggu orang lain membuatnya layak dikunjungi. Inilah pengakuan Dreams yang berlaku secara umum: buatlah game terlebih dahulu dan platform kemudian. Platform adalah babak kedua. Anda harus mendapatkannya dengan terlebih dahulu menjadi sesuatu yang digunakan orang karena nilai dari dirinya sendiri.
Metrik yang benar-benar memprediksi keberlangsungan bukanlah yang tercantum dalam siaran pers. Riset mengenai hal ini konsisten. Sinyal utama kecocokan produk dengan pasar adalah <a href="https://newsletter.pmcurve.com/p/retention-masterclass">kurva retensi Anda mendatar</a>: ada kelompok pengguna yang terus kembali tanpa batas waktu. Kurva yang terus menurun hingga nol berarti tidak ada kecocokan, sebesar apa pun bagian teratas corong Anda. Patokan kasar industri untuk retensi adalah <a href="https://solsten.io/blog/d1-d7-d30-retention-in-gaming">40 persen pada hari ke-1, 20 persen pada hari ke-7, dan 10 persen pada hari ke-30</a>, dengan hari ke-30 sebagai prediktor kesehatan jangka panjang. Dan untuk produk apa pun yang memiliki sisi kreator, sisi suplai adalah tempat Anda tumbang: <a href="https://forkoff.xyz/blog/founder-growth/two-sided-marketplace-cold-start-2026">sekitar 67 persen marketplace yang gagal ambruk karena suplai</a>, bukan permintaan. Retensi kreator adalah tanda vitalnya. Akun terdaftar dan valuasi hanyalah metrik semu.</p>
<p>Ada beberapa pelajaran lain yang muncul dari kisah-kisah tersebut. Bantu kreator Anda menghasilkan uang atau kehilangan mereka, karena Dreams membuktikan bahwa orang-orang berbakat tidak akan menginvestasikan bertahun-tahun tanpa potensi keuntungan. Menurut penyesalan Media Molecule sendiri, multipemain biasanya merupakan inti produknya, bukan sekadar fitur. Jangan pernah membangun rumah di atas platform yang dapat mengusir Anda, seperti yang ditunjukkan Crayta. Dan tanpa unduhan adalah pedang bermata dua: itu merupakan kanal akuisisi terbaik yang pernah ada sekaligus sarana terlemah untuk membangun komitmen, sehingga seluruh bebannya jatuh pada kualitas enam puluh detik pertama.</p>
<h2>Jebakan yang mendasari semuanya</h2>
<p>Ada satu lapisan lagi, dan lapisan ini khas untuk zaman kita, karena kita memiliki alat yang tidak pernah dimiliki mereka yang telah tumbang. Kita dapat menghasilkan dunia dengan AI. Hal itu memunculkan sebuah paradoks yang terus saya pertimbangkan dari berbagai sisi selama berminggu-minggu.</p>
<p>Jika menggunakan AI, bukankah setiap dunia seharusnya unik, dibuat baru untuk setiap orang, dan disesuaikan untuk mereka? Namun, jika dunia setiap orang unik, bagaimana seseorang bisa bertemu orang lain, mengingat sebuah momen bersama membutuhkan tempat bersama? Dan jika dunia itu tetap harus dibagikan, mengapa harus menggunakan AI, alih-alih merancang satu tempat indah secara manual seperti studio sungguhan?</p>
<p>Masing-masing dorongan itu, jika diikuti sampai akhir, berujung pada sesuatu yang tidak berfungsi. Dunia yang dibuat khusus untuk Anda adalah dunia tanpa siapa pun di dalamnya. Genie milik Google dapat membuat lingkungan yang bisa dimainkan hanya dari satu kalimat, lalu lingkungan itu lenyap semenit kemudian—pemain tunggal, tanpa ingatan, tanpa tetangga. Itulah jalan buntu yang sepi. Namun, merancang satu dunia tetap secara manual juga merupakan jalan buntu: dibutuhkan seratus orang selama bertahun-tahun untuk mengisi dua kilometer persegi dengan tangan, dan setelah selesai, dunia itu membeku, tetap sama pada kunjungan keseratus seperti pada kunjungan pertama, serta tidak mampu berkembang seiring kedatangan orang-orang.</p>
<p>Jalan keluarnya adalah berhenti menganggap &quot;dunia&quot; sebagai satu hal. Dunia terdiri atas tiga lapisan, dan keunikan serta kebersamaan dapat hidup di lapisan yang berbeda tanpa saling bertentangan. Tanah tempat semua orang berpijak adalah satu dunia bersama, dikurasi dengan standar tinggi, sebagai tempat pertemuan. Apa yang Anda bawa ke dalamnya—aset buatan AI Anda, bangunan yang Anda buat—benar-benar unik, dan Anda menempatkannya <em>ke dalam</em> dunia bersama agar keunikan Anda menjadi penemuan bagi semua orang lain. Sementara perjalanan Anda melaluinya—misi yang Anda dapatkan, hal-hal yang ditunjukkan kepada Anda—dapat dipersonalisasi tanpa mengorbankan apa pun, karena jalur bukanlah tempat. Pilihan palsunya adalah antara &quot;dunia yang dipersonalisasi,&quot; yang mematikan multipemain, dan &quot;jalur yang dipersonalisasi melalui dunia bersama,&quot; yang justru memperdalam pengalaman multipemain. Kita menginginkan yang kedua.</p>
<p>Jadi, tugas AI sejak awal bukanlah memberikan dunia pribadi kepada setiap orang. Tugasnya adalah membuat satu dunia bersama terasa tak terbatas, hidup, dan personal untuk dijelajahi. Keunikannya berasal dari segala sesuatu yang bertumbuh dan terkumpul di dalamnya seiring waktu, dari setiap kontribusi unik para kreator. Setiap server Minecraft itu unik. Semua orang di server tertentu berbagi dunia yang sama. Itu bukan kontradiksi. Itulah inti triknya, dan tangkapan layar di bagian atas tulisan ini—AI membangun rumah yang tetap berdiri di dalam dunia yang dapat dimasuki orang lain—adalah wujud nyata dari trik tersebut.</p>
<h2>Cara kami meluncurkan Cinevva World</h2>
<p>Jadi, inilah bentuk konkretnya bagi kami. Bukan rencana pemasaran. Lima taruhan, yang sengaja kami pasang untuk melawan lima hal yang menumbangkan semua pihak pada paruh pertama tulisan ini. Dan saya akan menilai masing-masing berdasarkan seberapa kuat bukti yang benar-benar mendukungnya, karena rencana yang tidak dapat dinilai hanyalah angan-angan dengan pencahayaan bagus.</p>
<p><strong>Taruhan pertama, yang berani saya jadikan pertaruhan perusahaan: kami meluncurkan sebuah game, bukan platform.</strong> Ini bukan soal preferensi, melainkan temuan paling konsisten dalam seluruh studi. Minecraft, Roblox, dan Fortnite semuanya memulai dengan sesuatu yang menyenangkan untuk <em>dilakukan</em>, lalu menumbuhkan lapisan kreator di atasnya. Setelah semuanya berlalu, Media Molecule—studio kreasi paling berbakat yang masih ada—menyimpulkan bahwa Dreams seharusnya menjadi game terlebih dahulu. Jadi, hal pertama yang dilakukan orang baru di Cinevva World bukanlah menatap lahan kosong. Mereka akan memasuki sebuah siklus permainan dengan tujuan, sebuah alasan untuk berada di sana pada hari Selasa ketika hampir tidak ada orang lain yang online. Sebagian besar orang yang datang akan bermain dan tidak pernah membangun, dan itu memang desainnya, bukan kegagalan. Itulah bentuk Roblox yang sesungguhnya: ratusan juta orang yang bermain, ditopang oleh lapisan tipis orang yang berkarya. Roda pertumbuhannya adalah babak kedua, dan kami harus lebih dahulu layak mendapatkannya. Saya yakin akan hal ini karena kuburan para pendahulu sudah menjalankan eksperimennya.</p>
<p><strong>Taruhan kedua, yang sejujurnya memang sebuah spekulasi: AI memungkinkan kami memproduksi suplai yang gagal didapatkan pihak lain hingga mereka tumbang.</strong> Saya ingin menjelaskan secara tepat mengapa ini merupakan taruhan, bukan jaminan, karena tidak ada platform dalam studi ini yang pernah dirintis dengan AI generatif. Saya memiliki mekanisme, bukan bukti. Mekanismenya: sekitar dua pertiga platform dua sisi tumbang di sisi suplai, bukan sisi permintaan. Solusi klasiknya adalah memalsukan suplai hingga suplai nyata terbentuk, seperti DoorDash yang mengantarkan sendiri makanannya, tim Reddit yang membuat postingan memakai nama samaran, dan para pendiri Roblox yang membangun sendiri game-game awal selama bertahun-tahun. Kami dapat melakukannya dengan generasi AI, dengan biaya dan kecepatan yang tidak pernah mereka miliki. Namun, inilah bagian yang menjaga saya tetap realistis, dan ini adalah pelajaran dari batu nisan Decentraland: Decentraland dipenuhi konten yang dihasilkan secara otomatis tetapi hanya menarik sekitar tiga puluh orang per hari, karena indah tidak sama dengan layak menghabiskan waktu di sana. Jadi, saya tidak bertaruh bahwa AI akan membuat dunia ini menyenangkan. AI tidak mampu melakukannya. Saya bertaruh bahwa AI akan menghilangkan hambatan produksi aset sehingga setiap jam dari tenaga manusia kami yang terbatas dapat dicurahkan pada satu hal yang benar-benar mempertahankan pemain: siklus permainannya. AI membangun bukit dengan murah. Kami merancang sendiri alasan untuk mendakinya. Dan kami membatasi konten awal sintetis pada <a href="https://forkoff.xyz/blog/founder-growth/two-sided-marketplace-cold-start-2026">sekitar 30 persen, lalu mengubahnya menjadi konten kreator sungguhan dalam waktu sekitar 60 hari</a>, karena suplai palsu yang tidak pernah menjadi nyata akan menghancurkan kepercayaan begitu ada yang menyadarinya.</p>
<p><strong>Taruhan ketiga: kami memublikasikan sendiri kriteria penghentian kami.</strong> Inilah perbedaan antara rencana yang berpijak pada kenyataan dan rencana yang hanya penuh harapan. Metrik yang memprediksi keberlangsungan dalam setiap kasus adalah apakah <a href="https://newsletter.pmcurve.com/p/retention-masterclass">kurva retensi mendatar</a>, apakah sebagian kelompok pengguna terus kembali alih-alih menyusut hingga nol. Jadi, itulah ujian yang kami tetapkan secara terbuka untuk diri sendiri. Jika retensi hari ke-7 versi alfa tidak mendatar, jika pemain yang tidak pernah membangun tidak kembali, jika konten awal buatan AI hanya dilewati dan diabaikan, berarti tesis kami salah, dan kami akan mengubahnya atau berhenti. Kami akan melacak pemain dan kreator sebagai dua corong terpisah dengan dua momen pencerahan yang berbeda, karena datanya dengan jelas menunjukkan bahwa mereka bukan orang yang sama. Dan kami tidak akan berpura-pura bahwa uang dapat melakukan pekerjaan awal tersebut. Dengan lima puluh pengguna, atau bahkan seribu, tip dan penghasilan marketplace praktis bernilai nol, sehingga belum dapat mempertahankan siapa pun. Retensi awal berasal dari siklus permainan, atau tidak akan muncul sama sekali. Dreams adalah bukti nyata akibat membalik urutan itu.</p>
<p><strong>Taruhan keempat: kami sengaja memulai dari lingkup sempit.</strong> Riset tentang produk berjejaring mencapai kesimpulan yang sama. Anda tidak meluncurkan ke sebuah pasar, tetapi ke sebuah <a href="https://www.lennysnewsletter.com/p/atomic-network">&quot;jaringan atomik,&quot;</a> kelompok terkecil yang cukup padat untuk hidup secara mandiri. Facebook bermula di satu sekolah. Jaringan kami sudah ada: para kreator Cinevva yang telah menghasilkan aset 3D, musik, dan suara, serta sudah memiliki inventaris untuk ditempatkan. Lima puluh orang dari mereka di satu dunia pada jam yang sama, dengan sebuah tujuan dan wilayah baru untuk dijelajahi, jauh lebih padat dan hidup daripada lima puluh ribu pendaftar yang tersebar. Bukti sangat kuat mendukung taruhan ini.</p>
<p><strong>Taruhan kelima, yang paling lemah, dan saya akan mengakuinya: kami menyampaikan kenyataan tentang kekosongan itu alih-alih menyembunyikannya.</strong> Dunia yang dipoles tetapi sunyi terasa seperti dunia mati, dan semua pihak yang gagal mencoba menutupinya dengan efek suasana. Kami akan mencoba kebalikannya. Ini adalah langkah yang paling minim bukti di antara kelimanya, lebih mendekati firasat daripada temuan. Orang-orang pertama yang masuk bukan sedang mengunjungi produk yang belum selesai. Mereka adalah warga pendiri sebuah tempat yang kosong <em>karena mereka datang lebih awal</em>, dan apa yang mereka bangun akan tetap berdiri ketika seribu orang berikutnya tiba.</p>
<p>Itulah rencananya, dinilai dengan jujur. Empat taruhan yang didukung kuat oleh kuburan para pendahulu, dan satu spekulasi nyata pada alat yang tidak dimiliki mereka yang telah tumbang, dibatasi oleh disiplin yang justru tidak mereka miliki. Kami dapat menghasilkan bukitnya. Kami tidak dapat menghasilkan perasaan menjadi orang pertama yang mendakinya, ataupun orang asing yang melambaikan tangan dari puncak. Tugas kami adalah memungkinkan lambaian itu terjadi, membuktikannya melalui kurva retensi, dan berhenti menipu diri sendiri begitu kurvanya berkata tidak.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 30: Kamera yang menghormati dinding]]></title>
            <link>https://app.cinevva.com/id/blog/2026-06-04-open-world-browser-part-30-collision-aware-camera</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-06-04-open-world-browser-part-30-collision-aware-camera</guid>
            <pubDate>Thu, 04 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Dua puluh sembilan bagian telah membangun dunia tempat Anda dapat berjalan, berenang, dan membangun, semuanya diamati oleh kamera yang menembus bukit dan dinding rumah. Bagian 30 memperbaikinya dengan boom yang sadar akan tabrakan: lengan pegas yang hanya mengendalikan panjangnya sendiri, kontrak collider yang dapat dipasang agar medan, properti, dan bangunan semuanya menghentikan kamera melalui antarmuka yang sama, serta probe jarak bertanda yang memperhitungkan satu hal yang tidak pernah dapat ditangani heightmap, yaitu overhang dan gua. Sistem ini dipasang sebagai pascaproses di atas OrbitControls tanpa menulis ulang satu baris pun logika input orbit yang sudah kita percayai.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 30: Kamera yang menghormati dinding</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru mengikuti seri ini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menautkan semua bagian.</p>
<p><a href="/id/blog/2026-05-15-open-world-browser-part-29-pluggable-character">Bagian 29</a> memberi kita satu controller yang dapat mengendalikan tubuh apa pun. Tubuh itu sekarang bergerak dengan benar. Ia berjalan, meluncur, berenang, melayang, memanjat masuk ke gua, dan merunduk di bawah overhang. Masalahnya adalah apa yang mengamatinya. Selama dua puluh sembilan bagian, kameranya berupa rig orbit standar yang mengikuti pemain dan hanya melakukan satu hal cerdas untuk menghindari masalah: kamera menolak dimiringkan ke bawah garis cakrawala agar tidak dapat menyelinap ke bawah tanah datar. Clamp itu adalah petunjuknya. Clamp tersebut ada karena kamera sama sekali tidak mengetahui letak geometri dunia, sehingga satu-satunya pertahanan terhadap clipping adalah melarang sudut-sudut yang paling mungkin menyebabkan clipping. Berjalanlah mendekati bukit dan kamera akan berada di dalam bukit. Masuklah ke salah satu gua marching cubes dari <a href="/id/blog/2026-02-25-open-world-browser-part-07-marching-cubes">Bagian 7</a> dan Anda akan melihat bagian dalam batu. Bangunlah rumah dengan alat authoring dari <a href="/id/blog/2026-04-28-open-world-browser-part-16-structure-and-authoring">Bagian 16</a>, lalu berdirilah di dalam ruangan, dan kamera akan melayang di luar dinding sambil menghadap pelapis luarnya. Bagian ini membuat kamera menghormati geometri sebagaimana tubuh pemain sudah melakukannya.</p>
<h2>Bentuk masalah dan bentuk solusinya</h2>
<p>Kamera orang ketiga memiliki satu tugas yang sulit dan belasan tugas yang mudah. Tugas mudahnya adalah mengikuti, memperhalus gerakan, dan menangani input orbit, dan semuanya sudah kita miliki. Tugas sulitnya disebut sebagai batasan visibilitas dalam literatur akademis, dan survei yang dirujuk semua orang, <em>Camera Control in Computer Graphics</em> karya Christie dan Olivier, membingkai seluruh bidang ini di sekitarnya: pertahankan subjek di dalam bingkai dan jangan sampai terhalang, sambil tetap menghormati dunia. Saat runtime, persoalan itu dapat dipersempit menjadi pertanyaan yang tampak sederhana dan diajukan setiap frame. Pemain adalah pivot. Pengguna telah memutar dan memperbesar atau memperkecil kamera ke posisi yang diinginkan pada jarak tertentu di belakang pemain. Seberapa jauh kamera benar-benar dapat ditempatkan di sepanjang garis tersebut sebelum menembus benda padat? Jawab pertanyaan itu dengan akurat, maka kamera akan merapat ke depan bukit, bergeser masuk sepanjang boom saat Anda mundur ke sudut, dan berhenti di langit-langit gua alih-alih menembusnya.</p>
<p>Pola yang menjawabnya sudah lama digunakan dan terbukti andal. Unreal menyebutnya spring arm, Godot menyediakan node <code>SpringArm3D</code>, dan Cinemachine milik Unity membaginya antara rig pengikut orang ketiga dan ekstensi deoccluder. Gagasannya selalu sama. Gantungkan kamera di ujung boom yang ditambatkan pada pivot. Pertahankan kamera pada panjang yang diinginkan ketika jalurnya bebas, tarik kamera mendekati pivot ketika ada sesuatu yang menghalangi, lalu pegas kembali ke luar ketika jalurnya kembali bebas. <em>Real-Time Cameras</em> karya Mark Haigh-Hutchinson, yang ditulis oleh pemimpin kamera Metroid Prime, mencurahkan beberapa bab penuh untuk membahas berbagai mode kegagalan yang dapat mengubah implementasi naif menjadi sesuatu yang membuat pemain mual. Kita mengambil pola tersebut dan membangun versi kita sendiri, cukup ringkas untuk dibaca dalam sekali duduk, di <code>public/world/src/camera-rig.mjs</code>.</p>
<figure style="margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12);border-radius:8px;overflow:hidden;background:#0d1117">
<svg viewBox="0 0 680 290" width="100%" role="img" aria-label="Boom lengan pegas memendek sepanjang garisnya sendiri sehingga bola probe bersandar pada dinding alih-alih menembusnya" style="display:block">
  <rect x="382" y="40" width="46" height="222" fill="#39424f" stroke="#5b6675"/>
  <text x="405" y="280" fill="#9aa7b4" font-size="13" text-anchor="middle" font-family="sans-serif">dinding</text>
  <line x1="110" y1="212" x2="600" y2="70" stroke="#9aa7b4" stroke-width="2" stroke-dasharray="6 6"/>
  <line x1="110" y1="212" x2="360" y2="140" stroke="#6ea8fe" stroke-width="3"/>
  <circle cx="110" cy="212" r="6" fill="#e6edf3"/>
  <text x="110" y="234" fill="#e6edf3" font-size="13" text-anchor="middle" font-family="sans-serif">pivot (kepala pemain)</text>
  <circle cx="600" cy="70" r="9" fill="none" stroke="#9aa7b4" stroke-width="2"/>
  <text x="600" y="52" fill="#9aa7b4" font-size="13" text-anchor="middle" font-family="sans-serif">posisi yang diinginkan (zoom pengguna)</text>
  <circle cx="360" cy="140" r="22" fill="rgba(110,168,254,0.18)" stroke="#6ea8fe" stroke-width="2"/>
  <circle cx="360" cy="140" r="5" fill="#6ea8fe"/>
  <text x="300" y="104" fill="#6ea8fe" font-size="13" text-anchor="middle" font-family="sans-serif">kamera + radius probe r</text>
  <text x="222" y="192" fill="#6ea8fe" font-size="13" font-family="sans-serif" transform="rotate(-16 222 192)">ℓ (dibatasi)</text>
</svg>
<figcaption style="padding:0.6rem 1rem;color:#9aa7b4;font-size:0.85rem;border-top:1px solid rgba(255,255,255,0.12);font-family:sans-serif">Boom mempertahankan kamera pada zoom yang diinginkan pengguna sampai sebuah penghalang masuk ke jalurnya, lalu memendek sepanjang garis yang sama sehingga bola probe bersandar pada permukaan alih-alih near plane menembusnya.</figcaption>
</figure>
<h2>Boom yang hanya mengendalikan panjangnya</h2>
<p>Aturan desain yang menjaga rig ini tetap ringkas dipinjam dari pekerjaan controller di Bagian 29: kendalikan satu hal secara penuh dan tolak sisanya. Rig ini mengendalikan panjang boom dan tidak mengendalikan hal lain. Yaw, pitch, damping orbit, gestur sentuh dan roda gulir, semuanya tetap ditangani OrbitControls, yang sudah menyelesaikannya dengan baik dan sama sekali tidak ingin kita tulis ulang. Jadi, rig ini bukan controller kamera. Ini adalah pascaproses yang berjalan setelah perhitungan orbit dan mengoreksi tepat satu angka, yaitu jarak dari pivot ke kamera.</p>
<p>Keputusan itu terdengar rapi dan nyaris langsung merusak semuanya karena cara berpikir OrbitControls. Pada awal setiap pembaruan, OrbitControls membaca posisi kamera saat ini dan memperoleh radius orbit darinya. Biasanya proses itu tidak terlihat. Namun, begitu rig kita memperpendek posisi kamera untuk menghindari dinding, pada frame berikutnya OrbitControls membaca posisi yang telah diperpendek tersebut, menyimpulkan bahwa pengguna pasti telah memperbesar tampilan, lalu menetapkan pemendekan itu sebagai zoom yang diinginkan pengguna. Setelah beberapa frame, kamera pun merapat ke kepala pemain dan tidak mau kembali menjauh. Solusinya adalah dua pemanggilan yang mengapit pembaruan orbit, dan hanya itulah seluruh integrasinya. Sebelum OrbitControls berjalan, <code>beforeControls()</code> mengembalikan kamera ke jarak penuh dari frame sebelumnya yang belum diperpendek, sehingga perhitungan orbit selalu membaca zoom pengguna yang sebenarnya. Setelah OrbitControls berjalan, <code>afterControls(dt)</code> membaca posisi target yang baru selesai diorbitkan tersebut, menyelesaikan tabrakan, menerapkan damping pada panjangnya, dan menempatkan kamera di posisi yang seharusnya benar-benar dirender. Maksud pengguna dan koreksi tabrakan tidak pernah saling memengaruhi, dan dolly tetap seresponsif sebelum rig ini ada. Pengujian headless yang kita tulis untuk rig ini mengunci perilaku tersebut secara tepat: dorong boom ke dinding selama enam puluh frame, singkirkan dindingnya, dan panjang boom akan kembali memantul ke zoom penuh pengguna sejauh sepuluh meter, bukan tertahan pada jarak tabrakan.</p>
<h2>Satu kontrak untuk collider apa pun</h2>
<p>Rig tidak pernah menanyakan dunia terbuat dari apa. Collider hanyalah objek dengan metode <code>probe</code>, dan rig memberinya sebuah ray, jarak maksimum, serta radius probe kamera, lalu menerima satu angka sebagai hasilnya, yaitu jarak terjauh yang dapat ditempuh kamera sebelum collider tersebut menghalanginya. Rig memeriksa setiap collider yang terdaftar dan mengambil benturan terdekat. Itulah keseluruhan kontraknya, dan pendekatan ini sama dengan yang digunakan character controller ketika mengubah lokomosi menjadi perilaku yang dapat dipasang. Medan dapat dipasang, properti dapat dipasang, selubung bangunan dapat dipasang, masing-masing di balik <code>probe</code> yang sama, sementara rig tetap tidak perlu mengetahui apa pun tentang semuanya. Menambahkan jenis penghalang baru berarti menambahkan collider ke daftar, bukan mengedit kamera.</p>
<p>Satu detail dalam kontrak ini terbukti sangat berguna, yaitu radius probe. Kita tidak menembakkan ray tipis dari pivot ke kamera, tetapi menyapu bola yang cukup besar untuk menampung near plane kamera. Satu ray menghentikan pusat kamera pada dinding, tetapi near plane memiliki lebar, sehingga sudut-sudutnya sudah akan tertanam di dalam dinding sebelum ray di pusat melaporkan benturan. Menyapu bola kecil alih-alih ray adalah pendekatan yang digunakan setiap implementasi produksi; Unreal mengeksposnya sebagai ukuran probe. Inilah perbedaan antara kamera yang bersandar rapi pada permukaan dan kamera yang memungkinkan Anda melihat menembus permukaan di tepi layar.</p>
<p>Kita tidak menebak radius tersebut, melainkan menghitungnya. Titik near plane yang terjauh dari kamera adalah salah satu sudutnya, dan jaraknya dapat langsung diturunkan dari proyeksi. Dengan near plane $n$ dan field of view vertikal $\theta$, setengah tingginya adalah $h = n\tan(\theta/2)$, setengah lebarnya adalah $w = h\cdot\text{aspect}$, dan sudutnya berada pada jarak</p>
<p>$$
r_{\text{near}} = \sqrt{n^2 + w^2 + h^2}
$$</p>
<p>Radius probe adalah jarak sudut tersebut dikalikan margin keamanan kecil, dengan batas bawah tetap agar tidak pernah turun di bawah nilai minimum yang masuk akal pada frustum yang sangat sempit. Setiap kali field of view, rasio aspek, atau near plane berubah, radius dihitung ulang, sehingga perubahan ukuran jendela atau zoom yang memengaruhi proyeksi tidak dapat diam-diam membuat probe terlalu kecil untuk mencakup sudut-sudut yang seharusnya dilindunginya.</p>
<h2>Collider yang memahami gua</h2>
<p>Collider medan menjadi bagian yang menarik, karena medan di engine kita bukanlah heightmap. Sejak Bagian 7, medan tersebut berupa signed distance field, sebuah fungsi yang mengembalikan seberapa jauh titik mana pun di ruang dari permukaan padat terdekat dan apakah titik tersebut berada di dalam atau di luar batu. Nilai positif berarti udara, nilai negatif berarti batu, dan satu fakta itulah yang memungkinkan kamera kita melakukan sesuatu yang secara struktural tidak dapat dilakukan kamera berbasis heightmap. Heightmap mengetahui ketinggian tanah pada koordinat x dan z. Heightmap tidak memiliki konsep langit-langit karena hanya ada satu permukaan di atas setiap titik. Jadi, kamera berbasis heightmap dapat mencegah Anda berjalan menembus bukit, tetapi sama sekali tidak mengetahui bahwa bibir overhang atau atap gua menggantung di atas pivot, sehingga kamera melaju menembus keduanya. Distance field mengetahui setiap permukaan dalam tiga dimensi, sehingga probe yang sama yang menghentikan kamera pada lereng bukit juga menghentikannya pada langit-langit gua tanpa satu pun kasus khusus.</p>
<figure style="margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12);border-radius:8px;overflow:hidden;background:#0d1117">
<svg viewBox="0 0 680 320" width="100%" role="img" aria-label="Di bawah overhang, heightmap membiarkan boom menembus batu langit-langit, sedangkan signed distance field menghentikannya pada sisi bawah langit-langit" style="display:block">
  <path d="M680,320 L680,40 L250,40 L250,150 L430,150 L430,250 L250,250 L250,320 Z" fill="#39424f" stroke="#5b6675" stroke-width="1.5"/>
  <text x="340" y="205" fill="#9aa7b4" font-size="13" text-anchor="middle" font-family="sans-serif">gua</text>
  <text x="540" y="100" fill="#5b6675" font-size="13" text-anchor="middle" font-family="sans-serif">batuan padat</text>
  <line x1="330" y1="212" x2="230" y2="60" stroke="#9aa7b4" stroke-width="2" stroke-dasharray="6 6"/>
  <line x1="290" y1="150" x2="250" y2="90" stroke="#f85149" stroke-width="4"/>
  <circle cx="330" cy="212" r="6" fill="#e6edf3"/>
  <text x="330" y="234" fill="#e6edf3" font-size="13" text-anchor="middle" font-family="sans-serif">pemain</text>
  <circle cx="230" cy="60" r="10" fill="none" stroke="#f85149" stroke-width="2"/>
  <text x="230" y="42" fill="#f85149" font-size="13" text-anchor="middle" font-family="sans-serif">heightmap: menembus ✗</text>
  <circle cx="305" cy="170" r="9" fill="rgba(86,211,100,0.2)" stroke="#56d364" stroke-width="2"/>
  <text x="420" y="172" fill="#56d364" font-size="13" text-anchor="middle" font-family="sans-serif">SDF: berhenti di langit-langit ✓</text>
</svg>
<figcaption style="padding:0.6rem 1rem;color:#9aa7b4;font-size:0.85rem;border-top:1px solid rgba(255,255,255,0.12);font-family:sans-serif">Heightmap menyimpan satu permukaan per kolom, sehingga tidak pernah melihat lempengan batu di atas pemain dan membiarkan boom menembus langit-langit. Distance field bernilai negatif di dalam lempengan tersebut, sehingga probe menyentuhnya dan kamera bertahan tepat di bawah atap gua.</figcaption>
</figure>
<p>Menjalankan probe di sepanjang field merupakan teknik yang memiliki nama dan makalah yang mendasarinya. <em>Sphere Tracing</em> karya John Hart dari tahun 1996 adalah cara standar untuk melakukan marching ray terhadap distance field, dan triknya adalah bahwa field tersebut tidak hanya memberi tahu apakah Anda telah menabrak sesuatu, tetapi juga memberi tahu jarak aman yang dapat ditempuh tanpa menabrak apa pun. Jadi, alih-alih bergerak perlahan dalam langkah-langkah kecil yang tetap, Anda mengambil sampel field, melangkah maju sejauh ruang aman yang dilaporkannya, lalu mengulanginya, dengan langkah panjang melalui udara terbuka dan langkah pendek yang hati-hati saat mendekati permukaan.
Namun, ada satu kendala yang dipaksakan oleh medan kita. Medan jarak sejati melaporkan jarak Euklides sebenarnya ke permukaan terdekat, dan melangkah sejauh seluruh ruang bebas tersebut selalu aman. Namun, di wilayah tempat medan masih berupa heightmap alih-alih voxel yang dipahat, medan yang dapat kita sampel dengan murah bukanlah jarak sejati, melainkan jarak bebas vertikal, yaitu celah lurus ke bawah menuju tanah. Pada lereng, angka tersebut melaporkan jarak gerak kamera secara berlebihan karena batu terdekat berada di samping, bukan tepat di bawah. Jarak sebenarnya lebih kecil dengan faktor yang bertambah seiring gradien, $\sqrt{1 + \lVert\nabla h\rVert^2}$, sehingga langkah yang ukurannya mengikuti ruang bebas yang dilaporkan akan melampaui batas dan dapat melompati punggung bukit sepenuhnya. Solusinya adalah relaksasi-bawah, yaitu bergerak maju hanya sebesar sebagian dari ruang bebas yang dilaporkan, bukan seluruhnya. Cara ini tetap aman hingga kemiringan sekitar enam puluh derajat dan tidak menambah biaya apa pun di wilayah voxel berjarak sejati selain beberapa sampel tambahan. Kita memadukannya dengan batas bawah langkah agar dinding gua setebal satu atau dua sel tidak pernah terlewati sepenuhnya, serta batas atas yang lebih ketat agar proses marching tetap murah. Ketika bola akhirnya menyentuh permukaan, proses biseksi singkat memperketat titik kontak, lalu kamera mundur sejauh radiusnya sendiri dan berhenti di sana.</p>
<p>Jika dituliskan, boom tersebut adalah sinar $\mathbf{r}(t) = \mathbf{p} + t,\mathbf{d}$ dari pivot $\mathbf{p}$ sepanjang arah satuan $\mathbf{d}$, dan proses marching bergerak maju sebesar bagian yang direlaksasi-bawah dari ruang bebas medan hingga kontak, dengan penjepitan di kedua ujung:</p>
<p>$$
t_{n+1} = t_n + \operatorname{clamp}!\big(\lambda,(\Phi(\mathbf{r}(t_n)) - r),; s_{\min},; s_{\max}\big)
$$</p>
<p>Di sini, $\Phi$ adalah jarak bertanda, positif di udara dan negatif di dalam batu, $r$ adalah radius probe, $\lambda \in (0, 1]$ adalah faktor relaksasi-bawah yang mencegah medan heightmap dengan pelaporan berlebih melompati lereng, dan $s_{\min}, s_{\max}$ adalah batas langkah yang mencegah dinding tipis terlewati serta proses marching berlangsung terlalu lama. Kontak adalah $t$ pertama ketika $\Phi(\mathbf{r}(t)) \le r$, yang berarti permukaan bola telah mencapai batu, dan kamera bertahan pada panjang busur tersebut dikurangi radiusnya.</p>
<p>Collider memiliki satu metode tambahan sebagai jaring pengaman, yaitu depenetrasi. Collision seharusnya sejak awal mencegah kamera masuk ke benda padat, tetapi beberapa situasi masih dapat lolos: pivot yang mengangkangi dinding sangat tipis sehingga boom dimulai di dalamnya, gua yang baru saja dipahat oleh alat medan ketika kamera berada di dalam batu yang kini telah hilang, atau bagian bangunan yang ditempatkan mengelilingi kamera. Untuk situasi tersebut, collider memeriksa apakah kamera mengakhiri frame di dalam benda padat, yaitu ketika $\Phi(\mathbf{c}) &lt; r$. Jika ya, collider membaca gradien medan, yang mengarah lurus menuju udara terbuka karena $\Phi$ membesar ketika Anda meninggalkan batu, lalu mendorong kamera keluar sepanjang arah tersebut:</p>
<p>$$
\mathbf{c} \leftarrow \mathbf{c} + \big(r - \Phi(\mathbf{c})\big),\frac{\nabla \Phi(\mathbf{c})}{\lVert \nabla \Phi(\mathbf{c}) \rVert}
$$</p>
<p>Beberapa iterasi saja akan konvergen ke isopermukaan $r$, dan mekanisme inilah yang memungkinkan alat pemahat menggali tanah dari bawah kamera lalu memulihkan tampilan pada frame berikutnya alih-alih membuat layar menjadi hitam.</p>
<h2>Menyentak masuk, melonggar keluar, dan tidak tersentak oleh tiang pagar</h2>
<p>Boom yang sekadar melompat ke jarak collision setiap frame justru lebih buruk daripada tidak memakai boom sama sekali, karena dunia dipenuhi benda tipis yang dilewati kamera dari belakang hanya selama satu frame: tiang pagar, lampu, batang pohon. Kamera yang menerjang untuk menghindari setiap benda lalu menerjang kembali akan membuat mual. Buku Haigh-Hutchinson dan presentasi Itay Keren yang sangat disukai tentang gerakan kamera sama-sama sampai pada intuisi yang sama: kamera harus bereaksi terhadap ancaman dan bahaya lebih cepat daripada saat kembali rileks setelah ancaman berlalu. Karena itu, damping sengaja dibuat asimetris. Saat occluder muncul dan boom perlu memendek, boom menyentak masuk hampir seketika karena clipping selama satu frame terlihat buruk dan pemain akan memaklumi gerakan masuk yang cepat. Saat occluder menghilang dan boom ingin memanjang, boom melonggar keluar secara perlahan, dan hanya setelah timer jeda singkat dengan ruang bebas terus-menerus telah berlalu. Jeda tersebut adalah histeresis yang menghilangkan sentakan. Putar kamera dengan cepat melewati tiang tipis dan tiang itu tidak pernah menghilang cukup lama untuk memicu pemanjangan lambat, sehingga kamera meluncur melewatinya seolah-olah tiang itu tidak ada, tepat seperti yang diinginkan mata Anda. Cinemachine menggunakan gagasan yang sama sebagai nilai damping terpisah untuk memasuki dan keluar dari collision, dan asimetri inilah yang membuatnya terasa seperti operator kamera alih-alih pegas.</p>
<p>Dalam kode, mekanismenya hanya satu baris exponential smoothing dengan laju yang diganti berdasarkan tanda perubahan. Jika $\ell$ adalah panjang boom saat ini, $a$ adalah panjang yang diizinkan collision pada frame ini, dan $\Delta t$ adalah waktu frame, maka</p>
<p>$$
\ell \leftarrow \ell + (a - \ell)\big(1 - e^{-k,\Delta t}\big), \qquad
k = \begin{cases}
k_{\text{in}}  &amp; a \le \ell \[2pt]
k_{\text{out}} &amp; a &gt; \ell
\end{cases}, \quad k_{\text{in}} \gg k_{\text{out}}
$$</p>
<p>dan cabang pelonggaran keluar hanya berjalan setelah ruang bebas bertahan selama waktu jeda $\tau$. Bentuk $1 - e^{-k,\Delta t}$ penting bukan hanya karena terlihat rapi. Bentuk ini menetapkan konstanta waktu respons pada $1/k$ tanpa bergantung pada frame rate, sehingga kamera terasa sama pada 30 maupun 144 frame per detik. Sebaliknya, blend konstan naif $\ell \leftarrow \ell + \alpha(a - \ell)$ akan menyentak lebih cepat pada mesin cepat dan terasa lembek pada mesin lambat.</p>
<p>Perilaku terakhir ditujukan untuk interior sempit yang mengawali seluruh bagian ini. Ketika boom memendek sedemikian rupa sehingga kamera berada tepat di atas pemain, kita menyembunyikan avatar pemain sendiri dan membiarkan tampilan berada dekat dengan sudut pandang orang pertama. Inilah yang dilakukan Breath of the Wild di shrine sempit dan yang menjadi pilihan cadangan sebagian besar game orang ketiga ketika berada di sudut, karena alternatifnya, kamera yang terjepit ke dinding sambil menatap belakang kepala, tidak berguna. Rig menyediakan satu flag untuk hal ini, lalu loop dunia membaca flag tersebut dan mengubah visibilitas avatar lokal. Ketika boom lebih pendek dari satu meter, Anda pada dasarnya berada dalam sudut pandang orang pertama, dinding tetap dipatuhi, dan begitu Anda mundur ke ruangan yang lebih lapang, avatar perlahan muncul kembali dan boom memanjang.</p>
<h2>Yang akan dipasang berikutnya</h2>
<p>Collider medan dirilis hari ini dan merupakan separuh yang sulit, karena medan ada di mana-mana dan distance field merupakan hal yang merepotkan untuk diperiksa. Prop dan selubung bangunan dari eksperimen authoring adalah separuh yang mudah, dan kontraknya sudah siap menunggu. Collider kedua, yaitu raycast collider, memancarkan sinar dari pivot menuju kamera terhadap daftar mesh dan melaporkan hit terdekat dengan cara yang sama seperti collider medan. Versi murah memancarkan satu sinar, yang memadai hingga jumlah prop meningkat, sedangkan peningkatannya adalah mengganti sinar tersebut dengan bola yang disapu menggunakan three-mesh-bvh, pustaka Garrett Johnson yang membungkus mesh dalam hierarki volume pembatas agar kueri spasial berjalan dalam waktu logaritmik alih-alih melalui brute force. Apa pun pilihannya, rig tidak berubah. Rig mengueri daftar collider yang lebih panjang dan mengambil hit terdekat, yang memang merupakan tujuan utama membangun kontrak terlebih dahulu dan collider setelahnya.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Boom yang hanya memiliki satu angka.</strong> Rig kamera adalah post-process di atas OrbitControls, bukan penggantinya. Rig hanya memiliki panjang boom dan menyerahkan yaw, pitch, zoom, serta penanganan gestur kepada orbit controller yang sudah kita percayai. Integrasinya terdiri dari dua pemanggilan yang mengapit proses: <code>beforeControls()</code> memulihkan jarak penuh frame sebelumnya agar matematika orbit membaca zoom sebenarnya dari pengguna, bukannya salah mengira pemendekan akibat collision sebagai dolly-in, lalu <code>afterControls(dt)</code> menyelesaikan collision dan menulis posisi yang dirender. Tanpa pasangan tersebut, kamera akan runtuh mendekati pemain dalam beberapa frame.</p>
<p><strong>Kontrak collider yang dapat dipasang-lepas.</strong> Collider adalah objek apa pun dengan <code>probe</code> yang menjawab, &quot;seberapa jauh kamera dapat bergerak dari pivot sepanjang sinar ini sebelum Anda menghalanginya.&quot; Rig mengueri setiap collider dan mengambil hit terdekat tanpa perlu mengetahui apakah rintangannya adalah medan, prop, atau dinding. Ini adalah disiplin hanya-memiliki-satu-hal yang sama seperti yang digunakan <a href="/id/blog/2026-05-15-open-world-browser-part-29-pluggable-character">controller karakter yang dapat dipasang-lepas</a> untuk pergerakan. Probe tersebut berupa bola yang disapu dengan ukuran yang mencakup near plane, bukan sinar tipis, sehingga sudut-sudut frustum tidak pernah menembus permukaan yang luput dari sinar tengah. Radiusnya diturunkan dari proyeksi, yaitu jarak ke sudut near plane $\sqrt{n^2 + w^2 + h^2}$ dikalikan margin keamanan, dan dihitung ulang setiap kali field of view, aspect, atau near plane berubah.</p>
<p><strong>Probe medan jarak bertanda yang mematuhi overhang dan gua.</strong> Karena medan merupakan <a href="/id/blog/2026-02-25-open-world-browser-part-07-marching-cubes">signed distance field</a>, bukan heightmap, probe yang menghentikan kamera di lereng bukit juga menghentikannya di langit-langit gua, kasus yang secara struktural tidak dapat dilihat oleh raycast heightmap. Proses marching menggunakan sphere tracing ala Hart, melangkah sebesar bagian yang direlaksasi-bawah dari ruang bebas yang dilaporkan medan dan dijepit di kedua ujung. Ini diperlukan karena wilayah heightmap melaporkan jarak bebas vertikal alih-alih jarak sejati dan melebih-lebihkan seberapa jauh kamera dapat bergerak di lereng, sehingga langkah penuh akan melompati punggung bukit. Pass depenetrasi yang digerakkan gradien menjadi jaring pengaman yang memulihkan tampilan ketika tanah dipahat dari bawah kamera.</p>
<p><strong>Damping asimetris dengan timer jeda.</strong> Boom menyentak masuk dengan cepat saat occluder muncul dan melonggar keluar secara perlahan setelah occluder hilang, serta hanya setelah ruang bebas terus tersedia selama jendela waktu singkat. Dengan begitu, gerakan cepat melewati tiang pagar tidak pernah membuat kamera menerjang. Di bawah ambang keruntuhan, rig menandai kondisi mendekati sudut pandang orang pertama dan loop dunia menyembunyikan avatar lokal, solusi cadangan standar untuk interior sempit alih-alih membiarkan kamera terkubur di dalam dinding.</p>
<h2>Referensi</h2>
<p>Perumusan kontrol kamera sebagai batasan visibilitas berasal dari Marc Christie dan Patrick Olivier, <a href="https://people.irisa.fr/Marc.Christie/Publications/2008/CON08.html"><em>Kontrol Kamera dalam Grafika Komputer</em></a> (Computer Graphics Forum, 2008). Proses marching distance field berasal dari John C. Hart, <a href="https://graphics.stanford.edu/courses/cs348b-20-spring-content/uploads/hart.pdf"><em>Sphere Tracing: Metode Geometris untuk Ray Tracing Berantialias pada Permukaan Implisit</em></a> (The Visual Computer, 1996). Pola spring-arm dan collision bola probe-nya didokumentasikan dalam <a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/using-spring-arm-components-in-unreal-engine">Komponen Spring Arm</a> dari Epic serta <a href="https://docs.unity3d.com/Packages/com.unity.cinemachine@3.1/manual/CinemachineDeoccluder.html">Cinemachine Deoccluder</a> dan <a href="https://docs.unity3d.com/Packages/com.unity.cinemachine@3.1/manual/CinemachineThirdPersonFollow.html">Third Person Follow</a> dari Unity. Intuisi gerakan dan damping berasal dari Mark Haigh-Hutchinson, <em>Kamera Waktu Nyata</em> (Morgan Kaufmann, 2009), dan Itay Keren, <a href="https://www.gamedeveloper.com/design/scroll-back-the-theory-and-practice-of-cameras-in-side-scrollers"><em>Gulir Kembali: Teori dan Praktik Kamera dalam Game Side-Scroller</em></a> (GDC 2015). Jalur peningkatan mesh collider menggunakan <a href="https://github.com/gkjohnson/three-mesh-bvh">three-mesh-bvh</a> karya Garrett Johnson.</p>
<hr>
<p>Bagian 30 dari 30.
Sebelumnya: <a href="/id/blog/2026-05-15-open-world-browser-part-29-pluggable-character">Bagian 29 - Satu controller, tubuh apa pun</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Jangan render rumput di balik bukit: occlusion culling yang memahami medan]]></title>
            <link>https://app.cinevva.com/id/blog/2026-05-19-terrain-occlusion-culling</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-05-19-terrain-occlusion-culling</guid>
            <pubDate>Tue, 19 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Delapan teknik occlusion culling yang dinilai untuk dunia terbuka di browser, teknik yang menang karena medan kami berupa heightmap, dan spike interaktif yang memungkinkan Anda membandingkannya secara A/B dalam scene Anda sendiri.]]></description>
            <content:encoded><![CDATA[<h1>Jangan render rumput di balik bukit: occlusion culling yang memahami medan</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p><a href="/id/blog/2026-05-14-open-world-browser-part-28-grass-and-occlusion">Bagian 28</a> memperkenalkan Spike 57 dan menguji performa empat jalur culling-nya dalam beberapa paragraf. Ini versi panjangnya: mengapa kami memilih keempat jalur tersebut, apa saja empat teknik lainnya, dan alasan di balik teknik yang akan kami rilis.</p>
<p>Ada sebuah bukit di antara kamera dan padang rumput. Anda tidak perlu merender padang rumput itu. Semua engine AAA modern memahami hal ini. Sebagian besar engine 3D berbasis browser tidak, termasuk engine kami sampai minggu lalu.</p>
<p>Tulisan ini adalah hasil dari riset yang dilakukan dengan benar, disesuaikan dengan codebase kami yang sebenarnya, diwujudkan sebagai spike yang berfungsi, serta penilaian berbagai teknik berdasarkan seberapa besar manfaatnya <em>secara khusus bagi kami</em>, mengingat saat ini kami merilis untuk WebGL dan besok untuk WebGPU.</p>
<p>Anda dapat mencoba spike interaktif di bawah ini sebelum melanjutkan membaca. <kbd>T</kbd>/<kbd>Y</kbd>/<kbd>U</kbd>/<kbd>I</kbd> beralih di antara jalur culling, <kbd>C</kbd> menggilir preset kamera, dan <kbd>B</kbd> mewarnai chunk yang disembunyikan dengan wireframe merah agar Anda dapat melihat apa saja yang dihapus oleh pengujian tersebut. HUD melaporkan berapa banyak instance yang ditolak oleh setiap tahap.</p>
<div style="position:relative;padding-bottom:62%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.08)">
<iframe src="/id/spikes/57-terrain-occlusion/" title="Spike 57: Occlusion culling medan" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#1a1f2a" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/57-terrain-occlusion/" target="_blank">Buka Spike 57 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=57-terrain-occlusion">Lihat kode sumber</a></p>
<h2>Apa yang dilakukan engine kami saat ini (dan yang tidak dilakukannya)</h2>
<p>Pengelola streaming chunk kami memuat lingkaran chunk berukuran 64 m di sekitar pemain pada tiga tingkat LOD. Setiap chunk memiliki pohon-pohon instanced yang disebarkan di atas heightmap. Logika culling-nya, yang berada di <code>Chunk.updateObjectVisibility</code>, hanya berupa pemeriksaan jarak: pohon dalam radius 60 m dirender sebagai mesh penuh, pohon antara 60 m dan 140 m dirender sebagai billboard, dan di luar itu tidak dirender sama sekali.</p>
<p>Culling tersebut melewatkan dua kategori pemborosan yang sangat besar:</p>
<ol>
<li>Apa pun yang berada di dalam lingkaran 60 m <em>tetapi di belakang kamera</em>. Kami mengurutkan ulang buffer instance setiap kali pemain bergerak lebih dari 4 m, tetapi kami tidak menguji view frustum, sehingga rata-rata separuh lingkaran dikirim ke GPU hanya untuk di-clip setelah transformasi vertex.</li>
<li>Apa pun yang berada di dalam lingkaran 60 m <em>tetapi di balik bukit</em>. Medan kami memiliki rentang vertikal 80 m dan banyak lembah. Saat kamera berada di lembah, sebagian besar vegetasi di dalam radius culling tersembunyi secara geometris oleh punggung bukit terdekat. Kami tetap menggambarnya.</li>
</ol>
<p>Kategori kedua menjadi fokus tulisan ini. Ini juga kategori yang diatasi oleh engine AAA dengan serangkaian trik cerdas yang, sekilas, tidak mudah diterapkan di browser.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0">
<iframe src="https://www.youtube.com/embed/wavnKZNSYqU" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0" allow="accelerometer;autoplay;clipboard-write;encrypted-media;gyroscope;picture-in-picture" allowfullscreen></iframe>
</div>
<p><em>Gilbert Sanders dari Guerrilla menjelaskan cara Horizon Zero Dawn merender vegetasi dunia terbuka. Pembahasan rangkaian culling ada di 20 menit terakhir dan merupakan pelajaran luar biasa tentang mengapa &quot;menggambar lebih sedikit&quot; mengalahkan &quot;menggambar lebih cepat&quot;.</em></p>
<h2>Delapan teknik, dinilai untuk kasus kami</h2>
<p>Saya mempelajari rangkaian occlusion culling modern dan menilai setiap bagiannya berdasarkan seberapa besar manfaatnya bagi dunia terbuka prosedural berbasis heightmap yang berjalan di browser. Ada dua sumbu: nilai (seberapa banyak pemborosan yang dihilangkan dalam scene kami) dan biaya (upaya engineering, ditambah seberapa banyak bagian stack kami yang harus diubah). Alasan lengkapnya ada di berkas riset yang mendasari tulisan ini; berikut versi singkatnya.</p>
<p><strong>1. Frustum culling per instance. Nilai tinggi, biaya rendah.</strong> Saat ini kami sama sekali tidak menguji frustum untuk vegetasi instanced. Menambahkannya memangkas kira-kira separuh pekerjaan pada tampilan apa pun, hanya membutuhkan sekitar tiga puluh baris kode, dan dapat dirilis di WebGL sekarang. Ini adalah peningkatan murah terbesar dan seharusnya sudah kami lakukan berbulan-bulan lalu.</p>
<p><strong>2. Raycast horizon heightmap. Nilai tinggi, biaya rendah–menengah.</strong> Lakukan ray marching dari kamera melalui setiap instance kandidat, sambil mengambil sampel ketinggian medan sepanjang jalurnya. Jika medan pernah naik melampaui ray, instance tersebut terhalang. Teknik ini bekerja secara presisi karena dunia kami merupakan heightmap, yang menyederhanakan visibilitas menjadi persoalan 1D di sepanjang arah horizontal. Versi padatnya memiliki kompleksitas O(langkah) per instance per frame. Versi yang dipercepat (poin berikutnya) menurunkannya menjadi O(log langkah).</p>
<p><strong>3. Akselerasi piramida ketinggian maksimum. Nilai tinggi, biaya menengah.</strong> Mipmap 2D dari heightmap, dengan setiap texel menyimpan ketinggian medan maksimum di dalam area cakupannya. Ini memungkinkan raycast horizon melompat dengan langkah-langkah besar saat area sekitarnya datar dan hanya memperhalus pengujian di atas bukit. Struktur inilah yang membuat teknik nomor 2 cukup murah untuk produksi.</p>
<p><strong>4. Occlusion Hierarchical-Z (Hi-Z / HZB). Nilai tinggi, biaya tinggi.</strong> Bangun mipmap depth buffer, proyeksikan bounds setiap instance ke screen space, lalu uji terhadap tingkat mip yang tepat. Ini adalah standar modern di sisi GPU, digunakan oleh Nanite milik Unreal, virtual geometry milik Bevy, dan port WebGPU VTK. Teknik ini bekerja untuk semuanya, bukan hanya medan, tetapi memerlukan WebGPU, indirect draw, dan compute pass. Investasinya baru sepadan saat kami merender jutaan helai rumput, bukan ribuan pohon.</p>
<p><strong>5. Hi-Z dua pass (gaya Nanite). Manfaat tambahan kecil dibandingkan nomor 4, biaya tinggi.</strong> Render ulang depth frame ini setelah pass 1 untuk menghindari artefak disocclusion satu frame. Hanya layak setelah jalur berbasis GPU kami cukup matang sehingga biayanya bersifat inkremental.</p>
<p><strong>6. Rasterizer occlusion perangkat lunak (Frostbite/Intel MOC). Nilai menengah, biaya tinggi.</strong> Rasterisasi depth buffer beresolusi rendah dari occluder besar di CPU. Tanpa latensi readback. Implementasi referensinya berupa C++ AVX/SSE; mem-porting-nya ke WASM merupakan proyek tersendiri, sementara raycast heightmap kami memperoleh sebagian besar manfaat yang sama dengan upaya yang jauh lebih kecil.</p>
<p><strong>7. PVS yang diprakomputasi. Nilai rendah, biaya tinggi.</strong> Sangat bagus untuk peta statis era Quake. Medan kami prosedural dan tak terbatas, sehingga semua prapemrosesan harus dilakukan saat streaming chunk, yang biayanya kurang lebih sama dengan menghitung visibilitas saat runtime. Lewati.</p>
<p><strong>8. Horizon culling gaya Cesium. Tidak bernilai bagi kami, biaya menengah.</strong> Dirancang untuk elipsoid planet. Dunia kami relatif datar dan berbatas; perhitungannya tidak berlaku dan hanya akan menjadi no-op atau salah melakukan culling. Lewati.</p>
<p>Jadi: lakukan nomor 1 serta nomor 2+3 sekarang, di CPU, dalam WebGL. Rencanakan nomor 4 untuk migrasi WebGPU. Lewati sisanya.</p>
<h2>Mengapa raycast heightmap unggul untuk medan di browser</h2>
<p>Saran standar dalam presentasi rendering modern mana pun adalah &quot;bangun buffer Hi-Z&quot;. <a href="https://www.youtube.com/watch?v=eviSykqSUUw">Pembahasan mendalam Nanite di SIGGRAPH 2021</a> oleh Brian Karis adalah rujukan utamanya dan patut Anda tonton setidaknya sekali.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0">
<iframe src="https://www.youtube.com/embed/eviSykqSUUw" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0" allow="accelerometer;autoplay;clipboard-write;encrypted-media;gyroscope;picture-in-picture" allowfullscreen></iframe>
</div>
<p>Itu jawaban yang tepat untuk engine yang sudah menjalankan semuanya melalui indirect draw berbasis GPU. Sebagian besar engine browser, termasuk engine kami, belum seperti itu. Kami memiliki buffer instance di sisi CPU, draw call WebGL, dan tidak memiliki tahap compute. Menambahkan Hi-Z ke stack tersebut berarti sekaligus mem-porting ke WebGPU, menulis ulang pipeline vegetasi menjadi indirect draw, serta menambahkan pass untuk membangun depth pyramid. Itu berarti kerja selama seperempat tahun hanya untuk menghasilkan frame pertama yang membuktikan gagasannya.</p>
<p>Raycast heightmap berjalan di CPU, dalam WebGL, menggunakan data yang sudah kami miliki. Teknik ini memanfaatkan satu fakta tentang dunia kami yang tidak dapat dimanfaatkan engine AAA: <strong>occluder kami dideskripsikan oleh fungsi ketinggian 1D</strong>. Mengambil sampel fungsi tersebut di sepanjang ray hanya memerlukan dua lookup array dan satu perkalian. Buffer Hi-Z harus menemukan fakta yang sama piksel demi piksel.</p>
<p>Teknik ini pertama kali diterbitkan dengan judul &quot;Horizon Occlusion Culling for Hierarchical Terrains&quot; di IEEE Visualization 2002 (<a href="https://saksagan.ceng.metu.edu.tr/courses/ceng591/RAPORLAR/HacerYalim.pdf">PDF</a>). Teknik ini tetap digunakan selama dua dekade karena memiliki karakteristik yang tepat: murah saat medan datar, mahal hanya ketika benar-benar ada bukit, dan sangat mudah diparalelkan.</p>
<h2>Piramida ketinggian maksimum, dalam gambar</h2>
<p>Raycast naif mengambil sampel <code>terrainHeight</code> pada sekitar 24 titik di sepanjang setiap ray dan berhenti lebih awal jika medan memotongnya. Itu cukup baik untuk ribuan pohon. Namun, performanya runtuh saat menangani ratusan ribu helai rumput.</p>
<p>Solusinya adalah mipmap heightmap dengan setiap texel menyimpan ketinggian <strong>maksimum</strong> di dalam area cakupannya:</p>
<pre><code>level 0 (256×256, 2,25 m per texel):  h maks dari 4×4 sampel dengan jitter
level 1 (128×128, 4,5 m  per texel):  maks(0,0), maks(1,0), maks(0,1), maks(1,1)
level 2 ( 64×64,  9,0 m per texel):  reduksi yang sama satu level ke atas
...
level 8 (   1×1,  576 m per texel):  maksimum global
</code></pre>
<p>Saat segmen ray panjang dan datar, ambil sampel dari level kasar: satu lookup memberi tahu Anda bahwa &quot;tidak ada medan dalam persegi 9 m ini yang pernah melebihi elevasi 12 m, sedangkan ray berada pada ketinggian 30 m di sana, jadi lanjutkan.&quot; Hanya ketika texel kasar mengatakan &quot;medan <em>mungkin</em> berada di atas ray&quot;, Anda turun satu level dan memperhalus pengujian. Seluruh struktur hanya berukuran beberapa ratus KB dan dapat dibangun dalam puluhan milidetik.</p>
<p>Dalam bentuk diagram:</p>
<pre><code>                                            ray dari mata
        mata 1,7 m                        o─────────────────────►
              o─────────────────────────·─·─·─·─·─·──────────────
              │                          \                       │
              │   level 3 (langkah besar) \   level 0 (perhalus) │
              │   &quot;tak ada medan &gt; 8 m&quot;    \   &quot;bukit 9 m!&quot;      │
              │                              \                   │
        ──────┴────────────/▔▔▔\─────────────/▔▔▔▔▔\─────────────
                                 bukit A (8 m) bukit B (12 m)
                                                ↑
                                           terhalang di sini
</code></pre>
<p>Untuk segmen ray yang melewati sekitar bukit A, lookup level 3 (&quot;ketinggian maksimum dalam kotak selebar 18 m ini adalah 8 m&quot;) sudah memberi tahu kita bahwa ray pada elevasi 1,7 m ditambah beberapa meter pendakian tidak terhalang. Kita melewati 36 m ray marching hanya dengan satu kueri. Di atas bukit B, level 3 mengatakan &quot;maksimum di sini adalah 12 m&quot;, kita turun ke level berikutnya, lalu level 0 mengatakan &quot;ya, 12 m tepat di texel ini&quot;, dan kita menolak instance tersebut.</p>
<p>Pembangunan piramida berada di <code>height-pyramid.mjs</code>, sedangkan jalur culling yang menggunakannya berada di <code>cull.mjs</code>. Keduanya dapat dibaca di <a href="/id/blog/spike-source?spike=57-terrain-occlusion">penjelajah kode sumber spike</a>.</p>
<h2>Apa yang sebenarnya ditunjukkan spike ini</h2>
<p>Buka Spike 57 di atas dan coba keempat jalurnya:</p>
<ul>
<li><strong>T0</strong> adalah yang dilakukan produksi saat ini. Hanya jarak. Dari C1 (dasar lembah), HUD melaporkan sekitar 12.000 helai rumput terlihat.</li>
<li><strong>T1</strong> menambahkan frustum culling per instance. Jumlah yang terlihat berkurang kira-kira separuh karena apa pun yang berada di belakang kamera atau di luar sisi tampilan dibuang sebelum mencapai GPU.</li>
<li><strong>T2</strong> menambahkan raycast heightmap brute-force. Di C1, jumlahnya turun lagi sebesar 60–80%, karena sebagian besar lapangan berada di balik punggung bukit terdekat. Kolom Cull-ms naik karena kami mengambil sampel <code>terrainHeight</code> sekitar 24 kali per instance.</li>
<li><strong>T3</strong> mengganti brute force dengan piramida ketinggian maksimum. Cull-ms kembali mendekati T1 sambil mempertahankan pengurangan jumlah objek terlihat. Inilah jalur yang benar-benar layak Anda rilis.</li>
</ul>
<p>Polanya sesuai dengan yang ditemukan engine produksi. Seri dua bagian Acerola tentang rendering rumput (<a href="https://www.youtube.com/watch?v=Y0Ko0kvwfgA">Bagaimana Game Merender Begitu Banyak Rumput?</a>, <a href="https://www.youtube.com/watch?v=PNvlqsXdQic">Apa yang Saya Lakukan untuk Mengoptimalkan Rumput dalam Game Saya</a>) adalah penjelasan YouTube yang paling mudah dipahami tentang mengapa upaya engineering sebaiknya dicurahkan pada tahap culling, bukan tahap shading.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0">
<iframe src="https://www.youtube.com/embed/Y0Ko0kvwfgA" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0" allow="accelerometer;autoplay;clipboard-write;encrypted-media;gyroscope;picture-in-picture" allowfullscreen></iframe>
</div>
<h2>Kamera C3 dan kasus kegagalan &quot;puncak bukit&quot;</h2>
<p>Preset kamera ketiga pada spike menempatkan kamera di puncak bukit, menghadap ke seluruh area permainan. Dalam kasus ini, horizon culling hampir tidak melakukan apa-apa karena tidak ada medan di antara kamera dan sebagian besar dunia. HUD menunjukkan T2/T3 hanya mengurangi jumlah objek terlihat sekitar 5–10% dibandingkan T1.</p>
<p>Itu adalah fitur, bukan bug. Teknik ini berhenti bekerja tepat ketika seharusnya: saat tidak ada apa pun yang menghalangi. Frustum culling masih melakukan pekerjaan nyata, distance culling masih membatasi anggaran, dan pengujian horizon dengan mulus berubah menjadi no-op. Jika Anda mengimplementasikannya, Anda harus memastikan bahwa kasus no-op juga murah. Inilah alasan piramida ketinggian maksimum tetap penting meskipun tidak ada ray yang akan ditolak: level paling kasar sering kali sudah cukup untuk mengonfirmasi bahwa &quot;tidak ada yang terhalang&quot;.</p>
<h2>Apa yang akan kami rilis berikutnya</h2>
<p>Ada tiga hal yang perlu dilakukan, secara berurutan.</p>
<p>Pertama, porting T1 dan T3 ke <code>Chunk.updateObjectVisibility</code> di produksi. Piramida sebaiknya ditempatkan satu tingkat lebih tinggi, pada pengelola chunk, karena cakupannya melintasi lebih dari satu chunk. Proses culling tetap berada di <code>Chunk</code> agar batching per chunk yang ada terus berfungsi. Perkiraan upaya: satu hari, termasuk pengujian.
Kedua, lakukan hal yang sama untuk rumput setelah kita memilikinya. Eksperimen saat ini menyebarkan 12.000 helai rumput di area permainan seluas 576 m; kepadatan produksi seharusnya kira-kira sepuluh kali lebih tinggi. Jalur culling CPU menangani 12.000 helai dalam waktu kurang dari satu milidetik, dan akselerasi piramida membuat hal itu tetap berlaku pada 120.000 helai.</p>
<p>Ketiga, saat kita bermigrasi ke <code>THREE.WebGPURenderer</code>, porting loop yang sama ke compute shader. Metadata menjadi storage buffer. Proses culling menulis argumen <code>drawIndirect</code>. Piramida diunggah sebagai tekstur 2D dengan max-reduction yang sudah diproses sebelumnya. Bentuk kodenya tetap nyaris identik, dan memang itulah intinya: kita tidak mempertaruhkan migrasi pada algoritma baru, tetapi memindahkan algoritma yang sudah kita miliki ke landasan yang lebih cepat.</p>
<p>Guerrilla membahas versi GPU dari pendekatan ini untuk sistem penempatan prosedural Horizon Zero Dawn; pipeline rendering tidak sepenting struktur datanya, dan struktur mereka memiliki bentuk yang sama:</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0">
<iframe src="https://www.youtube.com/embed/ToCozpl1sYY" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0" allow="accelerometer;autoplay;clipboard-write;encrypted-media;gyroscope;picture-in-picture" allowfullscreen></iframe>
</div>
<p>Hi-Z tetap akan berguna setelah kita merilis bangunan dan prop padat yang menutupi objek dari arah yang tidak dapat digambarkan oleh heightmap. Namun, piramida heightmap tetap berada dalam pipeline karena jauh lebih murah daripada Hi-Z untuk instance yang dekat dengan permukaan tanah, sedangkan rumput yang melintasi siluet punggung bukit adalah kasus yang paling sulit ditangani Hi-Z.</p>
<h2>Referensi</h2>
<p>Alasan lengkap yang telah diprioritaskan dan keputusan arsitekturnya ada di atas; berikut adalah sumber utama untuk setiap teknik, kurang lebih sesuai urutan kemunculannya dalam stack.</p>
<ul>
<li>Yalim &amp; Akman, <a href="https://saksagan.ceng.metu.edu.tr/courses/ceng591/RAPORLAR/HacerYalim.pdf">Culling Oklusi Horizon untuk Medan Hierarkis</a> (IEEE Visualization 2002, makalah awal tentang culling horizon medan).</li>
<li>Turitzin, <a href="https://miketuritzin.com/post/hierarchical-depth-buffers/">Buffer Kedalaman Hierarkis</a> (penjelasan paling jelas tentang cara membangun dan melakukan kueri pada rantai mip Hi-Z).</li>
<li>VKGuide, <a href="https://vkguide.dev/docs/gpudriven/compute_culling/">Culling Berbasis Compute</a> (referensi pipeline culling berbasis GPU; porting ke WebGPU bersifat mekanis).</li>
<li>Kruskonja, <a href="https://medium.com/@mil_kru/two-pass-occlusion-culling-4100edcad501">Culling Oklusi Dua Tahap</a> (arsitektur bergaya Nanite yang dijelaskan di luar slide Epic).</li>
<li>Karis dkk., <a href="https://www.youtube.com/watch?v=eviSykqSUUw">Nanite — Pembahasan Mendalam (SIGGRAPH 2021)</a> (referensi modern tentang bentuk culling berbasis GPU pada skala AAA).</li>
<li>Karis, <a href="https://www.youtube.com/watch?v=NRnj_lnpORU">Keynote HPG 2022: Perjalanan Menuju Nanite</a> (konteks yang lebih luas tentang alasan tahap culling penting).</li>
<li>Sanders, <a href="https://www.youtube.com/watch?v=wavnKZNSYqU">Antara Teknologi dan Seni: Vegetasi Horizon Zero Dawn</a> (stack culling vegetasi AAA secara menyeluruh).</li>
<li>Guerrilla, <a href="https://www.youtube.com/watch?v=ToCozpl1sYY">Penempatan Prosedural Saat Runtime Berbasis GPU di Horizon Zero Dawn</a> (penempatan berbasis instance dan visibilitas per instance).</li>
<li>Scthe, <a href="https://github.com/Scthe/nanite-webgpu">Nanite WebGPU</a> (implementasi referensi WebGPU, lengkap dengan HZB).</li>
<li>Kitware, <a href="https://www.kitware.com/webgpu-occlusion-culling-in-vtk/">Culling Oklusi WebGPU di VTK</a> (HZB produksi pertama di sisi browser yang saya ketahui).</li>
<li>Acerola, <a href="https://www.youtube.com/watch?v=Y0Ko0kvwfgA">Bagaimana Gim Merender Begitu Banyak Rumput?</a> dan <a href="https://www.youtube.com/watch?v=PNvlqsXdQic">Yang Saya Lakukan untuk Mengoptimalkan Rumput di Gim Saya</a> (tur YouTube yang mudah dipahami).</li>
<li>RasterGrid, <a href="https://www.rastergrid.com/blog/2010/10/hierarchical-z-map-based-occlusion-culling/">Culling Oklusi Berbasis Peta Hi-Z</a> (pengantar Hi-Z yang masih menjadi rujukan utama).</li>
<li>Intel, <a href="https://www.intel.com/content/www/us/en/developer/articles/technical/masked-software-occlusion-culling.html">Culling Oklusi Perangkat Lunak Bermask</a> (keluarga rasterizer CPU, jika Anda suatu saat memutuskan bahwa #6 layak diterapkan).</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 29: Satu pengontrol, tubuh apa pun]]></title>
            <link>https://app.cinevva.com/id/blog/2026-05-15-open-world-browser-part-29-pluggable-character</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-05-15-open-world-browser-part-29-pluggable-character</guid>
            <pubDate>Fri, 15 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 58 membangun pengontrol karakter yang mesin fisikanya tidak mengetahui apa pun tentang berjalan, berenang, atau meluncur. Setiap perilaku adalah pengontrol yang dapat dipasang, mesin yang sama menggerakkan pemain, kuda tunggangan, dan NPC otonom, serta semuanya berjalan secara headless di Node. Spike 59 memasang avatar yang telah di-retarget ke pengontrol tersebut tanpa menyentuh pengontrolnya, dan spike 60 memasang paket Synty yang sama sekali tidak memerlukan retargeting, di balik pemilih klip yang dapat diuji dengan unit test.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 29: Satu pengontrol, tubuh apa pun</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Salah Satu Pendiri Cinevva</em></p>
<p>Baru mengikuti seri ini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menautkan semua bagiannya.</p>
<p><a href="/id/blog/2026-05-14-open-world-browser-part-28-grass-and-occlusion">Bagian 28</a> membahas rumput dan oklusi. Dua puluh delapan bagian telah membangun dunia untuk dipijak: medan yang dapat Anda pahami, air untuk berenang, dedaunan yang tetap meyakinkan hingga cakrawala, serta server yang mengingat apa yang Anda ubah. Bagian ini membahas sesuatu yang bergerak melintasi semuanya, sekaligus menjadi hasil akhir dari keseluruhan mesin, karena tujuannya bukan sekadar pengontrol pemain. Tujuannya adalah pengontrol yang tidak peduli tubuh apa yang digerakkannya, dari mana animasinya berasal, atau apakah manusia maupun AI yang memegang kendali. Spike 58 membangun pergerakan sebagai tumpukan perilaku yang dapat dipasang di atas mesin fisika yang tidak mengetahui apa pun tentang lokomosi, lalu membuktikan arsitekturnya dengan menjalankan tiga tubuh berbeda melalui satu salinan mesin tersebut. Spike 59 memasang avatar nyata yang telah di-retarget ke pengontrol itu tanpa mengubah satu baris pun. Spike 60 memasang paket animasi berbeda yang sama sekali tidak memerlukan retargeting, lalu memisahkan logika pemilihan klip menjadi sesuatu yang benar-benar dapat diuji.</p>
<h2>Mesin fisika yang tidak mengetahui apa pun tentang berjalan</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/58-pluggable-character/" title="Spike 58 Karakter yang Dapat Dipasang" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/58-pluggable-character/" target="_blank">Buka Spike 58 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=58-pluggable-character">Lihat sumber</a></p>
<p>Aturan desainnya ketat dan itulah inti utamanya: mesin kapsul tidak memiliki lokomosi apa pun. Tidak ada berjalan, berlari, melompat, gesekan, batas kecepatan maksimum, bahkan gravitasi. Mesin ini hanya mengintegrasikan kapsul kinematik terhadap medan, tidak lebih. Setiap perilaku lokomosi—berjalan, meluncur di permukaan, melayang, memanjat, berenang, merunduk, stamina—berada dalam pengontrol mandiri yang didaftarkan ke mesin. Pada setiap frame, mesin menjalankan tick untuk setiap pengontrol, menanyakan apakah masing-masing ingin mengambil kendali, lalu mengizinkan pengklaim dengan prioritas tertinggi menulis kecepatan. Berjalan tidak memiliki status khusus. Ia hanyalah pengontrol berprioritas paling rendah yang selalu menjawab ya, sehingga menjadi perilaku default ketika tidak ada yang lain aktif. Sebuah pengontrol terdiri dari enam fungsi kecil: <code>tick</code> yang memperbarui state internalnya sendiri pada setiap frame meskipun sedang tidak aktif, predikat murni <code>wantsControl</code> yang mengklaim frame, <code>applyForces</code> yang hanya dijalankan oleh pemenang untuk menulis kecepatan dan menerapkan gravitasinya sendiri jika diperlukan, ditambah <code>onEnter</code>, <code>onExit</code>, dan <code>stateName</code> yang bersifat opsional. Pengontrol berenang mengembalikan <code>ownsCollision: true</code> dari <code>applyForces</code> untuk mengambil alih penanganan medan, karena jika tidak, pegas daya apungnya akan melawan foot-snap mesin.</p>
<p>Bahkan hal-hal yang bukan lokomosi tetap merembes melalui kontrak tersebut, dan itulah yang memaksa munculnya gagasan berikutnya. Bagian yang membuat arsitektur ini benar-benar bernilai adalah kanal. Desain kanal tunggal sebelumnya menjalankan semuanya melalui satu arbitrase, yang berarti pelacak stamina atau posisi merunduk harus berpura-pura menjadi lokomosi, lalu menolak kendali dengan trik <code>wantsControl</code> yang mengembalikan false hanya agar dapat menjalankan pembukuannya. Solusinya adalah membagi pengontrol ke dalam kanal bernama yang melakukan arbitrase secara independen dan diterapkan dalam urutan tetap: resource, lalu stance, lalu locomotion. Resource berjalan lebih dahulu karena hasil tulisannya, seperti pengurangan stamina, dibaca oleh yang lain. Stance berjalan kedua karena pengurangan tinggi kapsul saat merunduk harus sudah diterapkan sebelum walk membacanya untuk membatasi kecepatan maksimum. Locomotion berjalan terakhir dan memiliki hak atas penulisan kecepatan per frame. Dengan demikian, pengamat stamina, pengubah posisi merunduk, dan pengontrol berenang yang aktif dapat hidup berdampingan dengan bersih, masing-masing di kanalnya sendiri, tanpa ada pengontrol yang harus berbohong tentang identitasnya. Demo memvisualisasikan semua ini dengan kapsul polos yang berubah warna berdasarkan pengontrol aktif, sehingga Anda dapat menyaksikan arbitrase berlangsung: walk berwarna hijau berubah menjadi slide berwarna jingga di lereng curam, menjadi swim berwarna sian di danau, lalu menjadi glide berwarna krem di udara saat Anda mengetuk tombol melayang.</p>
<h2>Satu mesin, tiga tubuh</h2>
<p>Ujian sesungguhnya bagi prinsip &quot;tidak memiliki lokomosi&quot; bukanlah pemain. Ujiannya adalah apakah mesin yang sama, tanpa disentuh, dapat menggerakkan sesuatu yang sama sekali bukan pemain. <code>createCapsuleEngine</code> adalah factory murni tanpa state tingkat modul, tanpa singleton, dan tanpa efek samping per instance, sehingga spike ini membuat tiga instance darinya. Pemain adalah satu instance dengan set pengontrol lengkap. Kuda tunggangan adalah instance kedua yang hanya mendaftarkan pengontrol berjalan, membuat keseluruhan gagasan tersebut benar-benar harfiah: kosakata pergerakan suatu tubuh hanyalah kumpulan pengontrol yang Anda daftarkan. Karena itu, kuda lebih cepat di permukaan datar dan secara fisik tidak dapat memanjat, berenang, atau melayang karena pengontrol tersebut tidak pernah ditambahkan. NPC otonom adalah instance ketiga, yang dijalankan tick-nya pada setiap frame bersama pemain dan digerakkan oleh pengontrol berkeliaran yang menyintesis inputnya sendiri, sehingga tubuh tersebut dapat mengarahkan dirinya tanpa ada tangan di keyboard. Mesin tidak pernah mengetahui bahwa salah satu tubuhnya adalah kuda atau tubuh lainnya dikendalikan AI. Semuanya merupakan integrator kapsul yang sama dengan daftar pengontrol berbeda.</p>
<p>Menunggang adalah satu-satunya bagian yang sengaja berada di luar mesin. Menukar kendali antara pemain dan kuda berarti mengoordinasikan dua mesin, sementara sebuah pengontrol berjalan di dalam satu mesin dan tidak dapat melihat melampaui batas tersebut. Karena itu, logika menunggang berada di tingkat host: sebuah state machine kecil menentukan mesin mana yang dijalankan pada frame ini, membekukan mesin lainnya, menggeser pengendara dengan mulus ke pelana menggunakan smoothstep selama tiga perempat detik, dan memberi tahu kamera tubuh mana yang harus diikuti. Factory mesin tidak pernah mengetahui apa pun tentang semua itu. Itulah batas yang ditetapkan dan dipertahankan arsitektur ini. Perilaku yang dimiliki satu tubuh adalah pengontrol; koordinasi antartubuh adalah tugas host. Pemisahan ini membuat penambahan tubuh keempat maupun keempat puluh tidak memerlukan biaya arsitektur baru.</p>
<h2>Diuji tanpa browser</h2>
<p>Karena mesin tidak mengakses <code>window</code>, <code>document</code>, maupun Three.js, semuanya dapat berjalan secara headless. Spike ini menyertakan harness Node yang membuat mock antarmuka medan, menjalankan mesin frame demi frame dengan input terprogram, lalu membuat assertion terhadap state yang dihasilkan. Dengan demikian, regresi yang sangat sulit ditemukan melalui play-testing dapat ditangkap oleh skrip: transisi melompat-dan-mendarat, ambang masuk dan keluar dari berenang, status memanjat yang otomatis dibersihkan ketika permukaan menjadi datar, serta laju pengurasan stamina. Memberikan urutan input dan timestep yang sama sebanyak dua kali, lalu memeriksa state keluaran yang identik hingga tingkat byte, memastikan mesin bersifat deterministik—properti yang pada akhirnya akan diandalkan oleh build berjaringan. Salah satu regresi yang ditemukan harness ini layak dipertahankan sebagai pengujian: berpindah dari tanah yang dapat dilalui ke lereng yang terlalu curam untuk dilalui dahulu mengaktifkan pengontrol slide dan memantulkan pemain kembali ke atas bukit. Solusinya adalah gerbang penurunan. Slide hanya dimulai jika kapsul benar-benar sedang jatuh ke lereng. Dengan demikian, berjalan secara horizontal ke permukaan curam kini terhalang dengan bersih alih-alih membuat pemain meluncur, dan pengujian yang menegaskan &quot;berjalan menuju lereng yang tidak dapat dilalui menghalangi pemain&quot; memastikan masalah itu tetap teratasi.</p>
<h2>Memasang avatar nyata tanpa menyentuh pengontrol</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/59-pluggable-with-avatar/" title="Spike 59 Dapat Dipasang dengan Avatar" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/59-pluggable-with-avatar/" target="_blank">Buka Spike 59 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=59-pluggable-with-avatar">Lihat sumber</a></p>
<p>Spike 59 menguji apakah lapisan pengontrol benar-benar terpisah dari tubuh. Spike ini mengganti kapsul berwarna dengan karakter skeletal nyata, yaitu rig FBX 3MIKE yang dipasangi klip Quaternius Universal Animation Library yang telah di-retarget, dan pengontrolnya sama sekali tidak berubah. Titik penghubungnya hanyalah satu string. Setiap pengontrol telah melaporkan nama state melalui <code>stateName</code>—idle, walk, run, jump, fall, land, slide, glide, swim, swimIdle—lalu lapisan avatar memetakan nama tersebut ke klip hasil retargeting melalui tabel alias dan melakukan crossfade ketika berganti. Walk memilih sub-state-nya sendiri secara dinamis berdasarkan status grounded, kecepatan vertikal, dan kecepatan horizontal. Dengan demikian, satu pengontrol walk menggerakkan idle, walk, run, jump, fall, dan land, sementara avatar hanya mengikuti nama yang dilaporkan. Karena spike ini hanya untuk pemain tunggal, avatar membuang lapisan tidak langsung berupa integer untuk transmisi dan abstraksi multikarakter dari spike berjaringan sebelumnya, lalu memetakan nama state langsung ke klip. Buktinya adalah seluruh peningkatan visual dari kapsul menjadi manusia ber-rig tidak menyentuh satu baris pun kode lokomosi, dan itulah tepatnya manfaat yang seharusnya diberikan oleh pengontrol yang dapat dipasang.</p>
<h2>Paket yang tidak memerlukan retargeting, dan pemilih yang dapat diuji</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/60-polygon-animations/" title="Spike 60 Animasi Polygon" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/60-polygon-animations/" target="_blank">Buka Spike 60 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=60-polygon-animations">Lihat sumber</a></p>
<p>Spike 60 memasang tubuh ketiga, paket POLYGON Base Locomotion dari Synty, dan loader-nya nyaris tidak melakukan apa pun. Setiap klip disediakan sebagai FBX mandiri yang membawa salinan tertanam dari skeleton Synty yang sama beserta satu animasi baked. Karena rig karakter dan setiap klip menggunakan nama bone yang identik, Anda cukup mengambil klip dari <code>fbx.animations[0]</code> lalu memutarnya langsung pada mixer karakter tanpa melibatkan library retargeting. Three.js mencari target track animasi berdasarkan nama bone, bukan identitas objek, sehingga paket bergaya Synty atau Mixamo yang dibuat untuk rig yang cocok langsung berfungsi. Ini sengaja dikontraskan dengan jalur UAL dari spike sebelumnya, yang membutuhkan retargeting berat karena klip sumber dan rig target dibuat menggunakan skeleton berbeda. Pengontrol yang sama, titik penghubung nama state yang sama, tetapi dua pipeline animasi yang sepenuhnya berbeda di belakangnya.</p>
<p>Bagian lain dari spike 60 adalah membuat logika pemilihan klip dapat diuji. Pemilihan klip yang akan diputar dipenuhi ambang berbasis pertimbangan, dan logika tersebut sebelumnya terkubur di dalam lapisan avatar di samping FBXLoader dan DOM sehingga tidak dapat diuji. Spike ini mengekstrak pemilih tersebut menjadi fungsi-fungsi murni yang tidak menyentuh Three.js maupun window: fungsi itu menerima record pemain biasa (kecepatan, kecepatan horizontal, arah hadap, grounded, normal tanah, kecepatan benturan) serta pengganti clip-action, lalu mengembalikan string alias klip. Dengan demikian, ambangnya dapat hidup sebagai konstanta bernama yang diverifikasi melalui assertion. Lompatan dibagi menjadi varian berjalan, berlari, dan sprint berdasarkan kelompok kecepatan yang diselaraskan dengan ambang sprint aktual milik pengontrol walk; pendaratan dibagi menjadi ringan, sedang, dan keras berdasarkan kecepatan benturan; varian klip menanjak dan menurun dipicu oleh dot product proyeksi lereng dengan deadzone klip datar di bawah sekitar tujuh derajat; transisi idle-ke-lokomosi selalu memilih arah maju agar awal gerakan dari posisi berdiri tidak pernah memutar klip secara terbalik; dan transisi berhenti dibatasi oleh waktu minimum berada dalam loop karena klip berhenti berbasis fase kaki milik Synty berisi sekitar satu detik perlambatan bawaan yang tampak konyol jika ditempelkan pada langkah yang nyaris tidak dilakukan pemain. Debouncer state kecil menunda state fall selama beberapa frame agar hilangnya kontak tanah selama satu frame saat melewati sambungan tidak membuat animasi berkedip. Mengeluarkan semua itu dari shell rendering membuat aturannya dapat diuji dengan unit test tanpa GPU, menggunakan disiplin headless yang sama seperti yang diterapkan pada mesin di spike 58. Inilah perbedaan antara nuansa lokomosi yang disetel dengan menebak-nebak dan nuansa lokomosi yang dapat ditetapkan secara pasti.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Mesin fisika tanpa lokomosi.</strong> Mesin kapsul mengintegrasikan tubuh kinematik terhadap medan dan tidak memiliki perilaku berjalan, berlari, melompat, gesekan, batas kecepatan, maupun gravitasi. Setiap perilaku merupakan pengontrol terdaftar yang mengekspos <code>tick</code>, <code>wantsControl</code>, <code>applyForces</code>, serta <code>onEnter</code>/<code>onExit</code>/<code>stateName</code> yang bersifat opsional. Walk hanyalah default berprioritas paling rendah yang selalu menjawab ya, dan sebuah pengontrol dapat mengembalikan <code>ownsCollision: true</code> untuk mengambil alih penanganan medan (swim melakukannya agar pegas daya apungnya tidak melawan foot-snap).</p>
<p><strong>Kanal arbitrase independen.</strong> Pengontrol didaftarkan ke kanal bernama (resource, stance, locomotion) yang melakukan arbitrase secara terpisah dan diterapkan dalam urutan tetap. Dengan demikian, pengamat seperti stamina dan pengubah seperti crouch dapat hidup berdampingan dengan lokomosi aktif alih-alih berpura-pura mengambil kendali lalu menolaknya. Hasil penulisan resource (stamina) dibaca oleh stance dan locomotion; hasil penulisan stance (tinggi kapsul saat crouch) dibaca oleh batas kecepatan locomotion; locomotion berjalan terakhir dan memiliki hak atas penulisan kecepatan.
<strong>Satu factory, banyak tubuh.</strong> <code>createCapsuleEngine</code> adalah factory murni tanpa singleton, sehingga engine yang sama dapat menggerakkan pemain, kuda tunggangan yang hanya bisa berjalan, dan NPC yang mengarahkan dirinya sendiri menggunakan input sintetis. Kemampuan gerak sebuah tubuh ditentukan sepenuhnya oleh kumpulan controller yang didaftarkan, sehingga kuda tidak dapat memanjat atau berenang karena controller tersebut tidak pernah ditambahkan. Logika menaiki tunggangan berada di level host, bukan di dalam controller, karena logika ini mengoordinasikan dua engine yang tidak dapat saling mengakses. Lihat <a href="/id/guides/landscape-generation-browser#gpu-driven-lod-with-webgpu">LOD berbasis GPU</a>.</p>
<p><strong>Pengujian headless yang deterministik.</strong> Engine tidak mengakses <code>window</code>, <code>document</code>, ataupun Three.js, sehingga harness Node dapat menjalankannya frame demi frame dan menguji aksi melompat-dan-mendarat, ambang batas berenang, penghentian otomatis saat memanjat, serta pengurasan stamina. Memutar ulang input yang sama dua kali dan memeriksa apakah output-nya identik membuktikan determinisme, sementara sebuah uji regresi mengunci descent gate yang mencegah pemain terdorong mundur ketika berjalan horizontal menuju permukaan curam.</p>
<p><strong>Binding avatar yang independen dari tubuh dengan picker yang dapat diuji.</strong> Controller melaporkan string nama state dan lapisan visual memetakannya ke clip, sehingga mengganti kapsul dengan avatar 3MIKE + UAL yang telah di-retarget tidak mengubah kode locomotion sama sekali. Clip Synty POLYGON menggunakan nama tulang yang sama dengan rig dan dapat diputar tanpa retargeting (Three.js mengikat track berdasarkan nama tulang), berbeda dengan jalur UAL yang memerlukan proses retargeting berat. Clip picker dipisahkan menjadi fungsi-fungsi murni dengan konstanta bernama untuk kelompok kecepatan lompatan, tingkat keparahan pendaratan, varian proyeksi kemiringan, idle bridge yang selalu mengarah ke depan, pengaman waktu minimum stop bridge, dan debouncer untuk state jatuh, sehingga nuansa locomotion dapat diuji secara unit, bukan sekadar ditebak.</p>
<hr>
<p>Bagian 29 dari 30.
Sebelumnya: <a href="/id/blog/2026-05-14-open-world-browser-part-28-grass-and-occlusion">Bagian 28 - Rumput hingga cakrawala, dan tanah yang menyembunyikan dirinya sendiri</a>
Berikutnya: <a href="/id/blog/2026-06-04-open-world-browser-part-30-collision-aware-camera">Bagian 30 - Kamera yang menghormati dinding</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 28: Rumput hingga cakrawala, dan permukaan tanah yang menyembunyikan dirinya sendiri]]></title>
            <link>https://app.cinevva.com/id/blog/2026-05-14-open-world-browser-part-28-grass-and-occlusion</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-05-14-open-world-browser-part-28-grass-and-occlusion</guid>
            <pubDate>Thu, 14 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 56 membuat setengah juta rumpun rumput terlihat seperti padang alih-alih konfeti hijau, dengan satu kernel komputasi dan trik cross-quad. Spike 57 menguji performa empat cara untuk menyisihkan apa yang disembunyikan bukit, dan menemukan bahwa jalur yang dipercepat juga merupakan jalur yang benar secara geometris.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 28: Rumput hingga cakrawala, dan permukaan tanah yang menyembunyikan dirinya sendiri</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru di sini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menautkan semua bagian.</p>
<p><a href="/id/blog/2026-05-13-open-world-browser-part-27-island-and-terrain">Bagian 27</a> membangun pulau dan memberinya permukaan tanah yang tidak tampak berulang seperti ubin. Bagian ini membahas dua hal yang membuat medan terasa dihuni alih-alih kosong. Spike 56 adalah rumput, detail permukaan yang mengubah lereng bertekstur menjadi tempat yang ingin Anda jelajahi, dan tantangannya adalah membuat padang terlihat sebagai padang, bukan goresan-goresan yang tersebar. Spike 57 adalah kebalikan dari menggambar lebih banyak: ini tentang tidak menggambar apa yang sudah disembunyikan oleh bukit, dan hasil menariknya adalah bahwa cara cepat untuk mengujinya ternyata juga merupakan cara yang benar.</p>
<h2>Rumput yang terlihat seperti padang, bukan konfeti</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/56-grass/" title="Spike 56 Rumput" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/56-grass/" target="_blank">Buka Spike 56 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=56-grass">Lihat kode sumber</a></p>
<p>Keputusan intinya bersifat geometris. Satu helai tipis yang meruncing berukuran subpiksel dari sebagian besar sudut kamera, sehingga setengah juta helai datar terlihat seperti konfeti hijau yang jarang, bukan sebuah padang. Solusinya adalah rumpun cross-quad: tiga quad meruncing yang diputar dengan selisih enam puluh derajat mengelilingi sumbu atas lokal, sehingga dari arah pandang mana pun setidaknya satu quad berada nyaris tegak lurus terhadap kamera dan setiap instance mencakup kira-kira tiga kali lebar helai pada area layar sebenarnya. Itulah perbedaan antara melihat goresan hijau dan melihat rumput.</p>
<p>Sebuah kernel komputasi WebGPU menempatkan setiap rumpun satu kali saat inisialisasi. Kernel tersebut melakukan hash pada indeks instance menjadi lima aliran acak yang tidak berkorelasi, memilih posisi XZ di dalam petak, mengambil sampel ketinggian tanah dari FBM yang sama dengan yang digunakan mesh tanah CPU (port TSL dengan mod yang mempertahankan tanda agar nilainya cocok persis dan helai rumput berada di permukaan, bukan melayang di atasnya), menghitung normal dengan beda pusat, lalu mengacak lebar, tinggi, dan rona per rumpun. Sisi rendering menggunakan graf verteks TSL yang sepenuhnya melewati matriks instance dan menulis langsung ke ruang klip: graf ini menskalakan unit cross-quad, memutar arah atas lokal ke normal tanah dengan rumus Rodrigues, lalu mentranslasikannya ke posisi rumpun. LOD berdasarkan jarak didapatkan tanpa biaya tambahan dan tanpa pass culling, karena graf verteks mengalikan tinggi rumpun dengan $1 - \text{smoothstep}(\text{fadeNear}, \text{fadeFar}, \text{dist})$, sehingga rumpun yang jauh mengempis hingga tingginya nol dan tidak lagi membebani fill rate. Angin terdiri dari dua oktaf sin dan cos pada XZ dunia milik rumpun ditambah waktu, diterapkan secara horizontal dan dibatasi oleh fraksi tinggi agar pangkal tetap tertambat sementara ujungnya bergerak. Sedikit kemiringan yang memperhitungkan kamera mencondongkan setiap rumpun ke arah pengamat agar terbuka secara perspektif alih-alih tampak seperti kartu datar.</p>
<p>Resep warnanya diadaptasi dari shader URP Breath of the Wild milik NedMakesGames: flat shading dengan warna helai berupa lerp dari rona pangkal ke rona ujung sepanjang fraksi tinggi, sedangkan rona pangkal dan ujung itu sendiri merupakan hasil lerp antara dua palet berdasarkan nilai rona per rumpun. Ini menghasilkan tampilan dua rona berbintik-bintik seperti yang dimiliki padang rumput BotW sungguhan. Diffuse menggunakan normal tanah terhadap matahari dengan batas bawah ambient, karena normal per quad milik cross-quad terlalu berisik jika di-shading satu per satu untuk tampilan bergaya. Seluruh padang dirender dalam satu draw call, dengan penempatan dan animasi yang sepenuhnya dilakukan di GPU.</p>
<h2>Empat cara untuk menyisihkan apa yang disembunyikan bukit</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/57-terrain-occlusion/" title="Spike 57 Oklusi Medan" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/57-terrain-occlusion/" target="_blank">Buka Spike 57 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=57-terrain-occlusion">Lihat kode sumber</a></p>
<p>Spike 57 menguji performa empat jalur culling pada dunia prosedural yang sama dengan yang dialirkan oleh klien produksi, diskalakan 1,8x secara vertikal agar bukit benar-benar mengoklusi vegetasi. T0 hanya menggunakan jarak, sesuai dengan mekanisme visibilitas chunk pada versi yang dirilis. T1 menambahkan frustum culling, peningkatan murah terbesar, dengan membuang semua yang berada di luar kerucut pandang. T2 menambahkan pengujian cakrawala yang memperhitungkan medan: menelusuri sinar dari mata ke setiap instance dan menolaknya jika heightmap naik melewati sinar di titik mana pun sepanjang jalur, sehingga pohon di balik punggung bukit disisihkan meskipun berada di dalam frustum. T3 mempertahankan pengujian cakrawala yang sama, tetapi mempercepatnya dengan piramida ketinggian maksimum. T4 memindahkan seluruh pengujian jarak-plus-frustum-plus-cakrawala ke kernel komputasi TSL yang menulis skala visibilitas per instance, yang kemudian dibaca material vegetasi untuk mengempiskan verteks tersembunyi. Penghitung tetap-terlihat selama dua frame meredam kedipan satu frame ketika titik sampel jatuh tepat di dalam atau di luar sebuah texel saat kamera sedikit bergerak. Durasinya sengaja dibuat singkat karena durasi yang lebih panjang hanya menyamarkan bug algoritmis alih-alih memperbaikinya.</p>
<p>Piramida inilah yang membuat spike ini berharga, dan pelajarannya adalah menyesuaikan pengujian dengan apa yang benar-benar tampil di layar. Medan yang dirender adalah mesh segitiga dengan verteks pada grid tetap berjarak dua meter, dan di antara verteks, rasterizer melakukan interpolasi linear. Karena itu, ketinggian nyata yang dirender di dalam persegi panjang mana pun adalah nilai maksimum dari verteks di dalamnya, bukan puncak noise kontinu di antara verteks tersebut. Jika piramida oklusi mengambil sampel noise pada grid yang lebih rapat, piramida akan menemukan puncak semu yang tidak pernah ditampilkan mesh dan mulai menghalangi sinar yang jelas-jelas dapat ditembus pandangan kamera. Jadi, texel dasar piramida ditempatkan tepat pada grid verteks, masing-masing menyimpan nilai maksimum dari empat verteks sudutnya, sementara level atas menggunakan reduksi maksimum 2x2 standar. Ini membuatnya presisi terhadap mesh yang dirender. Untuk pengujian sinar per langkah, kode sengaja mengambil sampel titik pada mesh menggunakan interpolasi bilinear alih-alih mengkueri piramida, karena kueri AABB subtexel mengembalikan nilai maksimum seluruh texel dan menaikkan ketinggian beberapa meter pada punggung bukit yang curam—persis jenis oklusi berlebihan yang akan menyembunyikan prop yang sebenarnya terlihat.</p>
<p>Hasil yang mengejutkan adalah T2, referensi brute-force, justru merupakan jalur yang keliru. Karena T2 mengambil sampel titik langsung dari noise kontinu, jalur ini mendeteksi puncak di antara verteks mesh yang tidak pernah dirender. Akibatnya, T2 sedikit melakukan oklusi berlebihan dan menyembunyikan vegetasi yang sebenarnya dapat dilihat pemain. Jalur piramida lebih cepat berkat reduksi AABB $O(\log N)$ untuk pengujian tingkat chunk, sekaligus lebih benar secara geometris karena hanya dapat mengembalikan ketinggian yang benar-benar ditampilkan mesh. Itulah inti spike ini: struktur yang dipercepat bukanlah kompromi kualitas demi kecepatan, melainkan versi yang sesuai dengan kenyataan. Culling chunk menjalankan pengujian lima titik per chunk (empat sudut atas ditambah titik tengah pada ketinggian maksimum chunk) dan mengecualikan area chunk itu sendiri dari kumpulan pengoklusi agar chunk tidak pernah mengoklusi dirinya sendiri. Jalur produksi yang direkomendasikan adalah T4: masukkan metadata instance dan medan ketinggian ke storage buffer, lalu jalankan loop yang sama dalam compute shader dengan indirect draw, karena renderer memang sedang beralih ke WebGPU.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Rumput GPU cross-quad.</strong> Tiga quad meruncing yang diputar dengan selisih enam puluh derajat per rumpun menjamin adanya satu quad yang nyaris tegak lurus dari sudut mana pun, sehingga setengah juta instance terlihat seperti padang, bukan konfeti subpiksel. Sebuah kernel komputasi menempatkan setiap rumpun (ketinggian tanah FBM yang diambil sampelnya dengan mod yang mempertahankan tanda seperti pada mesh CPU, normal beda pusat, serta ukuran dan rona per rumpun), sementara graf verteks TSL melewati matriks instance untuk menskalakan, melakukan rotasi Rodrigues ke normal, mentranslasikan, dan menerapkan angin yang dibatasi oleh tinggi. LOD berdasarkan jarak didapatkan tanpa biaya tambahan: rumpun mengempis hingga tingginya nol berdasarkan $1 - \text{smoothstep}(\text{fadeNear}, \text{fadeFar}, \text{dist})$. Warnanya mengikuti resep BotW dari NedMakesGames, yaitu gradasi pangkal-ke-ujung pada dua palet yang dicampur berdasarkan rona. Lihat <a href="/id/guides/landscape-generation-browser#gpu-driven-lod-with-webgpu">LOD berbasis GPU</a>.</p>
<p><strong>Culling oklusi cakrawala medan.</strong> Empat jalur diuji performanya pada dunia produksi: jarak, ditambah frustum, ditambah pengujian sinar heightmap yang menolak instance di balik punggung bukit, ditambah piramida ketinggian maksimum yang mempercepatnya, lalu port komputasi TSL. Piramida mengambil sampel tepat pada grid verteks dua meter yang digunakan untuk teselasi mesh (texel dasar = nilai maksimum dari empat verteks sudut, dengan reduksi maksimum 2x2 ke atas), sehingga hanya mengembalikan ketinggian yang benar-benar ditampilkan rasterizer.</p>
<p><strong>Dipercepat sekaligus benar, bukan sebuah kompromi.</strong> Pengambilan sampel titik pada noise kontinu (jalur brute-force T2) menemukan puncak di antara verteks mesh yang tidak pernah dirender, sehingga melakukan oklusi berlebihan terhadap vegetasi yang terlihat. Piramida grid verteks lebih cepat (reduksi AABB $O(\log N)$) sekaligus presisi secara geometris. Karena itu, pengujian sinar per langkah mengambil sampel bilinear dari mesh alih-alih mengkueri nilai maksimum per texel milik piramida, yang akan menaikkan ketinggian beberapa meter pada punggung bukit curam. Culling chunk menggunakan pengujian lima titik dan mengecualikan area chunk itu sendiri agar tidak pernah mengoklusi dirinya sendiri. Jalur produksi memasukkan metadata dan medan ketinggian ke storage buffer untuk culling dengan compute shader serta indirect draw.</p>
<hr>
<p>Bagian 28 dari 29.
Sebelumnya: <a href="/id/blog/2026-05-13-open-world-browser-part-27-island-and-terrain">Bagian 27 - Pulau dari noise, permukaan tanah yang tampak seperti tanah</a>
Berikutnya: <a href="/id/blog/2026-05-15-open-world-browser-part-29-pluggable-character">Bagian 29 - Satu pengontrol, tubuh apa pun</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 27: Pulau dari noise, permukaan tanah yang tampak nyata]]></title>
            <link>https://app.cinevva.com/id/blog/2026-05-13-open-world-browser-part-27-island-and-terrain</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-05-13-open-world-browser-part-27-island-and-terrain</guid>
            <pubDate>Wed, 13 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 54 menumbuhkan pulau yang meyakinkan hanya dari noise: FBM dengan domain warping yang dibentuk oleh radial falloff, lalu erosi hidraulis yang mengukir drainase nyata, kemudian bioma yang ditetapkan berdasarkan elevasi dan kelembapan. Spike 55 memperbaiki masalah tekstur tertua yang ada, yaitu tile yang berulang, dengan empat mode sampling dan satu mode yang benar-benar unggul.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 27: Pulau dari noise, permukaan tanah yang tampak nyata</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Salah Satu Pendiri Cinevva</em></p>
<p>Baru di sini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan ini menjelaskan apa itu spike dan menautkan semua bagiannya.</p>
<p><a href="/id/blog/2026-05-12-open-world-browser-part-26-water">Bagian 26</a> menambahkan air ke dunia. Bagian ini membangun daratan di bawahnya, dalam dua tahap yang mencerminkan cara sebuah tempat nyata terbentuk. Spike 54 adalah medannya sendiri: bukan dipahat dengan tangan, melainkan ditumbuhkan dari noise, lalu dilapukkan hingga memiliki drainase dan garis pantai seperti tempat yang benar-benar pernah dialiri air. Spike 55 adalah kulit pada medan tersebut: menyelesaikan masalah yang menggagalkan hampir setiap permukaan tanah prosedural, yaitu tekstur berubin yang tampak berulang. Keduanya bersama-sama menjawab satu pertanyaan: bisakah kreator mendapatkan pulau yang masuk akal dan permukaan tanah yang benar-benar terbaca sebagai tanah tanpa sentuhan seniman? Jawabannya ya, jika Anda meniru resep yang tepat.</p>
<h2>Garis pantai yang tidak bisa diberikan oleh noise saja</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/54-procgen-island/" title="Spike 54 Pulau Prosedural" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/54-procgen-island/" target="_blank">Buka Spike 54 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=54-procgen-island">Lihat sumber</a></p>
<p>Heightmap ini mengikuti resep Red Blob Games, yaitu rangkaian transformasi kecil yang masing-masing memperbaiki kelemahan tertentu pada noise mentah. Fractional Brownian motion menjumlahkan beberapa oktaf noise Perlin sehingga medan memiliki bukit-bukit lebar sekaligus detail halus, tetapi FBM biasa tampak lembut dan sejajar dengan grid. Karena itu, titik sampelnya terlebih dahulu diberi domain warping: setiap koordinat digeser oleh medan noise lain, $p' = p + \text{noise}(p)\cdot s$, yang membengkokkan punggungan menjadi bentuk organik alih-alih terkunci pada sumbu. Kemudian redistribusi, dengan memangkatkan elevasi menjadi $e^{,k}$, menekan nada tengah sehingga dunia memiliki lembah datar dan puncak tajam, bukan seluruh permukaan berada pada kemiringan landai yang sama. Bagian yang menjadikannya pulau alih-alih perbukitan tak berujung adalah radial falloff: hitung jarak Euklides dari pusat, $d = \min(1, \sqrt{n_x^2 + n_y^2})$, lalu padukan elevasi menuju $1 - d$ sehingga medan turun ke laut di bagian tepi. Medan noise independen kedua menjadi peta kelembapan, yang tidak memengaruhi bentuk tetapi nantinya digunakan dalam tahap bioma.</p>
<p>Itu menghasilkan suatu bentuk, tetapi masih berupa bentuk noise. Tidak ada sungai, lembah yang terkikis air, atau kipas sedimen, karena belum pernah ada sesuatu yang mengalir melintasinya. Solusinya adalah erosi hidraulis, yang di-port dari implementasi berlisensi MIT milik Sebastian Lague. Ribuan tetesan air muncul secara acak dan mengalir menuruni lereng. Masing-masing membawa inersia agar tidak berbelok tajam membentuk sudut siku-siku, mengangkut sedimen ketika bergerak semakin cepat dan mengendapkannya ketika melambat atau menggenang. Brush melingkar yang telah dihitung sebelumnya menyebarkan setiap peristiwa erosi dalam radius kecil sehingga kikisannya halus, bukan goresan selebar satu piksel, sementara penguapan mengakhiri tetesan selama masa hidupnya. Jalankan cukup banyak tetesan dan medan akan menumbuhkan sesuatu yang tidak bisa dipalsukan oleh noise: jaringan drainase yang bertemu, lembah yang semakin lebar ke arah hilir, serta dataran tempat sedimen mengendap.</p>
<h2>Erosi di GPU, dan sungai yang tahu tempatnya</h2>
<p>Erosi CPU memberikan hasil yang benar tetapi lambat, sehingga spike ini juga mem-port-nya ke compute shader WebGPU. Bagian yang menarik adalah konsekuensi yang dipaksakan oleh atomic GPU. Ketinggian disimpan sebagai <code>i32</code> fixed-point dengan skala satu juta, karena WGSL tidak memiliki atomic add untuk float, dan satu-satunya cara agar ribuan tetesan dapat mengendapkan serta mengangkat sedimen dari sel yang sama secara paralel tanpa race condition adalah menggunakan <code>atomicAdd</code> dan <code>atomicSub</code> pada integer. Perjalanan bolak-balik fixed-point ini berarti suatu sel terkadang dapat menjadi sedikit negatif akibat tarikan bersamaan yang berat, tetapi hal itu tidak berbahaya dan nilainya dibatasi saat readback. Versi CPU menghitung tabel brush per sel terlebih dahulu, tetapi pada grid $1001^2$ tabel tersebut berukuran sekitar 100 MB. Karena itu, port GPU menghitung ulang brush setiap tetesan secara langsung, menukar sedikit komputasi dengan penghematan memori yang besar. Posisi awal tetesan tetap berasal dari CPU melalui generator Mulberry32 agar setiap proses berjalan deterministik.</p>
<p>Dua pass tambahan mengubah medan yang telah terlapukkan menjadi peta yang mudah dibaca. Drainase menggunakan metode akumulasi aliran D8 dari Red Blob: jatuhkan satu unit hujan pada setiap sel, urutkan semua sel berdasarkan elevasi dari tinggi ke rendah, lalu teruskan akumulasi air setiap sel ke satu tetangga terendahnya. Dengan demikian, air menumpuk di sepanjang lembah alami, dan setiap sel yang akumulasinya melewati ambang batas ditandai sebagai sungai. Masalahnya, heightmap yang telah tererosi memiliki cekungan, yaitu depresi lokal tanpa jalur keluar ke tempat yang lebih rendah. Air yang memasuki cekungan hanya akan berhenti dan memutus akumulasi. Karena itu, sebelum drainase dijalankan, pengisian cekungan Planchon-Darboux menaikkan setiap cekungan hingga sedikit di atas tetangga terendahnya, $\text{minNeighbour} + \epsilon$, dengan iterasi kurang dari dua puluh pass sampai setiap sel memiliki tempat untuk mengalirkan air. Terakhir, bioma ditetapkan dengan cara Red Blob, yaitu pencarian dua sumbu berdasarkan elevasi dan kelembapan. Sel yang tinggi dan kering menjadi batu, sedangkan sel yang rendah dan basah menjadi rawa, ditambah override berdasarkan kemiringan: permukaan curam selalu dijadikan batu terlepas dari kelembapan, pita garis air menjadi pantai, dan elevasi tertinggi tertutup salju. Hasilnya adalah pulau yang dapat dipahami sekilas, dibuat sepenuhnya dari dua seed noise.</p>
<h2>Tile yang terus berulang</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/55-terrain-shading/" title="Spike 55 Shading Medan" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/55-terrain-shading/" target="_blank">Buka Spike 55 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=55-terrain-shading">Lihat sumber</a></p>
<p>Medan memerlukan material yang mencakup area berkilo-kilometer dari tekstur yang lebarnya hanya beberapa meter, dan saat tile diperbesar untuk menutupi tanah, mata langsung menangkap pengulangannya. Spike 55 adalah pengujian A/B terhadap empat mode sampling pada geometri dan pencahayaan yang sama, sehingga satu-satunya variabel adalah cara tekstur dibaca. Baseline-nya adalah <code>plain</code>: satu sampel pada UV yang telah diskalakan, dengan pola pengulangan yang terlihat jelas setiap beberapa meter, dan keberadaannya hanya sebagai acuan yang harus dikalahkan. Layer PBR gratis berasal dari Poly Haven melalui CDN mereka, terdiri atas diffuse, peta ARM yang dipaketkan (ambient occlusion, roughness, metalness), serta normal GL. Semuanya berlisensi CC0 dan dimuat dengan anisotropy 8 serta mipmap.</p>
<p>Tiga mode lainnya menarik karena menggunakan pendekatan berbeda untuk mengatasi pengulangan. Mode <code>hex-linear</code> adalah grid segitiga Heitz-Neyret: hamparkan kisi segitiga miring di atas permukaan, lalu setiap fragmen berada di dalam satu segitiga yang ketiga verteksnya masing-masing mengambil tap dengan offset acak, kemudian dipadukan menggunakan bobot barycentric. Dengan demikian, wilayah yang bersebelahan mengambil sampel dari bagian tekstur yang berbeda dan pola tile berskala besar menghilang. Namun, perpaduan linear biasa dari tiga tap merata-ratakan warnanya di tepi segitiga, meninggalkan pola segitiga yang terlihat, yaitu artefak yang sama persis dengan yang ditemui spike 48. Mode <code>hex-vp</code> adalah perbaikan yang dipublikasikan dalam makalah tahun 2018 yang sama: setelah penjumlahan barycentric, kurangi warna rata-rata tekstur, skalakan ulang dengan kebalikan akar kuadrat dari jumlah bobot yang dikuadratkan agar varians tetap konstan, lalu tambahkan kembali nilai rata-ratanya. Hal ini mempertahankan kontras secara konsisten di seluruh perpaduan sehingga segitiganya menghilang. Itulah sebabnya material melakukan readback 1-kali-1 pada setiap tekstur yang dimuat untuk memperkirakan warna rata-ratanya sejak awal. Mode keempat, <code>iq-untiled</code>, adalah teknik 3 Texture Repetition milik Inigo Quilez: dua tap dengan offset yang dipadukan oleh pola variasi frekuensi rendah, hanya dua sampel alih-alih tiga dan tanpa struktur segitiga sejak awal—opsi ringan yang tetap memberikan hasil baik.</p>
<p>Di atas mode mana pun terdapat proyeksi triplanar opsional, yang memungkinkan material yang sama membungkus tebing tanpa meregang. Alih-alih satu UV, shader mengambil sampel dari tiga proyeksi sumbu dunia: permukaan yang menghadap X membaca bidang YZ, Y membaca ZX, dan Z membaca XY, lalu memadukannya berdasarkan <code>abs(normalWorld)</code> yang dipangkatkan dengan nilai penajaman antara empat dan delapan agar lereng 45 derajat tidak membaurkan ketiga proyeksi menjadi bubur. Pengujian ini memperjelas komprominya: perpaduan heksagonal yang mempertahankan varians unggul dalam kualitas, sedangkan metode dua tap Quilez lebih hemat performa. Keduanya mengalahkan mode plain dengan selisih yang begitu besar sehingga tidak ada kreator yang seharusnya merilis tile plain.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Pembuatan heightmap dengan rangkaian resep.</strong> Resep Red Blob Games menyusun noise mentah menjadi medan: FBM dengan domain warping ($p' = p + \text{noise}(p)\cdot s$) untuk punggungan organik, redistribusi $e^{,k}$ untuk lembah datar dan puncak tajam, serta radial falloff Euklides yang dipadukan menuju $1 - d$ untuk menurunkan bagian tepi ke laut dan membentuk pulau. Medan noise kedua menjadi peta kelembapan untuk penetapan bioma. Lihat <a href="/id/guides/landscape-generation-browser">pembuatan lanskap</a>.</p>
<p><strong>Erosi hidraulis, CPU dan GPU.</strong> Model tetesan Sebastian Lague (inersia, kapasitas angkut, brush endapan melingkar yang dihitung sebelumnya, penguapan) mengukir drainase nyata yang tidak dapat dipalsukan oleh noise. Port compute WebGPU menyimpan ketinggian sebagai <code>i32</code> fixed-point pada skala satu juta agar tetesan dapat menjalankan <code>atomicAdd</code>/<code>atomicSub</code> pada sel yang sama secara paralel, menghitung ulang brush setiap tetesan secara langsung untuk menghindari tabel berukuran ~100 MB pada $1001^2$, dan menentukan seed posisi awal dari generator Mulberry32 yang deterministik.</p>
<p><strong>Drainase D8 dengan pengisian cekungan.</strong> Akumulasi aliran D8 Red Blob menjatuhkan satu unit hujan per sel, mengurutkan sel berdasarkan elevasi menurun, lalu meneruskan air ke tetangga terendah setiap sel dan menandai sungai di atas ambang batas. Pengisian cekungan Planchon-Darboux terlebih dahulu menaikkan setiap depresi lokal hingga $\text{minNeighbour} + \epsilon$ (dengan iterasi kurang dari dua puluh pass) agar air tidak pernah terperangkap dan akumulasi tetap terhubung. Pencarian dua sumbu berdasarkan elevasi dan kelembapan menetapkan bioma, dengan override kemiringan yang memaksakan batu pada tebing, pantai di garis air, dan salju di puncak.</p>
<p><strong>Memecah pengulangan tekstur dengan empat cara.</strong> Pada geometri dan pencahayaan yang identik: <code>plain</code> (satu tap, pengulangan tile terlihat jelas), <code>hex-linear</code> (grid segitiga Heitz-Neyret, perpaduan linear meninggalkan pola segitiga), <code>hex-vp</code> (perbaikan pemertahanan varians EGSR 2018 §3.3 yang mengurangi nilai rata-rata, menskalakan ulang dengan inverse-sqrt dari bobot kuadrat, lalu menambahkan kembali nilai rata-rata, sehingga memerlukan readback nilai rata-rata 1×1 per tekstur), dan <code>iq-untiled</code> (teknik dua tap 3 dari Inigo Quilez). Proyeksi triplanar mengambil sampel dari tiga bidang sumbu dunia yang dipadukan menggunakan <code>abs(normalWorld)</code> dengan pangkat 4–8 agar tebing tidak meregang. Pemertahanan varians unggul dalam kualitas, sedangkan dua tap unggul dalam biaya. Lihat <a href="/id/guides/landscape-generation-browser#terrain-materials">material medan</a>.</p>
<hr>
<p>Bagian 27 dari 29.
Sebelumnya: <a href="/id/blog/2026-05-12-open-world-browser-part-26-water">Bagian 26 - Tiga cara membuat air</a>
Berikutnya: <a href="/id/blog/2026-05-14-open-world-browser-part-28-grass-and-occlusion">Bagian 28 - Rumput hingga cakrawala, dan tanah yang menyembunyikan dirinya sendiri</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 26: Tiga cara membuat air]]></title>
            <link>https://app.cinevva.com/id/blog/2026-05-12-open-world-browser-part-26-water</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-05-12-open-world-browser-part-26-water</guid>
            <pubDate>Tue, 12 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 51 membangun air dengan pantulan ruang layar dan menemui batas fundamentalnya: teknik ini tidak dapat memantulkan apa yang tidak pernah dilihat kamera. Spike 52 beralih ke cermin planar, pola yang digunakan setiap game yang dirilis, dan membasmi bug yang menghilangkan pantulan gelap. Spike 53 memasang pustaka air siap produksi untuk melihat seperti apa hasil yang benar-benar selesai.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 26: Tiga cara membuat air</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru di sini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menautkan semua bagian.</p>
<p><a href="/id/blog/2026-05-10-open-world-browser-part-25-universal-characters">Bagian 25</a> memberi pakaian pada avatar. Bagian ini membahas air, dan terdiri dari tiga spike karena air adalah permukaan tempat jalan pintas murah dan jawaban yang tepat tampak identik dalam tangkapan layar, tetapi sangat berbeda saat bergerak. Spike 51 membangun pantulan dengan cara ruang layar, pilihan yang menggoda, lalu langsung terbentur keterbatasan bawaannya. Spike 52 beralih ke metode yang benar-benar digunakan oleh setiap game yang dirilis. Spike 53 memasang pustaka air yang sudah jadi untuk melihat seberapa jauh posisi kita dari kondisi &quot;selesai&quot;. Ketiganya memakai satu lapisan refraksi yang sama, jadi satu-satunya variabel yang berubah di antara dua spike pertama adalah cara menghitung pantulan.</p>
<h2>Pantulan dari layar yang sudah Anda miliki</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/51-water-ssr-caustics/" title="Spike 51 Air SSR" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/51-water-ssr-caustics/" target="_blank">Buka Spike 51 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=51-water-ssr-caustics">Lihat sumber</a></p>
<p>Pantulan ruang layar menggunakan kembali frame yang sudah dirender. Untuk setiap piksel air, Anda memantulkan sinar pandang dari permukaan, menelusuri sinar pantulan tersebut melalui buffer kedalaman, lalu ketika sinar melewati bagian belakang permukaan yang tercatat, Anda telah menemukan apa yang dipantulkan air, yang langsung diambil sampelnya dari buffer warna. Port ini mengikuti <code>SSRNode</code> milik three.js baris demi baris, yang pada gilirannya mengikuti pengantar SSR dari lettier. Penelusurannya berupa langkah DDA dalam ruang layar: proyeksikan titik awal dan akhir sinar ke koordinat piksel, lalu melangkahlah di sepanjang sumbu yang lebih panjang, satu sampel per piksel. Kedalaman sinar pantulan pada setiap langkah memerlukan interpolasi yang tepat secara perspektif, $\frac{1}{1/z_0 + s,(1/z_1 - 1/z_0)}$, karena menginterpolasi view-Z secara linear jelas keliru dan menghasilkan perpotongan di tempat yang salah.</p>
<p>Dua hal membuatnya layak digunakan, bukan sekadar tayangan slide. Penelusuran kasar dibatasi hingga 64 langkah, karena sinar panjang yang diproyeksikan melintasi seribu piksel akan menjalankan ratusan iterasi per fragmen jika tidak dibatasi, dan bidang air dengan sejuta fragmen dikalikan ratusan iterasi serta beberapa sampel tekstur akan menghasilkan adegan 30 fps. Kualitas mengendalikan stride efektif di dalam batas tersebut, bukan jumlah iterasinya. Selain itu, karena penelusuran kasar yang dibatasi meninggalkan pola bertangga yang terlihat, penyempurnaan biner enam iterasi membagi dua interval antara titik meleset terakhir dan titik perpotongan. Hasilnya adalah akurasi sublangkah 64x, cukup agar fragmen air yang berdekatan tidak lagi terkunci pada posisi perpotongan kasar yang sama. Pemeriksaan akhir jarak titik-ke-garis memastikan kandidat benar-benar berada pada sinar pantulan, bukan sekadar memiliki kedalaman yang sama, dengan toleransi ketebalan yang otomatis menyesuaikan lebar satu piksel dalam ruang pandang pada kedalaman tersebut—lebih ketat dari dekat dan lebih longgar dari jauh.</p>
<p>Bagian yang jujur dari spike ini tertulis dalam komentarnya sendiri: SSR tidak dapat memantulkan apa yang tidak pernah diambil sampelnya oleh kamera utama. Bagian bawah pohon, apa pun yang berada di luar layar, dan apa pun yang terhalang tidak ada dalam buffer, jadi semuanya tidak dapat muncul dalam pantulan. Inilah &quot;hilangnya informasi dari sisi yang salah&quot; yang tidak dapat diperbaiki oleh kualitas penelusuran setinggi apa pun, dan inilah alasan pasti keberadaan spike berikutnya.</p>
<h2>Cermin yang tidak bisa berbohong</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/52-water-planar/" title="Spike 52 Air Planar" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/52-water-planar/" target="_blank">Buka Spike 52 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=52-water-planar">Lihat sumber</a></p>
<p>Pantulan planar merender adegan untuk kedua kalinya dari kamera yang dicerminkan melintasi bidang air ke sebuah target di luar layar, lalu shader air mengambil sampel dari target tersebut. Ini adalah pola kanonis yang digunakan oleh UE5 Water, <code>WaterMesh</code> milik three.js, ABZÛ, dan Sea of Thieves, karena tersedia setiap piksel adegan sebagai sumber, termasuk geometri yang tidak akan pernah dapat dilihat SSR. Dalam TSL, penerapannya hampir antiklimaks: <code>reflector()</code> mengalokasikan kamera pembantu yang dicerminkan beserta target rendernya, Anda menambahkan targetnya ke mesh agar diperbarui pada setiap frame, lalu mengambil sampel warnanya. Saat gelombang ditambahkan nanti, pantulan dibuat bergoyang dengan menambahkan offset distorsi ke node UV milik reflektor, persis seperti baris yang digunakan <code>WaterMesh</code>.</p>
<p>Bug yang patut dicatat berada di jaring pengaman, bukan di cerminnya. Versi sebelumnya mencampurkan keluaran reflektor dengan langit prosedural sebagai fallback, dengan bobot berdasarkan magnitudo warna pantulan, berlandaskan teori bahwa pantulan yang mendekati nol berarti target tidak memiliki apa pun di sana. Namun, bayangan kanopi yang gelap juga memiliki magnitudo rendah, sehingga clamp tidak pernah mencapai kekuatan penuh dan piksel yang memang benar-benar gelap itu tercampur dengan langit cerah. Gejala yang ditemukan pengguna sangat spesifik: target cermin mentah dalam mode debug menampilkan pepohonan gelap dengan sempurna, sementara hasil render komposit memiliki pantulan yang pudar, dan diagnosisnya adalah shader tersebut &quot;menghilangkan warna gelap&quot;. Perbaikannya adalah penghapusan. Target reflektor dapat diandalkan setelah frame pertama, jadi fallback sama sekali tidak diperlukan. Kedua spike memakai refraksi yang sama di bawahnya: ambil sampel adegan di belakang permukaan, rekonstruksi seberapa jauh setiap piksel berada di bawah garis air, lalu terapkan ekstingsi Beer-Lambert per kanal agar warna merah lenyap dalam beberapa meter sementara biru bertahan, dengan mask langit agar latar belakang bidang jauh tidak terkena kabut. Fresnel Schlick mencampurkan refraksi saat Anda melihat lurus ke bawah ke dalam air dengan pantulan saat Anda memandang melintasi permukaannya.</p>
<h2>Seperti apa hasil yang sudah selesai</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/53-water-pro/" title="Spike 53 Air Pro" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/53-water-pro/" target="_blank">Buka Spike 53 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=53-water-pro">Lihat sumber</a></p>
<p>Spike 53 adalah pemeriksaan buat-sendiri-versus-beli. Spike ini memasang <code>threejs-water-pro</code> sebagaimana pustaka tersebut didistribusikan, lengkap dengan preset tropis, clipmap laut bawaan, pelacakan kamera, dan langit Rayleigh, serta memuat glTF pulau yang sama dengan yang digunakan demo pustaka tersebut. Tujuannya adalah melihat jarak antara shader air datar buatan sendiri dan sistem laut lengkap, dan jaraknya memang besar: sistem ini memiliki daya apung yang mengambil sampel tinggi gelombang di beberapa titik di bawah lambung kapal agar kapal mengangguk dan berguling alih-alih sekadar naik-turun, generator jejak kapal, buih garis pantai dan permukaan, serta pass mask yang mencegah air dirender di dalam lambung kapal agar riak tidak menembus geladak.</p>
<p>Integrasinya mengungkap jenis detail yang hanya dapat dipelajari dengan menggunakan pustaka, bukan dengan membaca README-nya. Tekstur buih dirujuk berdasarkan nama file di dalam preset, tetapi pemuatannya menjadi tanggung jawab pengguna pustaka, dan tanpa tekstur tersebut garis pantai tampak seperti tepian garis air yang keras alih-alih ombak pecah. Pulau diposisikan sedemikian rupa sehingga geometri bawah airnya turun melewati dasar laut, sehingga mesh dasar milik pustaka menutupi cincin luar model tanpa tepian bidang yang terlihat. Inilah pola yang dimaksudkan pustaka tersebut: bawa model 3D, jangan menyintesis medan. Antialiasing juga sengaja dinonaktifkan pada renderer dan digantikan dengan pass FXAA pascaproses, karena MSAA mencampurkan fragmen tepi dengan latar belakang sebelum kabut atmosfer yang memperhitungkan kedalaman dijalankan, sehingga meninggalkan garis gelap tipis di setiap pertemuan geometri dengan kabut. Menangani aliasing setelah kabut, bukan sebelumnya, menghilangkan garis tersebut. Hal yang diamankan oleh spike ini adalah keputusannya sendiri: laut siap produksi merupakan sistem khusus yang besar, dan untuk kasus yang memerlukannya, mengadopsi pustaka yang dipelihara lebih baik daripada membangun ulang jejak kapal, daya apung, dan buih dari nol. Sementara itu, shader cermin planar dari spike 52 tetap menjadi jawaban yang tepat untuk perairan darat yang lebih kecil yang ditempatkan kreator di dunianya sendiri.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Air dengan pantulan ruang layar.</strong> Sinar pandang yang dipantulkan menelusuri buffer kedalaman dalam ruang layar melalui DDA, menggunakan interpolasi 1/z yang tepat secara perspektif, batas langkah tetap untuk membatasi biaya per fragmen, dan pass penyempurnaan biner untuk menghilangkan pola garis yang ditinggalkan oleh penelusuran terbatas. Konfirmasi titik-ke-garis dengan ketebalan yang diskalakan berdasarkan kedalaman menolak perpotongan palsu. Batas mutlak metode ini adalah bahwa ia hanya dapat memantulkan geometri yang sudah diambil sampelnya oleh kamera utama, sehingga permukaan di luar layar dan di sisi yang salah tidak pernah muncul. Lihat <a href="/id/guides/landscape-generation-browser#terrain-materials">material medan</a>.</p>
<p><strong>Pantulan cermin planar.</strong> Kamera pembantu yang dicerminkan melintasi bidang air merender adegan ke target di luar layar yang diambil sampelnya oleh shader air, sehingga menghasilkan pantulan yang presisi hingga tingkat piksel, termasuk geometri yang tidak dapat dilihat SSR. Inilah pola yang digunakan oleh UE5 Water dan <code>WaterMesh</code> three.js, dengan distorsi gelombang yang diterapkan sebagai offset pada node UV milik reflektor. Fallback langit berbobot magnitudo secara keliru menghapus piksel pantulan gelap; target reflektor dapat diandalkan setelah frame pertama, jadi menghapus fallback tersebut merupakan perbaikannya.</p>
<p><strong>Refraksi rona kedalaman Beer-Lambert.</strong> Kedua shader mengambil sampel adegan di belakang permukaan, merekonstruksi kedalaman setiap piksel latar di bawah garis air, lalu menerapkan ekstingsi eksponensial per kanal (merah lenyap dalam hitungan meter, biru bertahan) yang dikomposisikan menuju warna kabut air, dengan mask langit agar bidang jauh tidak terkena kabut. Fresnel Schlick mencampurkan refraksi pada insidensi normal dengan pantulan pada sudut datang landai.</p>
<p><strong>Mengadopsi pustaka air siap produksi.</strong> <code>threejs-water-pro</code> menyediakan clipmap laut, langit Rayleigh, daya apung multititik untuk gerakan angguk dan guling kapal, jejak kapal, buih, serta pass mask lambung. Detail di sisi pengguna pustaka itu penting: tekstur buih harus dimuat secara eksplisit, geometri bawah air pulau harus turun melewati dasar laut agar dasar tersebut menutupi tepiannya, dan antialiasing harus dijalankan sebagai pass FXAA pascaproses, bukan MSAA, untuk menghindari garis kabut gelap pada tepi geometri.</p>
<hr>
<p>Bagian 26 dari 29.
Sebelumnya: <a href="/id/blog/2026-05-10-open-world-browser-part-25-universal-characters">Bagian 25 - Satu kerangka, semua pakaian</a>
Berikutnya: <a href="/id/blog/2026-05-13-open-world-browser-part-27-island-and-terrain">Bagian 27 - Pulau dari noise, tanah yang benar-benar tampak seperti tanah</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Bagaimana engine modern mengatasi overdraw dedaunan]]></title>
            <link>https://app.cinevva.com/id/blog/2026-05-11-foliage-overdraw</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-05-11-foliage-overdraw</guid>
            <pubDate>Mon, 11 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Z-prepass, impostor oktahedral, cluster culling berbasis GPU, alpha ter-hash, visibility buffer, dan bayangan distance-field: rangkaian teknik yang mengubah overdraw dedaunan 8-15x menjadi 1-2x dalam adegan hutan lebat.]]></description>
            <content:encoded><![CDATA[<h1>Bagaimana engine modern mengatasi overdraw dedaunan</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Salah Satu Pendiri Cinevva</em></p>
<img src="/img/blog/foliage_overdraw_hero.webp" alt="Kanopi hutan lebat dengan kartu-kartu daun yang saling tumpang tindih dan bertumpuk di depan matahari terbenam, menggambarkan overdraw yang berat" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Hutan adalah salah satu hal terburuk yang bisa Anda minta untuk dirender oleh GPU. Setiap daun adalah quad bertekstur dengan bentuk yang dipotong menggunakan alpha mask. Puluhan quad tersebut bertumpuk di sepanjang setiap sinar pandang. Rasterizer tidak memiliki cara untuk mengetahui sebelumnya fragmen mana yang akan lolos uji alpha, sehingga optimasi early-Z standar yang menyelamatkan adegan opaque sebagian besar dinonaktifkan. Akibatnya, satu piksel layar dapat menjalankan shader daun penuh sebanyak 10 atau 15 kali sebelum frame selesai. Itulah overdraw dedaunan, dan ini merupakan bagian termahal dari sebuah frame dunia terbuka dalam game apa pun yang dirilis selama satu dekade terakhir.</p>
<p>Kabar baiknya, masalah ini sudah terpecahkan. Bukan dalam arti bahwa seseorang memperbaikinya dengan satu trik, melainkan karena ada rangkaian tujuh atau delapan teknik yang, jika digabungkan, menurunkan overdraw efektif dari 8-15x dalam hutan lebat menjadi 1-2x. Setiap engine modern menyertakan variasi dari rangkaian ini. Berikut isi rangkaian tersebut, alasan setiap bagiannya diperlukan, dan referensi utama untuk masing-masing teknik.</p>
<h2>1. Mengapa overdraw dedaunan begitu membebani</h2>
<p>Dalam adegan opaque pada umumnya, GPU melakukan penolakan depth awal: bahkan sebelum pixel shader berjalan, perangkat keras memeriksa depth buffer yang ada dan melewati fragmen yang sudah berada di belakang sesuatu. Proses ini pada dasarnya gratis dan membuat biaya geometri padat tetap masuk akal.</p>
<p>Dedaunan yang diuji dengan alpha merusak mekanisme ini. Fragment shader harus benar-benar berjalan untuk mengevaluasi tekstur alpha dan memanggil <code>discard</code> (atau <code>clip</code>) pada piksel yang dikeluarkan oleh mask. Perangkat keras tidak dapat mengetahui apakah sebuah fragmen akan dibuang sampai shader selesai berjalan, sehingga pada sebagian besar GPU, penggunaan <code>discard</code> di bagian mana pun dalam shader menonaktifkan early-Z sepenuhnya untuk draw call tersebut. Pada GPU berbasis tile (perangkat seluler, seri M, dan beberapa konsol), hal ini dapat menonaktifkan Hi-Z dan kompresi depth untuk seluruh frame. Pixel shader berjalan sekali untuk setiap segitiga yang menutupi sebuah piksel, dan sebagian besar evaluasi tersebut berakhir dengan discard.</p>
<p>Tumpuk 10 quad daun di depan satu piksel layar, maka shader daun akan berjalan 10 kali. Kalikan dengan 4 juta piksel dan biayanya menjadi luar biasa besar. Ulasan Marco Salvi, <a href="https://therealmjp.github.io/posts/to-earlyz-or-not-to-earlyz/">Menggunakan Early-Z atau Tidak</a>, adalah pengantar paling mudah dipahami tentang alasan hal ini terjadi pada tingkat perangkat keras, dan merupakan tempat yang tepat untuk memulai jika Anda belum pernah memikirkannya sebelumnya.</p>
<img src="/img/blog/foliage_overdraw_layers.webp" alt="Tampak samping sinar dari satu piksel layar yang melewati dua belas kartu daun yang saling tumpang tindih, dengan setiap kartu disorot untuk memperlihatkan fragmen hasil uji alpha yang bertumpuk" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<h2>2. Depth prepass untuk geometri masked</h2>
<p>Peningkatan terbesar dari satu teknik, dan teknik yang disertakan oleh setiap engine modern, adalah membagi proses rendering dedaunan menjadi dua pass. Pass pertama hanya menulis depth, menggunakan shader minimal yang menjalankan uji alpha, membuang piksel yang dikeluarkan oleh mask, dan tidak menulis apa pun selain depth. Pass kedua merender material penuh dengan depth testing yang diatur ke &quot;sama dengan&quot; dan penulisan depth dinonaktifkan. Setiap piksel yang terlihat kini menjalankan shading BRDF penuh tepat satu kali, sebanyak apa pun quad daun yang bertumpuk di belakangnya.</p>
<p>Ini terdengar seperti pekerjaan ganda karena segitiga yang sama diproses dua kali, tetapi shader prepass sangat murah (satu sampel tekstur, satu discard, dan satu penulisan depth), sehingga penghematan pada pass utama jauh melampaui biaya tambahannya. Dalam hutan lebat, pass utama berubah dari menjalankan shader daun penuh 10-15 kali per piksel menjadi tepat satu kali.</p>
<p>Unreal, Frostbite, Decima, serta cabang modern Rage dan Dunia semuanya melakukan ini. Teknik ini juga merupakan alasan utama material masked masih lebih murah daripada material translucent di semua engine tersebut.</p>
<p>Ulasan mendalam:</p>
<ul>
<li>Pettineo, <a href="https://therealmjp.github.io/posts/to-earlyz-or-not-to-earlyz/">Menggunakan Early-Z atau Tidak</a> (ulasan utama tentang interaksi <code>discard</code> dengan Hi-Z dan early-Z).</li>
<li>Wihlidal, <a href="http://www.frostbite.com/2016/03/optimizing-the-graphics-pipeline-with-compute/">Mengoptimalkan Pipeline Grafis dengan Compute</a> (GDC 2016, arsitektur depth prepass dan culling berbasis prepass milik Frostbite).</li>
<li>Sanders, <a href="https://www.gdcvault.com/play/1025066/Between-Tech-and-Art-The">Antara Teknologi dan Seni: Vegetasi Horizon Zero Dawn</a> (GDC 2018, mencakup rendering dedaunan dua pass milik Decima).</li>
<li>Persson, <a href="http://www.humus.name/index.php?page=News&amp;ID=255">Beberapa Catatan tentang Z</a> (masih menjadi salah satu penjelasan paling jelas tentang pengujian depth-equal dan keekonomian prepass).</li>
</ul>
<h2>3. LOD agresif dan impostor oktahedral</h2>
<p>Peningkatan terbesar kedua adalah tidak merender daun sama sekali ketika tidak diperlukan. Aset dedaunan disertakan dengan beberapa tingkat LOD. Tingkat terdekat menggunakan mesh lengkap dengan kartu-kartu daun individual. Pada jarak menengah, daun digabungkan menjadi kartu komposit yang lebih padat (serumpun 30 daun menjadi 1 kartu bertekstur dengan siluet yang sama). Setelah melewati ambang jarak tertentu, seluruh pohon berubah menjadi sebuah <em>impostor</em>: geometri kecil yang diberi tekstur berupa tampilan pohon yang telah dirender sebelumnya dari berbagai sudut.</p>
<p>Format impostor modern adalah <strong>impostor oktahedral</strong>: geometri bersisi 8 yang diberi tekstur berupa atlas tampilan yang diambil dari titik-titik pada sebuah bola menggunakan pemetaan oktahedral. Saat runtime, shader memilih dua atau tiga tampilan prarender terdekat berdasarkan arah kamera, lalu memadukannya. Hasilnya adalah representasi pengganti dengan sedikit segitiga yang tampak 3D dari sudut mana pun serta dapat memiliki shading yang tepat, normal map, dan bahkan animasi angin. Implementasi Ryan Brucks, yang awalnya merupakan plugin komunitas dan kini menjadi bagian dari Unreal, adalah rujukan utamanya. Hutan dengan miliaran pohon di Microsoft Flight Simulator pada dasarnya menggunakan impostor oktahedral di semua tempat kecuali di dekat kamera.</p>
<p>Keuntungan struktural yang lebih besar adalah impostor bersifat <em>opaque atau hampir opaque</em> pada jarak jauh. Kartu komposit berisi 30 daun adalah satu quad masked, bukan 30 quad. Impostor satu pohon utuh hanya terdiri dari beberapa sisi, bukan ribuan. Overdraw jarak jauh pun turun hingga nyaris nol.</p>
<p>Ulasan mendalam:</p>
<ul>
<li>Brucks, <a href="https://shaderbits.com/blog/octahedral-impostors">Impostor Oktahedral</a> (referensi utama, lengkap dengan perhitungan matematis dan implementasi UE).</li>
<li>Halen, <a href="https://dev.epicgames.com/community/learning/tutorials/JmL3/octahedral-impostors-unreal-engine">Impostor Oktahedral di Unreal Engine</a> (alur kerja terintegrasi di UE).</li>
<li>Häggström, <a href="https://www.diva-portal.org/smash/get/diva2:1135856/FULLTEXT01.pdf">Rendering Vegetasi Real-Time</a> (tesis yang jelas mengenai rantai LOD, impostor, dan perhitungan matematis di baliknya).</li>
<li>Crytek, <a href="http://developer.nvidia.com/gpugems/gpugems3/part-i-geometry/chapter-4-next-generation-speedtree-rendering">Integrasi SpeedTree di CryEngine 3</a> (GPU Gems 3, masih menjadi pengantar terbaik tentang rantai LOD pohon).</li>
</ul>
<h2>4. Cluster culling berbasis GPU</h2>
<p>Bahkan dengan depth prepass, prepass itu sendiri tetap membutuhkan biaya: prepass masih harus <em>menyentuh</em> setiap segitiga dari setiap pohon yang terlihat (atau mungkin terlihat). Engine modern menekan biaya tersebut dengan cluster culling berbasis GPU, yang membuang seluruh kelompok segitiga sebelum rasterizer melihatnya.</p>
<p>Pipeline-nya bekerja seperti ini: setiap mesh dibagi sebelumnya menjadi cluster berisi 64 atau 128 segitiga dengan bounding box yang rapat dan kerucut normal. Saat render berlangsung, compute shader menelusuri daftar instance, menguji setiap instance terhadap frustum, lalu menguji setiap cluster dari setiap instance yang terlihat terhadap frustum, kemudian melakukan <em>uji occlusion Hi-Z</em> pada setiap cluster yang lolos menggunakan depth pyramid dari frame sebelumnya. Seluruh cabang pohon yang tersembunyi di balik bukit atau berada di belakang pohon lain disingkirkan sebelum vertex shader berjalan. Hasilnya adalah daftar ringkas argumen &quot;render cluster ini&quot; yang diteruskan langsung ke satu panggilan <code>DrawIndirect</code>.</p>
<p>Inilah yang memungkinkan hutan berisi 10.000 pohon dirender dalam hitungan milidetik, bukan detik. Presentasi Assassin's Creed Unity dari Ubisoft memperkenalkan pipeline ini dalam bentuk yang digunakan di produksi (20-40% segitiga disingkirkan, 30-80% segitiga bayangan disingkirkan, dan jumlah instance di layar 10x lebih banyak dibandingkan generasi sebelumnya), lalu presentasi Frostbite dari Wihlidal mengembangkannya lebih jauh. Nanite di UE5 adalah hasil akhir yang terlihat dari perkembangan ini: cluster culling hingga ke tingkat piksel.</p>
<p>Ulasan mendalam:</p>
<ul>
<li>Haar dan Aaltonen, <a href="https://advances.realtimerendering.com/s2015/aaltonenhaar_siggraph2015_combined_final_footer_220dpi.pdf">Pipeline Rendering Berbasis GPU</a> (SIGGRAPH 2015, presentasi fundamental Assassin's Creed Unity).</li>
<li>Wihlidal, <a href="http://www.frostbite.com/2016/03/optimizing-the-graphics-pipeline-with-compute/">Mengoptimalkan Pipeline Grafis dengan Compute</a> (GDC 2016, prepass berbasis GPU milik Frostbite).</li>
<li>Karis, Stubbe, Wihlidal, <a href="https://advances.realtimerendering.com/s2021/Karis_Nanite_SIGGRAPH_Advances_2021_final.pdf">Ulasan Mendalam tentang Geometri Tervirtualisasi Nanite</a> (SIGGRAPH 2021, cluster culling pada granularitas meshlet).</li>
<li>Liktor, <a href="https://research.activision.com/publications/2021/09/geometry-rendering-pipeline-architecture-at-activision">Arsitektur Pipeline Rendering Geometri di Activision</a> (versi cluster culling milik Call of Duty, 2021).</li>
</ul>
<h2>5. Pengurutan instance dan cluster dari depan ke belakang</h2>
<p>Setelah prepass bekerja sebagaimana mestinya, <em>urutan</em> mulai menjadi penting. Prepass menulis depth, tetapi hanya untuk fragmen yang lolos uji alpha. Jika Anda merender bagian belakang hutan terlebih dahulu dan bagian depan terakhir, setiap fragmen depan akan menimpa fragmen belakang, sementara shader prepass tetap berjalan untuk bagian belakang. Jika Anda merender dari depan ke belakang, setiap draw berikutnya mengisi lebih banyak depth buffer dengan nilai yang lebih kecil, dan Hi-Z menolak semakin banyak fragmen belakang sebelum shader berjalan.</p>
<p>Inilah alasan hampir setiap engine modern mengurutkan instance dedaunan berdasarkan jaraknya dari kamera sebelum menjalankan prepass. Pengurutan ini murah (beberapa ratus ribu instance di GPU menggunakan radix sort), dan mengubah prepass itu sendiri menjadi operasi yang memangkas bebannya secara mandiri. Culling tingkat cluster melakukan pengurutan pada granularitas meshlet karena alasan yang sama. Depth prepass dan pengurutan dari depan ke belakang adalah pasangan teknik yang masing-masing bagus, tetapi menjadi luar biasa saat digabungkan.</p>
<p>Ulasan mendalam:</p>
<ul>
<li>Persson, <a href="http://www.humus.name/Articles/Persson_DepthInDepth.pdf">Depth secara Mendalam</a> (catatan arsitektural tentang pengurutan depth buffer, keekonomian prepass, dan perilaku Hi-Z).</li>
<li>Giesen, <a href="https://fgiesen.wordpress.com/2011/07/04/a-trip-through-the-graphics-pipeline-2011-part-7/">Perjalanan Menelusuri Pipeline Grafis</a> (penjelasan teknis mendalam tentang pengaruh urutan draw terhadap tingkat penolakan Hi-Z).</li>
<li>Wihlidal, <a href="http://www.frostbite.com/2016/03/optimizing-the-graphics-pipeline-with-compute/">Mengoptimalkan Pipeline Grafis dengan Compute</a> (GDC 2016, mencakup pengurutan instance di GPU milik Frostbite).</li>
</ul>
<h2>6. Transisi LOD dengan dithering dan alpha ter-hash</h2>
<p>Jebakan besar lainnya adalah fading. Cara naif untuk bertransisi antara dua LOD (atau memudarkan masuk atau keluar sebuah instance saat kamera mendekat) adalah alpha blending. Namun, geometri hasil blending tidak dapat menulis ke depth buffer, sehingga setiap pohon yang sedang memudar masuk ke jalur translucent yang lambat dan merusak prepass. Solusinya adalah mempertahankan geometri di jalur masked dan melakukan fading <em>di dalam uji alpha</em>.</p>
<p>Dua teknik utama:</p>
<ul>
<li><strong>Transisi LOD dengan dithering</strong> mengambil sampel pola Bayer 4x4 atau 8x8 (atau tekstur blue-noise dalam screen space), lalu menggunakannya sebagai pengubah cutoff per piksel. Pohon pada blend 50% memiliki pola kotak-kotak piksel yang bertahan; piksel yang hilang diisi oleh pola kotak-kotak komplementer dari LOD berikutnya. TAA menyatukan pola tersebut menjadi perpaduan halus dalam dua atau tiga frame. Murah, stabil, dan berpadu dengan semua sistem lain di dalam engine.</li>
<li><strong>Uji alpha ter-hash</strong> (Wyman &amp; McGuire, I3D 2017) mengganti ambang alpha tetap 0,5 dengan ambang ter-hash per piksel dalam rentang [0,1). Geometri alpha yang jauh dan biasanya menghilang sepenuhnya (karena alpha hasil mipmap turun di bawah 0,5) tetap mempertahankan sebaran piksel yang stabil. Sekali lagi, TAA membereskan hasil akhirnya.</li>
</ul>
<p>Kedua teknik tersebut mempertahankan dedaunan di jalur opaque/masked tempat depth prepass bekerja, sehingga Anda tidak perlu membayar seluruh biaya rendering translucent hanya untuk memudarkan sesuatu. <strong>Alpha to coverage</strong> adalah kerabat gagasan yang sama dari era MSAA: ubah alpha menjadi coverage mask subpiksel dan dapatkan transparansi parsial tanpa meninggalkan jalur masked. Kekurangannya, A2C hanya benar-benar unggul dengan MSAA, yang tidak lagi digunakan oleh sebagian besar deferred renderer modern.</p>
<p>Ulasan mendalam:</p>
<ul>
<li>Wyman dan McGuire, <a href="https://research.nvidia.com/labs/rtr/publication/wyman2017hashed/">Uji Alpha Ter-hash</a> (I3D 2017, makalah utama tentang hashed alpha).</li>
<li>Castaño, <a href="http://the-witness.net/news/2010/09/computing-alpha-mipmaps/">Menghitung Alpha Mipmap</a> (blog The Witness, cara yang tepat untuk membuat mip tekstur hasil uji alpha agar pohon di kejauhan tidak menghilang).</li>
<li>Yuksel, <a href="https://cemyuksel.com/research/alphadistribution/alpha_distribution.pdf">Distribusi Alpha untuk Uji Alpha</a> (penyempurnaan yang lebih baru untuk alpha mipmap).</li>
<li>NVIDIA, <a href="https://developer.nvidia.com/content/transparency-or-translucency-rendering">Uji Alpha dengan Anti-Aliasing</a> (tinjauan tentang A2C, hashed alpha, dan alternatif berbasis dithering).</li>
</ul>
<h2>7. Mengurangi biaya shading pada piksel masked</h2>
<p>Bahkan dengan prepass sempurna dan culling sempurna, Anda masih harus menjalankan shading satu kali untuk setiap piksel dedaunan yang terlihat. Engine juga mengurangi biaya tersebut:</p>
<ul>
<li><strong>BRDF yang lebih murah</strong>. Dedaunan bersifat matte dan tidak benar-benar memerlukan jalur spekular Cook-Torrance penuh. Difus wrapped-Lambertian ditambah aproksimasi spekular satu baris sudah lebih dari cukup.</li>
<li><strong>Normal map berfrekuensi lebih rendah</strong>. Daun pada dasarnya sudah penuh detail acak. Normal map 256x256 terlihat sama dengan yang berukuran 1024x1024 pada jarak pandang umum dan menghemat bandwidth.</li>
<li><strong>Tanpa parallax, anisotropi, atau clearcoat</strong>. Seluruh menu fitur PBR tersebut dimatikan untuk daun.</li>
<li><strong>Transmisi tipis dua sisi</strong> alih-alih subsurface scattering penuh. Daun meneruskan cahaya dari belakang, tetapi Anda dapat memalsukannya dengan satu dot product untuk cahaya belakang.</li>
<li><strong>Shading setengah resolusi</strong> di beberapa engine. Dedaunan di-shading pada laju 1/4 atau 1/2 piksel lalu di-upscale. Noise stokastik dari TAA menyamarkan resampling tersebut.</li>
<li><strong>Lewati tekstur detail dan decal</strong> pada material masked secara default.</li>
</ul>
<p>Masing-masing memberikan peningkatan kecil. Jika digabungkan, shader dedaunan masked dapat berjalan 2-3x lebih cepat daripada material opaque yang setara.</p>
<p>Pembahasan mendalam:</p>
<ul>
<li>Lagarde dan de Rousiers, <a href="https://seblagarde.wordpress.com/2015/07/14/siggraph-2014-moving-frostbite-to-physically-based-rendering/">Memindahkan Frostbite ke Physically Based Rendering 3.0, bagian tentang dedaunan dan translusensi</a> (SIGGRAPH 2014, penyesuaian PBR rujukan untuk material tipis dua sisi).</li>
<li>Jimenez, <a href="https://www.iryoku.com/stare-into-the-future">Rendering Karakter Generasi Berikutnya</a> (matematika wrapped-Lambertian dan translusensi belakang, awalnya untuk kulit tetapi kemudian banyak diterapkan pada daun).</li>
<li>Sanders, <a href="https://www.gdcvault.com/play/1025066/Between-Tech-and-Art-The">Antara Teknologi dan Seni: Vegetasi Horizon Zero Dawn</a> (GDC 2018, dengan penyederhanaan shader dedaunan Decima).</li>
</ul>
<h2>8. Visibility buffer dan Nanite untuk material masked</h2>
<p>Jawaban paling bersih untuk overdraw adalah <em>memisahkan shading dari rasterisasi sepenuhnya</em>. Visibility buffer merasterisasi geometri ke buffer ringkas (hanya ID segitiga dan ID instance per piksel), lalu menjalankan material penuh sebagai pass deferred yang membaca visibility buffer dan melakukan shading pada setiap piksel tepat satu kali. Secara desain, tidak ada overdraw pada tahap shading. Makalah Burns dan Hunt tahun 2013 memperkenalkan pendekatan ini; UE5 Nanite adalah implementasi berkualitas produksi, termasuk untuk dedaunan masked sejak UE 5.5.</p>
<p>Keunikan Nanite adalah pendekatan ini dilakukan dengan geometri tervirtualisasi pada tingkat cluster, sehingga rasterizer berjalan melalui jalur perangkat lunak untuk segitiga subpiksel dan menjaga overdraw tetap terbatas. Material masked di Nanite memerlukan fitur &quot;programmable raster&quot;: alpha test berjalan selama pass visibility-buffer, tetapi shading material tetap hanya dilakukan sekali per piksel yang terlihat dalam deferred resolve. Hasilnya, dedaunan Nanite yang sangat rapat—yang dahulu terkenal lambat saat memakai material masked—kini dapat bersaing dengan material opaque atau bahkan lebih murah, karena overdraw pada waktu shading bernilai nol. Ada kompromi: sering kali lebih baik mengalirkan geometri pohon <em>opaque</em> berpoligon tinggi melalui Nanite daripada mempertahankan pohon berbasis kartu masked berpoligon rendah, karena jalur masked menambahkan biaya programmable-raster.</p>
<p>Pembahasan mendalam:</p>
<ul>
<li>Burns dan Hunt, <a href="http://jcgt.org/published/0002/02/04/">Visibility Buffer: Pendekatan Ramah Cache untuk Deferred Shading</a> (JCGT 2013, makalah aslinya).</li>
<li>Karis, Stubbe, Wihlidal, <a href="https://advances.realtimerendering.com/s2021/Karis_Nanite_SIGGRAPH_Advances_2021_final.pdf">Pembahasan Mendalam tentang Geometri Tervirtualisasi Nanite</a> (SIGGRAPH 2021, arsitektur produksinya).</li>
<li>Epic, <a href="https://media.gdcvault.com/gdc2024/Slides/GDC+slide+presentations/Nanite+GPU+Driven+Materials.pdf">Material Berbasis GPU Nanite</a> (GDC 2024, dengan pipeline material masked dan programmable-raster).</li>
<li><a href="https://www.sctheblog.com/blog/nanite-materials-notes/">Catatan dari &quot;Material Berbasis GPU Nanite&quot;</a> (panduan pihak ketiga yang jelas untuk presentasi yang sama).</li>
</ul>
<h2>9. Representasi bayangan terpisah untuk dedaunan</h2>
<p>Shadow map untuk dedaunan yang diuji dengan alpha merupakan masalah bayangan termahal kedua dalam frame dunia terbuka, setelah cascade berukuran besar. Setiap cascade memerlukan depth prepass sendiri, setiap prepass menjalankan alpha test, dan biayanya cepat menumpuk pada 4 cascade serta puluhan frustum cahaya. Karena itu, kebanyakan engine tidak merender bayangan dedaunan dengan cara yang sama seperti merender warna dedaunan.</p>
<p>Pengganti yang umum:</p>
<ul>
<li><strong>Bayangan mesh distance field</strong> (UE Lumen, engine khusus). Setiap mesh memiliki signed distance field yang telah dihitung sebelumnya. Cone trace singkat melalui SDF menghasilkan bayangan lembut tanpa pernah menyentuh mesh yang diuji dengan alpha. Ini sangat cocok untuk pohon karena SDF menangkap siluet tajuk sebagai satu gumpalan padat dan mengabaikan detail per daun.</li>
<li><strong>Cascade beresolusi lebih rendah untuk dedaunan</strong>. Bayangan dedaunan dimasukkan ke slice setengah resolusi lalu di-upsample dengan pemfilteran yang mempertahankan tepi. Mata tidak menyadari penurunan resolusi karena bayangannya memang sudah lembut.</li>
<li><strong>Shadow map alpha-to-coverage dengan MSAA</strong>. Pada engine yang masih memiliki MSAA dalam jalur bayangannya, A2C menghasilkan bayangan dedaunan bertepi halus tanpa biaya alpha test penuh.</li>
<li><strong>Bayangan kapsul untuk batang dan cabang besar</strong>, distance field untuk tajuk, dan alpha test penuh hanya pada cascade terdekat. Representasi yang berbeda digunakan untuk jarak yang berbeda, lalu dibaurkan dalam pass pencahayaan.</li>
<li><strong>Jarak penonaktifan WPO</strong>. World Position Offset yang digerakkan angin dimatikan setelah melewati ambang tertentu agar data bayangan yang di-cache tetap valid antar-frame. Virtual Shadow Maps milik UE sangat mengandalkan teknik ini.</li>
</ul>
<p>Pembahasan mendalam:</p>
<ul>
<li>Epic, <a href="https://dev.epicgames.com/documentation/unreal-engine/distance-field-soft-shadows-in-unreal-engine">Bayangan Lembut Distance Field di Unreal Engine</a> (rujukan utama UE untuk bayangan DF mesh).</li>
<li>Wright, <a href="https://advances.realtimerendering.com/s2022/SIGGRAPH2022-Advances-Lumen-Wright%20et%20al.pdf">Lumen: Global Illumination Real-Time di Unreal Engine 5</a> (SIGGRAPH 2022, dengan integrasi mesh-SDF Lumen untuk dedaunan).</li>
<li>Epic, <a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/virtual-shadow-maps-in-unreal-engine">Virtual Shadow Maps</a> (arsitektur bayangan modern UE5, termasuk aturan caching dan penonaktifan WPO khusus dedaunan).</li>
<li>Persson, <a href="https://www.humus.name/index.php?page=3D&amp;ID=81">Cascaded Shadow Maps Praktis</a> (rujukan CSM yang masih menjadi standar, dengan catatan tentang objek pembentuk bayangan yang diuji dengan alpha).</li>
</ul>
<h2>10. Angin, animasi, dan caching bayangan</h2>
<p>Masalah terkait yang tidak kentara: sebagian besar dedaunan bergerak. Animasi vertex yang digerakkan angin (World Position Offset di UE, dengan padanannya di Frostbite dan Decima) berarti geometri dedaunan tidak stabil dari satu frame ke frame berikutnya, sehingga merusak caching dan reproyeksi bayangan. Engine modern mengatasinya dengan dua cara:</p>
<ul>
<li><strong>Batasi WPO berdasarkan jarak</strong>. Setelah melewati ambang tertentu, amplitudo animasi angin secara bertahap turun hingga nol. Mata juga tidak dapat melihat goyangannya dari jarak sejauh itu, sementara cache bayangan tetap valid.</li>
<li><strong>Masukkan pengaruh angin ke dalam batas cluster</strong>. Bounding box cluster diperbesar sebesar offset WPO maksimum agar culling tetap konservatif tanpa perlu mengunggah ulang data setiap frame.</li>
<li><strong>Offset fase per instance</strong>. Pohon-pohon identik menggunakan seed acak per instance untuk menggeser fase angin, sehingga hutan tidak bergoyang serempak tanpa harus membayar biaya animasi unik untuk setiap pohon.</li>
</ul>
<p>Detail semacam ini tidak muncul dalam daftar teknik, tetapi dalam praktiknya menjadi pembeda antara hutan yang memerlukan 3 ms dan 9 ms.</p>
<p>Pembahasan mendalam:</p>
<ul>
<li>Sanders, <a href="https://www.gdcvault.com/play/1025066/Between-Tech-and-Art-The">Antara Teknologi dan Seni: Vegetasi Horizon Zero Dawn</a> (GDC 2018, dengan pipeline animasi angin dan caching bayangan Decima).</li>
<li>McAuley, <a href="https://www.gdcvault.com/play/1022235/Rendering-the-World-of-Far">Merender Dunia Far Cry 4</a> (GDC 2015, mencakup sampling grid angin untuk vegetasi).</li>
<li>Epic, <a href="https://dev.epicgames.com/community/learning/tutorials/qLk6/unreal-engine-virtual-shadow-maps">Dedaunan dan Virtual Shadow Maps</a> (panduan komunitas UE5 tentang jarak penonaktifan WPO dan caching VSM).</li>
</ul>
<h2>11. Perhitungan gabungan</h2>
<p>Tidak satu pun trik ini merupakan solusi tunggal untuk semuanya. Hal yang menarik adalah apa yang terjadi saat semuanya ditumpuk:</p>
<ul>
<li>Pass dedaunan masked yang naif pada adegan hutan lebat menghasilkan overdraw efektif sebesar 8-15x. Setiap piksel yang terlihat menjalankan shader daun sebanyak 8 hingga 15 kali.</li>
<li>Tambahkan depth prepass dan overdraw pass utama turun menjadi ~1x, tetapi prepass itu sendiri masih menyentuh semuanya.</li>
<li>Tambahkan pengurutan dari depan ke belakang dan prepass mulai memangkas pekerjaannya sendiri.</li>
<li>Tambahkan GPU culling tingkat cluster dan prepass hanya menyentuh apa yang mungkin terlihat.</li>
<li>Tambahkan rantai LOD dan imposter, lalu <em>jumlah</em> quad yang terlihat turun satu tingkat besaran setelah jarak 30 m.</li>
<li>Tambahkan jalur visibility-buffer / Nanite dan tahap shading benar-benar berjalan sekali per piksel, bahkan pada tumpang tindih yang rapat.</li>
<li>Tambahkan bayangan distance field dan biaya bayangan berhenti meningkat mengikuti alpha test.</li>
</ul>
<p>Hasil utamanya, yang berulang kali muncul dalam presentasi yang ditautkan di atas: overdraw efektif merosot dari 8-15x menjadi 1-2x, dan total biaya frame dedaunan turun 4-6x dalam adegan hutan lebat. Itulah alasan utama game dunia terbuka modern dapat merender hutan pada 60+ fps di perangkat keras konsumen.</p>
<img src="/img/blog/foliage_overdraw_pipeline.webp" alt="Diagram yang memperlihatkan pipeline rendering dedaunan sebagai lima tahap bertumpuk: GPU culling, prepass terurut, pass warna masked dengan depth-equal, shading visibility-buffer, dan jalur bayangan distance-field terpisah" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<h2>12. Artinya bagi browser</h2>
<p>Sebagian besar rangkaian ini dapat dipetakan dengan baik ke WebGPU. Kami telah merilis GPU-driven culling, indirect dispatch, oklusi Hi-Z, dan prepass terurut dari depan ke belakang dalam <a href="/id/blog/2026-02-25-open-world-browser-series-guide">engine browser dunia terbuka</a>. Depth prepass untuk geometri masked cukup mudah diterapkan: WebGPU mendukung pengujian depth-equal dan <code>discard</code> dalam fragment shader, dengan catatan yang sama terkait early-Z. Imposter oktahedral dapat di-port secara mekanis; matematikanya hanya berupa pembukaan bungkus bola ke oktahedron dan pengindeksan atlas.</p>
<p>Bagian yang lebih sulit adalah teknik-teknik modernnya. Visibility buffer di WebGPU berarti menulis ID segitiga 32-bit ke render target dan me-resolve material dalam compute pass layar penuh; komponen dasarnya sudah tersedia, tetapi orkestrasi penerapannya cukup rumit. Bayangan mesh distance field memerlukan tekstur 3D per aset dan cone trace singkat, yang keduanya masih dalam jangkauan WebGPU. Hashed alpha dan LOD dengan dithering masing-masing hanya membutuhkan satu fungsi shader.</p>
<p>Jalur ke depan untuk dedaunan di browser sama seperti untuk komponen lain dalam rangkaian ini: rilis lebih dahulu bagian yang murah dan tangguh (prepass, instance terurut, LOD, imposter, hashed alpha), lalu tambahkan mekanisme berat (visibility buffer, bayangan mesh-SDF) di atasnya. Batas minimum perangkat keras browser akhirnya cukup tinggi sehingga tidak ada alasan arsitektural bagi hutan WebGPU untuk tidak tampil dan berjalan seperti versi konsol. Yang tersisa hanyalah alasan rekayasa, dan alasan rekayasa adalah jenis tantangan yang kami sukai.</p>
<h2>Bacaan lebih lanjut tentang keseluruhan rangkaian</h2>
<p>Jika Anda menginginkan satu sumber yang merangkum semua ini, arsip SIGGRAPH &quot;Advances in Real-Time Rendering in Games&quot; (<a href="https://advances.realtimerendering.com/">advances.realtimerendering.com</a>) memiliki presentasi rujukan tentang dedaunan dan rendering berbasis GPU sejak 2014. <a href="http://www.adriancourreges.com/blog/">Artikel profiling GPU</a> karya Adrian Courrèges mencakup uraian frame demi frame untuk GTA V dan Horizon Zero Dawn, yang memperlihatkan setiap pass yang dibahas di sini sesuai urutan produksinya. Khusus untuk matematika alpha test, <a href="https://cwyman.org/">halaman riset</a> Chris Wyman menyediakan makalah hashed-alpha dan transparansi stokastik beserta shader referensinya. Bab-bab tentang transparansi, sampling, dan penanganan depth dalam <a href="https://www.realtimerendering.com/">Real-Time Rendering, edisi ke-4</a> juga masih menjadi titik awal rujukan.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 25: Satu skeleton, semua pakaian]]></title>
            <link>https://app.cinevva.com/id/blog/2026-05-10-open-world-browser-part-25-universal-characters</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-05-10-open-world-browser-part-25-universal-characters</guid>
            <pubDate>Sun, 10 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 50 menguji apakah sebuah paket karakter CC0 mampu menopang produk kustomisasi avatar. Ternyata empat paket Quaternius sengaja menggunakan satu skeleton dengan 65 joint yang sama, sehingga spike ini berubah dari masalah pipeline animasi menjadi latihan rebinding skeleton berdasarkan nama.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 25: Satu skeleton, semua pakaian</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru mengikuti seri ini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan itu menjelaskan apa itu spike dan menautkan semua bagian.</p>
<p><a href="/id/blog/2026-05-09-open-world-browser-part-24-persistence-and-wind">Bagian 24</a> membuat dunia menjadi persisten dan memberi angin pada vegetasinya. Bagian ini kembali membahas orang-orang di dalamnya, tetapi dari sisi pakaian: bisakah kreator memilih tubuh dasar, mengganti pakaian, memilih gaya rambut, dan memainkan animasi apa pun, semuanya dengan paket aset gratis, tanpa melakukan rigging maupun membuat animasi? Membuat rig kustom bukanlah hal yang tepat untuk dikurangi risikonya. Pertanyaan yang perlu dijawab adalah apakah paket CC0 mampu menanggung seluruh kebutuhan tersebut.</p>
<h2>Paket yang dibuat agar semuanya saling cocok</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/50-universal-characters/" title="Spike 50 Karakter Universal" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/50-universal-characters/" target="_blank">Buka Spike 50 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=50-universal-characters">Lihat kode sumber</a></p>
<p>Quaternius menyediakan empat aset yang kesesuaiannya nyaris mencurigakan: Universal Base Characters dengan tubuh laki-laki dan perempuan, ditambah delapan gaya rambut dan dua set alis; Modular Character Outfits yang dibagi menjadi bagian tubuh, lengan, kaki, dan alas kaki dengan aksesori seperti pelindung bahu dan tudung; serta Universal Animation Library paket satu dan dua, dengan total 262 klip yang mencakup pergerakan, pertarungan, memanjat, bertani, memancing, gerakan diam, dan gerakan sosial. Pemeriksaan terhadap glTF-nya mengungkap alasan semuanya cocok: setiap mesh dalam keempat paket tersebut di-rig ke skeleton bergaya UE5 dengan 65 joint yang sama, nama joint yang sama, bind pose yang sama, mulai dari root melalui pelvis dan tulang belakang hingga kepala, lengan simetris dengan lima belas joint jari di setiap sisi, serta kaki simetris. Tidak diperlukan retargeting. Ini benar-benar kebalikan dari masalah retargeting tiga skeleton pada Spike 35, ketika rig wajah dengan 213 bone harus bekerja dengan rig Mixamo 65 bone. Di sini, keempat paket tersebut memang sengaja dibuat menggunakan skeleton milik pustaka animasi, dan kecocokannya sempurna.</p>
<p>Hal itu mengubah spike ini menjadi latihan binding, bukan persoalan pipeline animasi. Layer dasar memuat glTF tubuh, mengkloning scene dengan <code>SkeletonUtils.clone</code> agar setiap karakter memperoleh instance skeleton baru alih-alih meneruskan perubahan bone kembali ke scene cache milik loader, lalu menyimpan skeleton 65 bone tersebut sebagai skeleton kanonis bersama objek armature yang menjadi root animasi.</p>
<h2>Melakukan rebinding mantel ke tubuh</h2>
<p>Trik yang membuat semuanya berfungsi adalah bahwa mesh pakaian tidak bisa begitu saja dipindahkan parent-nya ke dalam scene, karena mesh itu masih mereferensikan bone dari glTF-nya sendiri, yang berada dalam subtree berbeda. Setiap bagian modular—tubuh petani atau kaki penjaga hutan—hadir sebagai SkinnedMesh tersendiri dengan kloning armature yang sama. Proses binding menelusuri bone milik skeleton sumber dalam urutan aslinya, mencari setiap bone berdasarkan nama di skeleton kanonis, lalu membuat <code>Skeleton</code> baru dari bone yang telah di-rebind tersebut sambil menggunakan kembali matriks bind-inverse dari sumber. Setelah itu, proses tersebut memanggil <code>SkinnedMesh.bind</code> dengan matriks bind identitas milik sumber. Seusai binding, mesh dilepaskan dari scene sumbernya dan ditempatkan langsung di bawah root karakter. Karena matriks bind menyimpan transformasi dunia pada saat binding dan root berada pada identitas, transformasi dunia milik mesh itu sendiri tidak pernah memengaruhi hasil, dan skinning sepenuhnya berlangsung melalui bone yang kini digunakan bersama.</p>
<p>Rambut dan alis juga merupakan slot, dan keduanya mengoreksi asumsi yang keliru. Struktur folder menyebutkan &quot;rigged to head bone,&quot; yang mengisyaratkan bahwa rambut adalah mesh statis yang ditempatkan sebagai child dari kepala dengan offset yang sudah di-bake. Ternyata tidak. Setiap file rambut adalah SkinnedMesh yang diberi weight di seluruh 65 joint, dengan weight rambut panjang merambat ke bagian atas tulang belakang dan leher agar rambut menjuntai ketika karakter menunduk. Jadi, rambut menempuh jalur rebinding berdasarkan nama yang sama seperti bagian pakaian lainnya. Satu-satunya kasus khusus adalah slot tubuh pakaian: saat dipasang, mesh tubuh dasar disembunyikan agar tidak menembus pakaian, sementara lengan, kaki, alas kaki, dan aksesori cukup ditumpuk karena paket tersebut dirancang agar semuanya bisa digunakan bersama tubuh dasar yang tetap terlihat di bagian tempat pakaian membiarkan kulit terbuka.</p>
<h2>262 animasi secara gratis</h2>
<p>Setelah skeleton digunakan bersama, animasi hampir terasa antiklimaks. Kedua GLB pustaka dimuat, klip-klipnya digabungkan menjadi satu daftar bernama, dan nama track dalam klip tersebut mereferensikan nama joint yang persis sama melalui <code>bone.position</code>, <code>bone.quaternion</code>, dan <code>bone.scale</code>. Sebuah <code>AnimationMixer</code> yang berakar pada armature karakter menemukan bone tersebut berdasarkan nama dan menggerakkannya secara langsung, dengan crossfade saat berganti. Panel kanan viewer menampilkan daftar seluruh 262 klip yang dapat difilter, lengkap dengan label sumber, sehingga pencarian &quot;fish&quot; menampilkan semua animasi memancing dari kedua pustaka. Pencahayaan tiga titik standar dengan bayangan lembut, grid polar di bawah kaki, dan tone mapping ACES menjaga tekstur dasar bergaya tetap mudah dibaca tanpa menghilangkan detail bayangan pada bodysuit gelap.</p>
<p>Dampaknya terhadap pengurangan risiko produk sangat besar. Fitur kustomisasi avatar dapat diluncurkan dengan paket CC0 tanpa pekerjaan rigging dan tanpa pembuatan animasi: masukkan keempat paket, hubungkan UI lemari pakaian, dan langsung tersedia variasi sekitar enam pakaian dikalikan delapan gaya rambut, dua jenis kelamin, dan 262 animasi. Skeleton dengan 65 joint cukup kecil sehingga biaya GPU skinning dapat diabaikan, dan pekerjaan batched skinning dari Spike 45 sudah mampu menangani lebih dari 200 avatar dengan rig sebesar ini. CC0 tidak memiliki batasan penggunaan, sehingga aman untuk penggunaan komersial pada platform kreator berbayar. Pertanyaan terbuka yang tersisa adalah pakaian yang diunggah sendiri, yang merupakan masalah Fase 3 dan dapat diselesaikan melalui retargeting saat unggahan ke skeleton kanonis ini—kebalikan dari retargeting runtime pada Spike 35. Ukuran asetnya sekitar 147 MB di disk dalam bentuk PNG 2K mentah dan GLB animasi tanpa kompresi, yang dalam produksi dapat diperkecil menjadi sekitar 30 MB menggunakan kompresi tekstur KTX2 dan satu tahap pemrosesan dengan gltf-transform.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Satu skeleton kanonis untuk seluruh paket.</strong> Empat paket Quaternius (tubuh dasar, pakaian modular, dan dua pustaka animasi) semuanya di-rig ke skeleton bergaya UE5 dengan 65 joint yang identik, nama joint yang sama, dan bind pose yang sama, sehingga penggabungannya tidak memerlukan retargeting. Mengkloning tubuh dasar dengan <code>SkeletonUtils.clone</code> memberi setiap karakter instance skeleton baru alih-alih mengubah scene cache milik loader.</p>
<p><strong>Rebinding skeleton berdasarkan nama.</strong> Setiap bagian modular menyertakan SkinnedMesh sendiri yang mereferensikan armature-nya sendiri. Proses rebinding menelusuri bone sumber secara berurutan, memetakan masing-masing berdasarkan nama ke skeleton kanonis, membuat <code>Skeleton</code> baru dengan menggunakan kembali bind-inverse dari sumber, lalu memanggil <code>SkinnedMesh.bind</code> dengan matriks bind identitas. Setelah itu, mesh ditempatkan di bawah root karakter bersama agar skinning sepenuhnya berjalan melalui bone yang digunakan bersama. Slot tubuh pakaian menyembunyikan tubuh dasar untuk mencegah clipping; slot lainnya ditumpuk.</p>
<p><strong>Rambut sebagai slot ber-skinning.</strong> Rambut bukan attachment statis pada bone kepala, melainkan SkinnedMesh yang diberi weight di seluruh 65 joint. Rambut panjang diberi weight hingga bagian atas tulang belakang dan leher agar menjuntai saat karakter menunduk. Rambut menempuh jalur rebinding yang sama seperti bagian pakaian.</p>
<p><strong>Retargeting animasi berbasis nama secara gratis.</strong> Klip Animation Library mereferensikan joint berdasarkan nama yang persis sama, sehingga <code>AnimationMixer</code> yang berakar pada armature bersama dapat menggerakkan seluruh 262 klip secara langsung dengan crossfade, tanpa retargeting per klip. Lisensi CC0 mencakup penggunaan komersial, dan jumlah joint yang kecil membuat GPU skinning cukup murah untuk menggunakan kembali jalur batched skinning dari Spike 45. Lihat <a href="/id/guides/landscape-generation-browser#gpu-driven-lod-with-webgpu">LOD berbasis GPU</a>.</p>
<hr>
<p>Bagian 25 dari 29.
Sebelumnya: <a href="/id/blog/2026-05-09-open-world-browser-part-24-persistence-and-wind">Bagian 24 - Menyimpan dunia, dan angin yang bisa dilihat</a>
Berikutnya: <a href="/id/blog/2026-05-12-open-world-browser-part-26-water">Bagian 26 - Air yang tetap meyakinkan pada setiap skala</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 24: Menyimpan dunia dan angin yang terlihat]]></title>
            <link>https://app.cinevva.com/id/blog/2026-05-09-open-world-browser-part-24-persistence-and-wind</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-05-09-open-world-browser-part-24-persistence-and-wind</guid>
            <pubDate>Sat, 09 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 47 membuat perubahan dunia tersimpan permanen: sebuah Durable Object yang mengatur kepemilikan, menyimpan blob biner per chunk, dan menyelaraskan terrain setiap peer melalui protokol pengeditan komutatif. Spike 49 mem-port shader angin Godot milik Quaternius ke TSL secara akurat, lalu memburu masalah kompilasi ulang per frame yang menurunkan scene hingga 1 fps.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 24: Menyimpan dunia dan angin yang terlihat</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru di sini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan ini menjelaskan apa itu spike dan menautkan semua bagiannya.</p>
<p><a href="/id/blog/2026-05-08-open-world-browser-part-23-avatars-and-voice">Bagian 23</a> menempatkan orang-orang di dalam dunia dan memberi mereka suara. Bagian ini membahas cara membuat dunia mengingat apa yang mereka lakukan terhadapnya, serta membuatnya terasa hidup ketika tak seorang pun menyentuhnya. Spike 47 membahas persistensi: kreator membentuk terrain dan menempatkan prop, lalu perubahan tersebut tetap ada setelah pemuatan ulang, disinkronkan ke setiap peer lain, dan diatur dengan rapi ketika dua orang mengedit secara bersamaan. Spike 49 membahas angin: mem-port shader vegetasi dari sebuah paket alam bergaya agar pepohonan, semak-semak, dan rumput bergerak seperti yang dimaksudkan oleh senimannya—yang ternyata lebih banyak menjadi pertarungan melawan compiler shader daripada melawan perhitungannya.</p>
<h2>Dunia yang mengingat</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/47-world-persistence/" title="Spike 47 Persistensi Dunia" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/47-world-persistence/" target="_blank">Buka Spike 47 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=47-world-persistence">Lihat kode sumber</a></p>
<p>Skenarionya adalah sesi pembuatan bersama. Pemain menjelajahi dunia, menempatkan prop dengan sekali klik, menghapusnya dengan klik kanan, dan membentuk permukaan tanah dengan menyeret kuas, baik untuk menaikkan dan menurunkan heightmap maupun mengukir gua volumetrik melalui terrain SDF yang mengalihkan sebuah chunk ke marching cubes. Semua yang mereka lakukan disimpan secara persisten di <code>WorldChunkDO</code> Cloudflare, sebuah Durable Object otoritatif-server yang didukung oleh penyimpanan SQLite-nya sendiri. Klien tidak menulis state secara langsung. Mereka mengirimkan intent, DO mengatur dan menyiarkan hasilnya, dan DO menjadi satu-satunya sumber kebenaran. Dengan demikian, peserta baru menerima snapshot dan masuk ke dunia yang persis sama dengan yang dilihat semua orang lain.</p>
<p>Dua detail persistensi terbukti sangat berguna. Terrain tidak disimpan sebagai log peristiwa yang harus diputar ulang saat bergabung; terrain disimpan sebagai blob biner per chunk yang menjadi sumber kebenaran dan diunggah ketika stroke berakhir. Dengan begitu, peserta baru langsung memuat byte yang sudah di-commit alih-alih menjalankan ulang ribuan sampel kuas. Blob tersebut juga menggunakan satu storage key per chunk, bukan satu baris besar, karena satu chunk SDF berukuran 168 KB dan DO memiliki batas 2 MB per baris. Indeks chunk melacak key yang tersedia agar DO dapat memuat kembali seluruh peta ketika aktif lagi. Identitas ditangani dengan dua jenis penyimpanan di sisi klien: id pemain disimpan di <code>sessionStorage</code> sehingga dua tab menjadi dua peer berbeda, bukan satu peer yang menimpa dirinya sendiri di peta pemain milik DO, sedangkan nama tampilan disimpan di <code>localStorage</code> agar perubahan nama di satu tab diterapkan ke semua tab.</p>
<h2>Membuat pengeditan serentak mencapai hasil yang sama</h2>
<p>Bagian yang benar-benar sulit dari pembuatan dunia multipemain adalah apa yang terjadi ketika dua orang mengedit area permukaan tanah yang tumpang tindih pada saat yang sama. Spike ini membagi pengeditan berdasarkan sifat aljabarnya. Operasi aditif—menaikkan dan menurunkan heightmap serta menambah dan mengurangi SDF—bersifat komutatif: menerapkannya dalam urutan apa pun menghasilkan hasil yang sama. Karena itu, operasi tersebut menggunakan jalur optimistic stamp, tempat setiap klien menerapkan perubahan secara lokal dan mengirim stamp-nya, lalu DO menyiarkannya kepada semua orang tanpa koordinasi. Urutan benar-benar tidak berpengaruh, jadi tidak ada yang perlu dikoordinasikan.</p>
<p>Operasi yang bergantung pada urutan—smooth dan flatten—menjadi kasus yang menarik. Desain pertama menggunakan kunci wilayah: klien meminta kunci saat pointer ditekan, DO menyetujui atau menolaknya, klien menampung sampel selama penekanan, lalu ketika pointer dilepas, DO menerapkan seluruh stroke secara atomik. Cara ini berfungsi, tetapi memerlukan protokol terpisah dengan TTL kunci serta perjalanan bolak-balik untuk persetujuan atau penolakan. Solusi lebih bersih yang menggantikannya adalah delta yang telah dihitung sebelumnya: pihak yang memulai menjalankan kuas smooth atau flatten secara lokal, lalu mengirim daftar delta per sel yang dihasilkan, dan setiap peer cukup menambahkan delta tersebut ke selnya sendiri tanpa menghitung ulang apa pun. Cara ini mengubah operasi yang bergantung pada urutan menjadi operasi komutatif dengan membekukan hasilnya di sumber. Dengan demikian, seluruh sistem pengeditan berjalan pada satu protokol komutatif yang seragam, dengan konvergensi identik dan tanpa kunci sama sekali. Kunci prop tetap dipertahankan karena alasan berbeda: penguncian per record menggantikan penghapusan khusus pemilik, sehingga peer mana pun dapat menghapus prop apa pun kecuali seseorang telah menguncinya, dan hanya pengunci yang dapat melepaskan kunci tersebut. Undo dan redo bekerja dengan mengizinkan klien menentukan id prop sebelum menempatkannya. Dengan begitu, klien mengetahui id tersebut sebelum echo dari server dan dapat membalik tindakannya sendiri secara deterministik. WebSocket yang berhibernasi membuat room yang tidak aktif tetap gratis sepanjang waktu, sifat yang sama yang membuat relay avatar pada bagian sebelumnya berbiaya rendah.</p>
<h2>Angin yang di-port secara akurat, lalu dilawan</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/49-gpu-wind-props/" title="Spike 49 Prop Angin GPU" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/49-gpu-wind-props/" target="_blank">Buka Spike 49 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=49-gpu-wind-props">Lihat kode sumber</a></p>
<p>Spike 49 mengambil Stylized Nature MegaKit milik Quaternius dan mem-port sistem anginnya ke stack kami. Paket tersebut menyertakan empat shader Godot sumber, dan langkah yang tepat adalah menerjemahkannya secara akurat, bukan menciptakannya kembali. Bark memiliki fungsi vertex kosong, sehingga batang pohon tetap kaku; percobaan procedural mask sebelumnya membuat batang pohon ikut bergoyang, dan solusinya cukup dengan tidak menerapkan angin pada bark sama sekali. Daun mendapatkan goyangan kacau per vertex dari hash pulsa segitiga yang diberi mask berdasarkan ketinggian, sehingga tajuk bergerak sementara pangkalnya tetap tertanam. Dedaunan dasar mendapatkan goyangan sin/cos yang dimodulasi noise dalam world space. Rumput adalah dedaunan dasar ditambah ayunan garis angin, dengan mengambil sampel dari tekstur noise yang bergulir melalui kurva pangkat sehingga hanya pita terang pada tekstur yang berkontribusi. Ini menghasilkan riak terlihat yang bergerak melintasi padang rumput. Dispatch mengikuti konvensi penamaan material milik paket itu sendiri, sehingga material bernama <code>Leaves_Birch</code> diarahkan ke jalur daun dan <code>Grass_Common</code> ke jalur rumput, tanpa perlu menebak.</p>
<p>Salah satu kejutan dari proses port ini adalah warna daun tidak berasal dari tekstur. Quaternius membangun tampilan daun sepenuhnya dari gradien vertikal dan tepian Fresnel: albedo merupakan campuran dari warna tambahan di bagian bawah tajuk ke warna daun di bagian atas berdasarkan ketinggian, dengan tint subsurface scattering yang ditambahkan sebagai emission dan diskalakan oleh suku Fresnel $(1 - \mathbf{N}\cdot\mathbf{V})^3$. Itulah sebabnya pass bertekstur biasa tampak datar. Warnanya berasal dari gradien dan tepian, bukan dari map yang dilukis. Port ini membaca atribut vertex <code>heightFactor</code> yang telah di-bake, bukan nilai Y lokal mentah, dan menormalisasikannya per kelompok daun pada waktu pemuatan berdasarkan Y world-space. Dengan demikian, gradien dan mask angin berperilaku dengan benar, terlepas dari bagaimana impor FBX memutar sumbu lokal setiap mesh. Konstanta warna Godot ditandai sebagai sRGB dan dikonversi ke linear sebelum diterima shader, sehingga port ini melakukan konversi yang sama alih-alih memasukkan angka sRGB terang sebagai linear dan membuat dedaunan tampak pudar.</p>
<h2>Kompilasi ulang yang menghabiskan frame rate</h2>
<p>Alasan fitur ini pertama-tama dikirimkan dengan baseline FBX, sementara seluruh set material angin disisihkan dalam file <code>.bak</code>, adalah bug kompilasi ulang per frame yang menurunkan scene hingga sekitar 1 fps. Menambahkan TSL kustom di atas material yang dimuat dari FBX memicu Three.js untuk membangun ulang program shader setiap frame, dengan <code>needsUpdate</code> yang seolah-olah terus aktif. Pendekatan diagnostiknya adalah menyederhanakan setiap material dedaunan menjadi pass bertekstur biasa tanpa node kustom, lalu mengamati apakah loop kompilasi ulang tetap terjadi. Jika berhenti, graph kustomlah penyebabnya; jika berlanjut, penyebabnya berada di hulu, pada setup material FBX atau Three.js itu sendiri. Perbaikan yang memungkinkan shader sebenarnya digunakan kembali adalah mengikat setiap perbedaan per material—warna daun, warna SSS, strength, dan blend—sebagai uniform. Dengan begitu, semua aset daun berbagi satu program yang telah dikompilasi, alih-alih compiler menghasilkan shader baru untuk setiap kombinasi warna unik dan membuat antrean kompilasi terus bergejolak.</p>
<p>Dua bagian lain juga layak dipertahankan. Rumput dirender sebagai satu <code>InstancedMesh</code> per file sumber, dan anginnya dihitung dalam world space karena fase sin bergantung pada posisi dunia. Namun, displacement harus diterapkan dalam local space sebelum instance matrix dijalankan, sementara WGSL tidak memiliki <code>inverse()</code> yang dapat dipanggil. Untuk instance matrix yang terdiri dari translasi, rotasi Y, dan skala seragam, invers matriks 3×3 bagian atas hanyalah transposenya yang dibagi dengan kuadrat skala. Karena itu, shader mengalikan displacement dunia dengan model matrix yang ditransposisi dan membaginya dengan kuadrat panjang kolom pertama matriks, sehingga skala dapat diperoleh kembali tanpa akar kuadrat. Setelah transformasi vertex menerapkan kembali matriks tersebut, gerakannya mendarat di world space persis seperti yang dirancang, terlepas dari rotasi atau skala setiap rumpun. Setiap rumpun juga menjalankan frustum cull GPU per vertex: pusat instance diproyeksikan ke clip space, dan jika berada di luar frustum beserta marginnya, setiap vertex diciutkan ke titik asal lokal sehingga ketiga vertex dari setiap segitiga berhimpit. Rasterizer membuang segitiga degeneratif tersebut, dan tidak ada pekerjaan fragment, alpha-test, maupun shadow untuk rumput di luar layar. Teknik ini ditumpuk di atas cull kasar bounding sphere per chunk yang sudah dilakukan Three.js, dan dibangun menggunakan <code>step</code> bertipe float, bukan boolean, agar dapat langsung dikalikan ke dalam position mix.</p>
<h2>Teknologi yang dibahas dalam bab ini</h2>
<p><strong>Persistensi dunia otoritatif-server.</strong> Sebuah Durable Object <code>WorldChunkDO</code> mengatur penempatan prop dan pengeditan terrain, menyimpan blob biner per chunk sebagai sumber kebenaran (sehingga peserta baru memuat byte yang telah di-commit alih-alih memutar ulang log peristiwa), serta menggunakan satu storage key per chunk agar tetap berada di bawah batas 2 MB per baris milik DO. Id pemain disimpan di <code>sessionStorage</code> agar setiap tab menjadi peer berbeda; nama tampilan disimpan di <code>localStorage</code> agar perubahan nama diterapkan ke semua tab.</p>
<p><strong>Konvergensi pengeditan komutatif.</strong> Operasi terrain aditif (naik/turun, tambah/kurang SDF) bersifat komutatif dan menggunakan jalur optimistic stamp tanpa koordinasi. Operasi yang bergantung pada urutan (smooth, flatten) dibuat komutatif dengan mengirim delta per sel yang telah dihitung sebelumnya, alih-alih memperoleh kunci wilayah. Dengan demikian, seluruh sistem mencapai hasil yang sama melalui satu protokol seragam tanpa kunci. Kunci prop per record menggantikan penghapusan khusus pemilik, dan id objek yang ditentukan klien memungkinkan undo/redo deterministik sebelum echo server tiba. Lihat <a href="/id/guides/landscape-generation-browser#gpu-driven-lod-with-webgpu">LOD berbasis GPU</a>.</p>
<p><strong>Port shader yang akurat dari Godot ke TSL.</strong> Empat shader angin sumber milik Quaternius diterjemahkan baris demi baris: bark yang kaku, goyangan daun dengan mask berdasarkan ketinggian, goyangan dedaunan dalam world space, dan rumput dengan ayunan garis angin yang bergulir, semuanya di-dispatch berdasarkan konvensi penamaan material milik paket tersebut. Warna daun berasal dari gradien ketinggian ditambah tepian SSS yang digerakkan Fresnel, bukan dari tekstur, dan konstanta authoring sRGB dikonversi ke linear agar tampilannya sesuai dengan render referensi.</p>
<p><strong>Menghindari kompilasi ulang shader per frame.</strong> Menambahkan TSL kustom pada material FBX dapat membuat <code>needsUpdate</code> terus aktif dan membangun ulang program setiap frame, sehingga performa merosot hingga ~1 fps. Mengikat setiap perbedaan per material sebagai uniform memungkinkan semua varian berbagi satu program yang telah dikompilasi, alih-alih menghasilkan shader baru untuk setiap set parameter unik. Pass diagnostik bertekstur biasa mengisolasi apakah penyebabnya adalah graph kustom atau setup di hulu.</p>
<p><strong>Angin world-space pada dedaunan terinstansiasi.</strong> Angin rumput dihitung dalam world space dan ditransformasikan kembali ke local space dengan invers yang diturunkan secara manual (transpose dibagi kuadrat skala), karena WGSL tidak memiliki <code>inverse()</code>. Frustum cull GPU per vertex menciutkan rumpun di luar layar menjadi segitiga degeneratif agar tidak ada pekerjaan fragment atau shadow yang dijalankan, sebagai lapisan tambahan di atas cull bounding sphere per chunk milik Three.js.</p>
<hr>
<p>Bagian 24 dari 29.
Sebelumnya: <a href="/id/blog/2026-05-08-open-world-browser-part-23-avatars-and-voice">Bagian 23 - Lima puluh avatar dan satu suara di dalam room</a>
Berikutnya: <a href="/id/blog/2026-05-10-open-world-browser-part-25-universal-characters">Bagian 25 - Satu skeleton, setiap pakaian</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 23: Lima puluh avatar dan satu suara di ruangan]]></title>
            <link>https://app.cinevva.com/id/blog/2026-05-08-open-world-browser-part-23-avatars-and-voice</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-05-08-open-world-browser-part-23-avatars-and-voice</guid>
            <pubDate>Fri, 08 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 45 memangkas beban JS per frame untuk 50 karakter dari 13 md menjadi satu draw call dengan skinning GPU secara batch, dan menghabiskan dua jam memburu error WGSL yang ternyata disebabkan oleh morph target. Spike 46 membangun suara berbasis kedekatan dengan audio spasial HRTF, lalu menghapus separuh rantai audio agar sesuai dengan yang benar-benar digunakan Meet dan Teams.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 23: Lima puluh avatar dan satu suara di ruangan</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Salah Satu Pendiri Cinevva</em></p>
<p>Baru di sini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan ini menjelaskan apa itu spike dan menautkan semua bagiannya.</p>
<p><a href="/id/blog/2026-05-07-open-world-browser-part-22-clouds-and-meshlets">Bagian 22</a> menempatkan langit di atas dunia. Bagian ini menempatkan orang-orang di dalamnya. Dunia terbuka orang ketiga ingin menampilkan lebih dari 50 karakter pada waktu tertentu, dan ingin mendengar mereka yang berdiri di dekat Anda. Spike 45 membahas sisi rendering: memasukkan avatar animasi sebanyak itu ke GPU tanpa membebani main thread secara berlebihan. Spike 46 membahas sisi audio: suara peer-to-peer yang menggeser kanal dan meredam volume sesuai posisi, disetel agar terdengar seperti panggilan video biasa, bukan demo teknologi.</p>
<h2>Satu draw call untuk lima puluh penari</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/45-avatar-network-sync/" title="Spike 45 Sinkronisasi Jaringan Avatar" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/45-avatar-network-sync/" target="_blank">Buka Spike 45 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=45-avatar-network-sync">Lihat kode sumber</a></p>
<p>Jalur bawaan Three.js memberikan setiap karakter <code>SkinnedMesh</code> sendiri, <code>AnimationMixer</code> sendiri, pengunggahan matriks tulang sendiri, dan draw call sendiri. Dengan 50 avatar di Mac lokal, beban ini mencapai sekitar 13 md overhead JavaScript murni per frame sebelum GPU melakukan apa pun. Pertanyaan pengurangan risiko untuk seluruh jalur multipemain adalah apakah satu arsitektur skinning secara batch dapat mengendalikan beban tersebut dan berskala linear terhadap jumlah karakter.</p>
<p>Jawabannya adalah memisahkan tempat animasi dihitung dan tempat animasi digambar. Tiga kelas karakter berbagi satu templat FBX. Pemain lokal merupakan <code>Avatar</code> biasa, yaitu klona kerangka lengkap dengan mixer-nya sendiri dan jalur Three.js standar, karena jumlahnya selalu hanya satu. Setiap peer jarak jauh merupakan <code>VirtualSkeleton</code>: juga klona lengkap dengan mixer sendiri yang menjalankan klip yang sama, tetapi setiap node <code>SkinnedMesh</code> langsung dihapus setelah kloning sehingga hanya tulangnya yang tersisa. Objek ini tidak pernah masuk ke scene. Pada setiap frame, setelah mixer diperbarui dan matriksnya stabil, objek ini mengemas <code>(bone.matrixWorld × boneInverse)</code> untuk seluruh 100 tulang ke dalam satu slot pada <code>Float32Array</code> bersama. <code>BatchSkinnedRenderer</code> kemudian memiliki satu <code>InstancedMesh</code> untuk setiap bagian geometri, yang semuanya membaca dari satu <code>StorageBufferAttribute</code> berisi matriks tulang dengan ukuran <code>maxInstances × numBones × mat4</code>, yaitu 60 × 100 × 64 = 384 KB. Sebuah <code>MeshStandardNodeMaterial</code> dengan <code>positionNode</code> dan <code>normalNode</code> khusus membaca empat pengaruh tulang per vertex langsung dari storage buffer tersebut. Hasilnya adalah satu pengunggahan storage dan satu draw call per bagian geometri untuk seluruh kerumunan, berapa pun jumlah orang di dalamnya. Skinning berjalan di vertex shader, sedangkan biaya JavaScript per avatar turun menjadi menjalankan mixer dan menyalin 100 matriks.</p>
<p>HUD yang mengukurnya juga harus dibangun ulang. Versi lama menandai &quot;melebihi anggaran&quot; ketika waktu GPU seluruh frame melewati 3 md, tetapi frame tersebut selalu mencakup shadow map, permukaan tanah, dan skinned mesh lengkap milik pemain lokal, yang bersama-sama membutuhkan 3 hingga 5 md pada perangkat keras nyata, berapa pun jumlah peer sintetis yang ada. Solusinya adalah anggaran yang mengalibrasi dirinya sendiri: selama belum ada avatar batch, HUD mengambil waktu GPU aktif sebagai baseline melalui EMA cepat, lalu membekukan baseline tersebut dan menaikkan anggaran secara linear sebesar 0,06 md untuk setiap avatar tambahan setelah avatar sintetis muncul. HUD menampilkan PASS saat idle di setiap mesin dan memperketat batas secara proporsional seiring membesarnya kerumunan.</p>
<h2>Bug-nya adalah wajah yang tak terlihat</h2>
<p>Pengujian pertama di Chrome menampilkan bayangan keperakan di tanah tanpa avatar sama sekali, disertai error parsing WGSL: <code>cannot index type 'f32'</code> pada baris yang mencoba mengakses <code>object.nodeUniform2[i]</code>, padahal uniform tersebut dideklarasikan sebagai skalar. Bagian jujur dari kisah ini adalah bahwa perbaikan pertama ternyata salah, tetapi tetap berhasil. Dugaan awalnya adalah jalur instance matrix milik <code>InstancedMesh</code> menghasilkan kode yang bermasalah, dan menggantinya dengan <code>StorageInstancedBufferAttribute</code> membuat error tersebut hilang di Chrome. Namun, error itu hilang karena jalur baru menghasilkan kode shader yang berbeda, bukan karena penyebabnya telah ditangani. Ini adalah jenis perbaikan yang paling berbahaya.</p>
<p>Penyebab sebenarnya adalah morph target. 3MIKE.fbx menyertakan ekspresi wajah blend-shape, geometri hasil kloning mewarisi <code>morphAttributes</code>, dan <code>MorphNode.setup()</code> milik Three.js mendeklarasikan <code>morphTargetInfluences</code> sebagai <code>float</code> skalar lalu mencoba memanggil <code>.element(i)</code> di dalam loop hasil sintesis. Itulah operasi subskrip skalar yang ditolak compiler. Perbaikannya hanya satu baris, yaitu mengosongkan <code>geometry.morphAttributes = {}</code> pada geometri yang tidak menggunakan morph, sehingga Three.js tidak pernah menyisipkan <code>MorphNode</code>. Perbaikan Chrome yang tidak disengaja itu dipertahankan untuk sementara waktu, lalu menimbulkan masalah: di Safari, jalur storage-instanced menghasilkan <code>Vertex buffer is not big enough</code> sebanyak 256 kali karena backend WebGPU Safari tidak menerjemahkannya dengan baik. Mengembalikannya adalah keputusan yang tepat, dan storage buffer matriks tulang biasa, yang merupakan bagian inti WebGPU alih-alih jalur instance hasil generasi, berfungsi dengan baik di semua browser. Pelajarannya patut diingat: ketika sebuah perbaikan berhasil di satu browser dan Anda tidak dapat menjelaskan mekanismenya, berarti Anda hanya menambal gejala, jadi bacalah WGSL yang benar-benar dihasilkan. Shim <code>getCompilationInfo()</code> yang kemudian ditambahkan dalam spike mengubah pesan umum Three.js, <code>&quot;module is not valid&quot;</code>, menjadi error Tint yang sebenarnya dan berkali-kali membuktikan manfaatnya.</p>
<p>Di sebelahnya terdapat trik terkait untuk menghindari intervensi framework. Three.js mendeteksi nama atribut standar <code>skinIndex</code> dan <code>skinWeight</code>, lalu mencoba menyisipkan <code>SkinningNode</code> sendiri, bahkan pada <code>InstancedMesh</code> yang <code>positionNode</code> khususnya sudah melakukan skinning. Mengganti nama atribut tersebut menjadi <code>boneIndex</code> dan <code>boneWeight</code> menyembunyikannya dari framework, lalu TSL khusus membacanya dengan nama baru.</p>
<h2>Relay yang melupakan Anda di antara kata-kata</h2>
<p>Versi pertama menyinkronkan peer melalui <code>BroadcastChannel</code>, pengganti dalam browser yang sama dengan format wire dan frekuensi pengiriman sebenarnya, dan komentar protokolnya menjanjikan bahwa peralihan ke transportasi nyata hanya memerlukan perubahan satu baris. Mewujudkan janji itu menghasilkan <code>AvatarRoomDO</code>, Cloudflare Durable Object sepanjang 74 baris yang bahkan tidak mendekode frame biner 36 byte. Objek tersebut meneruskan setiap pesan apa adanya kepada semua peer lain di ruangan, karena id pengirim tertanam di dalam frame dan setiap penerima menyaring echo miliknya sendiri di sisi klien. Relay sama sekali tidak mengetahui identitas. Hibernating WebSockets membuat ruangan idle tidak memerlukan biaya: DO dikeluarkan dari memori di antara pesan, lalu runtime memulihkan socket bertag saat paket berikutnya tiba. Dengan 10 event per detik per peer, jumlahnya menjadi 36.000 permintaan DO per peer-jam, sekitar setengah sen, dengan egress gratis di Cloudflare dan kira-kira 6 hingga 10 kali lebih murah daripada konfigurasi WebSocket AWS yang setara.</p>
<p>Peralihan ini mengungkap bug state machine yang layak dicatat. Seorang pemain jarak jauh terus berjalan setelah mereka berhenti. Permintaan animasi melakukan pemeriksaan terhadap <code>this._state</code>, yaitu klip yang sedang diputar, bukan nama terakhir dalam antrean. Akibatnya, ketika dua pesan jaringan tiba dalam tick yang sama, pertama <code>walk</code> lalu <code>idle</code>, <code>idle</code> dibandingkan dengan state yang belum sempat berubah dan dibuang diam-diam. Peer tersebut terus berjalan selamanya karena paket <code>idle</code> berikutnya dideduplikasi di hulu sebagai sesuatu yang tidak berubah. Perbaikannya adalah selalu menimpa nama yang tertunda dan membiarkan helper transisi menghentikan lebih awal permintaan dengan state yang benar-benar sama, sebagaimana memang sudah dilakukannya. Kelas bug ini bersifat umum: pemeriksaan deduplikasi terhadap nilai acuan yang salah diam-diam menelan input yang justru penting.</p>
<p>Safari membutuhkan dua guard tambahan. Browser ini membuka WebSocket lebih cepat daripada Chrome, sehingga pesan peer masuk yang pertama dapat tiba sebelum batch renderer selesai dibuat dan menyebabkan dereferensi null; membuang pesan saat renderer belum tersedia aman dilakukan karena peer menyiarkan ulang setiap 100 md. Selain itu, <code>'gpu' in navigator</code> mengembalikan true sementara <code>requestAdapter()</code> mengembalikan null, sehingga Three.js diam-diam beralih ke WebGL2. Di sana, rantai skinning storage-buffer tidak memiliki terjemahan yang valid dan memuntahkan error. Memeriksa keberadaan adapter sungguhan dan memastikan backend benar-benar WebGPU mengubah render yang terdegradasi menjadi pesan yang jelas di layar pemuatan. Bahkan ada perbedaan dialek WGSL: Three.js menghasilkan <code>@interpolate(flat, either)</code> modern dengan dua argumen yang belum didukung compiler WebKit. Ini ditambal dengan menulis ulang source shader saat masuk ke <code>createShaderModule</code> untuk menghapus argumen kedua, tanpa biaya apa pun karena interpolasi flat membawa nilai yang sama pada setiap vertex.</p>
<h2>Suara yang bergeser mengikuti ruangan</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/46-proximity-voice/" title="Spike 46 Suara Berbasis Kedekatan" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/46-proximity-voice/" target="_blank">Buka Spike 46 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=46-proximity-voice">Lihat kode sumber</a></p>
<p>Spike 46 adalah suara berbasis kedekatan: WebRTC peer-to-peer dengan audio spasial HRTF, yang cakupannya secara eksplisit ditetapkan agar menyamai kualitas Google Meet dan Microsoft Teams di ruangan yang tenang hingga cukup bising. Sebuah <code>VoiceRoomDO</code> menangani signaling sebagai relay JSON, mengirimkan daftar penghuni kepada setiap peer baru, mengumumkan peer yang bergabung dan keluar, merutekan SDP dan ICE ke satu peer tertentu berdasarkan tag socket, serta menyiarkan pembaruan posisi yang menggerakkan panner spasial. DO tersebut membubuhkan id pengirim pada setiap pesan agar peer tidak dapat menyamar sebagai peer lain, sementara audio itu sendiri tidak pernah melewati DO. Ada satu <code>RTCPeerConnection</code> untuk setiap peer jarak jauh, dan peer dengan id yang lebih kecil secara leksikografis selalu membuat offer agar kedua sisi sepakat tentang siapa yang memulai tanpa implementasi perfect negotiation secara penuh.</p>
<p>Di sisi penerima, audio setiap peer melewati <code>PannerNode</code> yang disetel ke HRTF dengan pelemahan inverse distance, dan <code>AudioListener</code> diperbarui setiap frame berdasarkan posisi dan arah hadap pemain lokal menggunakan <code>forwardX = sin(facing)</code>, <code>forwardZ = cos(facing)</code>, yang sesuai dengan konvensi arah hadap <code>atan2(wx, wz)</code> pada scene. Satu keanehan Chrome menghabiskan waktu satu jam: <code>MediaStream</code> yang hanya digunakan oleh Web Audio terkadang tidak menarik paket, sehingga setiap stream juga dihubungkan ke elemen <code>&lt;audio&gt;</code> tersembunyi yang dibisukan untuk memaksa decoder menjadwalkan pemrosesan. Dari sisi kualitas, browser secara default menggunakan Opus mono sekitar 32 kbps. Karena itu, spike mengubah baris <code>fmtp</code> pada setiap offer dan answer untuk menaikkannya menjadi 128 kbps dengan FEC in-band diaktifkan dan DTX dinonaktifkan, lalu memanggil <code>setParameters</code> dengan bitrate maksimum yang tinggi untuk menjamin encoder benar-benar menggunakan nilai yang diiklankan SDP. FEC memberikan peningkatan audio terbesar kedua setelah kenaikan bitrate, dengan memulihkan kehilangan paket tanpa renegosiasi.</p>
<h2>Menghapus komponen demi audio yang jernih</h2>
<p>Rantai audio yang akhirnya dirilis jauh lebih kecil daripada versi awal saya, dan menyusutkannya merupakan pelajaran yang sebenarnya. Versi pertama memiliki high-pass filter, click limiter yang disetel untuk menangkap suara keyboard, compressor, noise gate, dan crossfade wet-dry, didahului panel mengambang dengan lebih dari dua belas slider. Ketika pengguna melaporkan suara klik keyboard yang terdengar, naluri awalnya adalah menyetel click limiter lebih agresif dan mengurangi dry mix, sebuah tumpukan tambalan. Jawaban strukturalnya adalah bahwa setelah denoiser ML masuk ke dalam rantai, click limiter, gate, dan sebagian besar high-pass menjadi berlebihan, karena RNNoise memang dilatih untuk menangani suara keyboard, tetikus, dan ketikan, sedangkan amplitude clipping hanyalah versi yang lebih buruk untuk pekerjaan yang sama. Klien produksi menggunakan denoise berbasis ML, echo cancellation, automatic gain, dan soft compressor untuk meratakan level, tanpa komponen lain. Jadi empat tahap dihapus, panel slider dihapus, dan opsi &quot;pilih pengurangan noise&quot; juga dihapus, menyisakan satu pipeline tetap.</p>
<p>Setiap tahap yang tersisa harus membuktikan manfaatnya. Echo cancellation browser tetap aktif karena RNNoise tidak menangani echo, dan tanpanya feedback dari speaker ke mikrofon tidak memiliki batas. Noise suppression browser dimatikan karena menumpuknya di atas RNNoise menghasilkan artefak pada konsonan frikatif, jadi hanya satu denoiser yang dipilih. Automatic gain browser tetap aktif karena menonaktifkannya membuat sinyal terlalu pelan untuk diproses compressor, sedangkan <code>DynamicsCompressorNode</code> milik Web Audio tidak memiliki parameter makeup gain sebagai kompensasi; perataan level luas dari browser dan compressor cepat milik spike bekerja pada rentang waktu berbeda dan dapat digunakan bersamaan. RNNoise berjalan dengan 92 persen wet yang dicampur 8 persen dry karena RNNoise dapat meredam secara berlebihan konsonan tak bersuara seperti s, sh, dan f ketika probabilitas suaranya turun, sementara jalur dry yang kecil mempertahankan konsonan tersebut dengan konsekuensi sedikit suara ketikan ikut bocor.
Dua fitur melengkapinya. Push-to-talk tidak mengubah <code>track.enabled</code>, karena tindakan itu membuang semua data yang masih berada dalam buffer pipeline dan memotong suku kata terakhir saat tombol dilepas. Sebagai gantinya, sebuah <code>GainNode</code> di dekat ujung rangkaian melakukan ramp dengan <code>setTargetAtTime</code>: attack cepat agar suku kata pertama tetap terdengar dan release lambat agar konsonan terakhir sempat tersalurkan, sementara track dibiarkan selalu aktif. Selain itu, penundaan siaran lima detik yang diminta sebagai fitur bergaya radio dijalankan melalui jalur bypass dan jalur <code>DelayNode</code> yang di-crossfade bersama, dengan tombol dump yang langsung membisukan output tertunda dan menampilkan hitung mundur di HUD sebelum audio dilanjutkan. Membundel denoiser menjadi kisah kecil tersendiri: worklet RNNoise yang dipublikasikan menggunakan impor bare-specifier yang tidak dapat di-resolve oleh CDN mana pun, sehingga solusinya adalah bundle esbuild lokal yang menghasilkan satu berkas mandiri berukuran 1,9 MB dengan WASM yang disisipkan sebagai base64, di-commit ke repo, dan dirujuk melalui URL relatif terhadap modul agar dapat di-resolve dengan cara yang sama di server pengembangan, build VitePress, dan domain khusus. Jika worklet gagal dimuat, rangkaian tetap menghasilkan audio melalui high-pass dan kompresor biasa, sementara HUD menampilkan kegagalan tersebut dengan warna merah.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>GPU skinning berkelompok untuk kerumunan.</strong> Avatar jarak jauh menjalankan <code>VirtualSkeleton</code> headless (klona penuh dengan mesh ber-skin yang dihapus, tulang dipertahankan, dan mixer tersendiri) yang mengemas <code>bone.matrixWorld × boneInverse</code> untuk setiap tulang ke dalam <code>StorageBufferAttribute</code> bersama. Satu <code>InstancedMesh</code> per bagian geometri membaca matriks tersebut dalam <code>positionNode</code>/<code>normalNode</code> TSL khusus, sehingga seluruh kerumunan hanya memerlukan satu unggahan storage dan satu draw call per bagian, dengan pekerjaan CPU per avatar terbatas pada pembaruan mixer dan penyalinan matriks. Lihat <a href="/id/guides/landscape-generation-browser#gpu-driven-lod-with-webgpu">LOD berbasis GPU</a>.</p>
<p><strong>Membaca WGSL yang dihasilkan, bukan gejalanya.</strong> Error kompilasi <code>cannot index type 'f32'</code> ditelusuri hingga <code>MorphNode</code> Three.js yang mendeklarasikan <code>morphTargetInfluences</code> sebagai skalar lalu mengaksesnya dengan subskrip; masalah ini diperbaiki dengan mengosongkan <code>morphAttributes</code> pada geometri yang tidak menggunakan morph. Perbaikan pertama yang hanya mengubah jalur shader yang dihasilkan menutupi penyebabnya dan kemudian merusak dukungan Safari. Mengganti nama <code>skinIndex</code>/<code>skinWeight</code> menjadi <code>boneIndex</code>/<code>boneWeight</code> menyembunyikan atribut tersebut dari injeksi otomatis <code>SkinningNode</code> milik Three.js sehingga material skinning khusus dapat sepenuhnya menangani perhitungannya.</p>
<p><strong>Relay Durable Object yang berhibernasi.</strong> <code>AvatarRoomDO</code> biner murni meneruskan frame 36 byte ke setiap peer lain tanpa mendekodenya, dengan identitas pengirim disematkan dalam frame dan gema balik ke pengirim sendiri difilter di sisi klien. WebSocket yang berhibernasi membuat ruang yang tidak aktif bebas biaya, dan arsitektur ini memerlukan biaya sekitar setengah sen per jam-peer pada 10 Hz, jauh di bawah harga layanan WebSocket terkelola yang setara. Guard deduplikasi yang membandingkan dengan status animasi yang sedang diputar, bukan status terakhir yang masuk antrean, secara diam-diam membuang pesan berhenti dan membuat pemain jarak jauh terjebak dalam loop berjalan.</p>
<p><strong>Suara proksimitas WebRTC dengan HRTF.</strong> Satu <code>RTCPeerConnection</code> per peer dengan peran offer/answer yang ditentukan berdasarkan urutan ID peer, audio disalurkan melalui <code>PannerNode</code> HRTF dengan <code>AudioListener</code> yang diperbarui setiap frame berdasarkan arah hadap pemain, dan Opus diubah menjadi 128 kbps dengan FEC in-band agar lebih tangguh. Elemen <code>&lt;audio&gt;</code> tersembunyi yang dibisukan memaksa Chrome mengambil paket dari stream yang hanya menggunakan Web Audio.</p>
<p><strong>Rekayasa audio subtraktif.</strong> Menyamai kualitas Meet/Teams berarti mengurangi tahap, bukan menambahkannya: denoise ML ditambah pembatalan gema, penguatan otomatis, dan kompresor halus, tanpa gate maupun click limiter, karena denoiser ML yang dilatih untuk menangani suara keyboard membuat clipping amplitudo tidak lagi diperlukan. Push-to-talk melakukan ramp pada <code>GainNode</code> di ujung rangkaian dengan envelope asimetris alih-alih mengaktifkan atau menonaktifkan track agar suku kata tidak terpotong, dan worklet denoiser dikirim sebagai satu bundle esbuild mandiri untuk menghindari masalah resolusi impor bare-specifier.</p>
<hr>
<p>Bagian 23 dari 29.
Sebelumnya: <a href="/id/blog/2026-05-07-open-world-browser-part-22-clouds-and-meshlets">Bagian 22 - Awan yang dapat disinari, dan culling yang harus diberi data</a>
Berikutnya: <a href="/id/blog/2026-05-09-open-world-browser-part-24-persistence-and-wind">Bagian 24 - Menyimpan dunia, dan angin yang dapat dilihat</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 22: Awan yang bisa diterangi, dan culling yang harus diberi asupan]]></title>
            <link>https://app.cinevva.com/id/blog/2026-05-07-open-world-browser-part-22-clouds-and-meshlets</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-05-07-open-world-browser-part-22-clouds-and-meshlets</guid>
            <pubDate>Thu, 07 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 43 menampilkan langit berbasis fisika dan awan volumetrik dalam waktu kurang dari 2 ms, dengan matahari terbenam yang tidak memerlukan penyetelan untuk setiap waktu. Spike 44 membangun meshlet GPU culling dan menemukan bahwa oklusi Hi-Z hanya bekerja jika occluder cukup besar untuk bertahan dari max-reduce.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 22: Awan yang bisa diterangi, dan culling yang harus diberi asupan</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Salah Satu Pendiri Cinevva</em></p>
<p>Baru mengikuti seri ini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan memuat tautan ke semua bagian.</p>
<p><a href="/id/blog/2026-05-06-open-world-browser-part-21-visibility-buffer">Bagian 21</a> membahas teknik rendering yang tidak memberikan hasil sepadan. Bagian ini memuat satu teknik yang berhasil, serta satu lagi yang memerlukan perbaikan cermat agar bisa berfungsi sama sekali. Spike 43 membahas langit: atmosfer berbasis fisika dan awan volumetrik, fondasi yang membuat sebuah adegan terasa seperti tempat sungguhan, bukan sekadar demo teknologi. Spike 44 membahas GPU culling bergaya meshlet, dengan pelajaran bahwa pengujian oklusi hanya akan sebaik occluder yang diberikan kepadanya.</p>
<h2>Langit dari fisika, bukan gradien</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/43-clouds-atmosphere/" title="Spike 43 Awan dan Atmosfer" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/43-clouds-atmosphere/" target="_blank">Buka Spike 43 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=43-clouds-atmosphere">Lihat kode sumber</a></p>
<p>Hampir setiap efek cuaca sinematik bergantung pada dua bagian infrastruktur: atmosfer berbasis fisika, agar warna langit dan matahari mengikuti waktu berdasarkan fisika, bukan gradien yang disetel manual, serta volume awan volumetrik, agar langit memiliki struktur 3D alih-alih cubemap yang sudah di-bake. Spike 43 membangun tepat kedua hal tersebut di atas stack WebGPU dan TSL yang sudah ada, tanpa tambahan lain, karena setelah keduanya tersedia, bagian lain dari stack cuaca (kabut, god ray, permukaan basah, salju) menjadi serangkaian pengembangan lanjutan yang lebih kecil dan sudah dipahami.</p>
<p>Atmosfernya menggunakan model Hillaire 2020, yaitu sekumpulan lookup table yang dihitung dalam compute shader WGSL. Tabel transmittance mengintegrasikan cahaya matahari melalui profil kepadatan Rayleigh, Mie, dan ozon, lalu dihitung ulang hanya ketika matahari bergerak. Tabel sky-view di-bake ulang setiap frame karena biayanya cukup murah sehingga membatasi pembaruannya tidak sepadan dengan kode tambahan, dengan parameterisasi nonlinier di sekitar horizon untuk menghindari banding. Untuk saat ini, multiple scattering menggunakan pendekatan analitis sebagai pengganti tabel yang semestinya, dan matahari terbenam tetap terlihat tepat, jadi jalan pintas ini tersamarkan dengan baik. Awannya menggunakan ray-march bergaya Schneider Nubis melalui lapisan horizontal, dengan bentuk dari tekstur Perlin-Worley 128³ yang dierosi oleh tekstur Worley 32³. Keduanya di-bake saat startup menggunakan compute tanpa pengambilan data melalui jaringan, lalu diterangi dengan ekstingsi hukum Beer, fungsi fase dua lobus, dan pendekatan powder. Keterkaitan utamanya adalah warna matahari pada awan mengambil sampel dari tabel transmittance yang sama di setiap langkah, sehingga pencahayaan awan mengikuti matahari terbenam tanpa tahap penyetelan kedua.</p>
<p>Pada M1, keseluruhan proses ini selesai dalam 1,1 hingga 2,0 ms dengan awan beresolusi setengah, jauh di bawah anggaran 6 ms, menggunakan sekitar 14 MB memori GPU, dan berjalan di atas 100 FPS. Kedua klaim utama terbukti dalam praktik. Matahari terbenam adalah adegan andalan, momen yang membuat renderer terasa sinematik, dan hasilnya muncul secara alami dari fisika tanpa penyetelan untuk setiap waktu. Ada juga keuntungan tak terduga: dengan lapisan awan yang diparameterkan antara 800 m dan 4.000 m, awan jauh di horizon terlihat seperti jajaran pegunungan gelap dari posisi kamera yang rendah. Hal ini memberi dunia tersebut medan latar tanpa perlu ada yang memodelkan medan latar.</p>
<p>Ada satu catatan arsitektur yang patut dipertahankan. Struktur yang paling alami adalah menggambar langit ke swap chain terlebih dahulu, lalu membiarkan three.js menggambar geometri di atasnya dengan <code>autoClear = false</code>. Cara itu tidak bertahan pada renderer WebGPU di r184, karena flag tersebut tidak mengendalikan color load op seperti pada WebGL, sehingga three.js menimpa langit setiap frame. Solusinya adalah merender three.js ke target offscreen dan melakukan komposit akhir (<code>mix(skyCloud, scene, scene.alpha)</code> lalu ACES lalu sRGB) dalam pass milik kita sendiri yang menguasai swap chain.</p>
<h2>Culling yang hanya sebaik occluder-nya</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/44-meshlet-clusters/" title="Spike 44 Klaster Meshlet" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/44-meshlet-clusters/" target="_blank">Buka Spike 44 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=44-meshlet-clusters">Lihat kode sumber</a></p>
<p>Spike 44 membandingkan performa empat mode rendering: forward biasa, culling klaster CPU, compute culling GPU, serta visibility buffer dengan culling oklusi Hi-Z. Jalur Hi-Z adalah bagian yang menarik, dan ternyata memiliki bug tersembunyi: HUD-nya menyatakan bahwa oklusi aktif, tetapi penghitung &quot;Hi-Z killed&quot; selamanya berada tepat di 0,0%. Frustum culling berfungsi, jadi proses hulu cull shader tidak bermasalah. Bagian oklusinya tidak melakukan apa-apa meskipun tetap menanggung seluruh biayanya.</p>
<p>Pengujian oklusi Hi-Z memproyeksikan bounding box klaster ke layar, memilih level mip pada piramida kedalaman agar persegi panjang di layar berukuran sekitar 2×2 texel, mengambil sampel kedalaman occluder terdalam dalam persegi panjang tersebut, lalu menolak klaster jika titik terdekatnya masih lebih jauh daripada occluder itu. Piramida kedalaman dibangun setiap frame dengan mengisi mip 0 dari opaque-depth pre-pass, lalu melakukan max-reduce ke level-level berikutnya. Opaque pre-pass sengaja hanya menyertakan occluder solid, yaitu tanah dan proksi batang untuk setiap pohon, karena dedaunan dengan alpha test akan menciptakan celah yang mengecoh max-reduce.</p>
<p>Bug-nya bersifat geometris, bukan logis. Proksi batang berupa kotak berukuran 0,5 m × 4 m × 0,5 m. Pada jarak 30 m, proyeksinya di layar hanya sekitar 17 piksel. Namun, klaster rumput berukuran 50 m biasanya memilih mip 5, tempat setiap texel mencakup 32 piksel sumber. Batang selebar 17 piksel tidak sepenuhnya menutupi satu pun texel mip 5, sehingga setiap texel yang menyentuh batang juga menyentuh tanah di sekitarnya. Max-reduce 2×2 pertama memilih nilai kedalaman yang lebih besar, yaitu tanah yang lebih jauh di belakang batang, sehingga kedalaman batang terhapus pada reduksi pertama. Pada mip 5, piramida akhirnya memuat kedalaman tanah hampir di semua tempat, klaster tidak pernah lebih jauh daripada tanah, dan tidak ada apa pun yang pernah dianggap teroklusi.</p>
<p>Solusinya adalah membuat proksi cukup besar untuk mendominasi texel yang ditempatinya, dengan ukuran mengikuti siluet pohon, bukan kayunya. Proksi berukuran sekitar 2 m × 6 m × 2 m masih lebih kecil daripada kanopi sebenarnya, sehingga daun yang terlihat melalui celah tidak mengalami culling berlebihan, tetapi ukurannya cukup besar untuk bertahan dari max-reduce hingga jarak yang relevan, dan penghitung oklusi langsung naik dari nol. Pelajaran ini dapat digeneralisasikan menjadi aturan untuk engine produksi: segala sesuatu yang dipercaya sebagai occluder Hi-Z harus berukuran sesuai siluetnya di layar, karena efektivitas Hi-Z dalam adegan terbuka penuh dedaunan didominasi oleh cakupan occluder pada mip yang relevan, bukan oleh keanggunan matematika pengujian kedalamannya. Oklusi rumput terhadap rumput memang tidak bisa terjadi, karena bilah rumput berada pada kedalaman yang sama dengan tanah di bawahnya. Jadi, keuntungan sebenarnya berasal dari pohon yang mengoklusi dedaunan jauh dan pohon yang mengoklusi pohon lain.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>LUT atmosfer Hillaire 2020.</strong> Tabel transmittance (cahaya matahari melalui profil Rayleigh, Mie, dan ozon) yang dihitung ulang hanya ketika matahari bergerak, ditambah tabel sky-view per frame dengan parameterisasi horizon nonlinier, menghasilkan warna langit dan matahari berbasis fisika yang mengikuti waktu tanpa gradien yang disetel manual. Pendekatan analitis untuk multiple scattering menggantikan tabel lengkap sampai ada artefak yang mengharuskan proses bake yang semestinya. Matahari terbenam muncul secara alami dari fisika tanpa penyetelan untuk setiap waktu.</p>
<p><strong>Awan volumetrik Schneider Nubis.</strong> Ray-march melalui lapisan horizontal, yang dibentuk oleh tekstur Perlin-Worley 128³ hasil bake saat startup dan dierosi oleh tekstur Worley 32³, lalu diterangi dengan ekstingsi hukum Beer, fase dua lobus, serta komponen powder. Mengambil sampel warna matahari pada awan dari tabel transmittance yang sama di setiap langkah membuat pencahayaan awan mengikuti matahari terbit dan terbenam tanpa biaya penyetelan tambahan. Ray-march beresolusi setengah berjalan sekitar 4× lebih murah daripada resolusi penuh tanpa penurunan kualitas yang terlihat pada jarak umum, sebuah kompromi standar untuk produksi.</p>
<p><strong>Mengompositkan WebGPU mentah dengan three.js pada r184.</strong> Menggambar langit ke swap chain dan menggambar geometri three.js di atasnya dengan <code>autoClear = false</code> gagal karena flag tersebut tidak mengendalikan color load op di backend WebGPU. Render three.js ke target offscreen RGBA16F, lalu lakukan <code>mix</code> akhir beserta tone mapping dan sRGB dalam pass yang menguasai swap chain.</p>
<p><strong>Culling oklusi Hi-Z dan penentuan ukuran occluder.</strong> Piramida kedalaman yang dibangun melalui max-reduce memungkinkan GPU cull pass menolak klaster yang titik terdekatnya berada di belakang occluder terdalam dalam persegi panjang layarnya. Pengujian tersebut diam-diam tidak melakukan apa pun jika occluder terlalu kecil untuk mendominasi satu texel pada mip yang dipilih, karena max-reduce pertama mengganti kedalaman occluder dengan latar belakang yang lebih jauh di belakangnya. Occluder harus berukuran sesuai siluetnya di layar, bukan inti fisiknya. Lihat <a href="/id/guides/landscape-generation-browser#gpu-driven-lod-with-webgpu">LOD berbasis GPU</a>.</p>
<hr>
<p>Bagian 22 dari 29.
Sebelumnya: <a href="/id/blog/2026-05-06-open-world-browser-part-21-visibility-buffer">Bagian 21 - Renderer lebih cepat yang ternyata tidak lebih cepat</a>
Berikutnya: <a href="/id/blog/2026-05-08-open-world-browser-part-23-avatars-and-voice">Bagian 23 - Lima puluh avatar dan satu suara di dalam ruangan</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 21: Renderer lebih cepat yang ternyata tidak lebih cepat]]></title>
            <link>https://app.cinevva.com/id/blog/2026-05-06-open-world-browser-part-21-visibility-buffer</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-05-06-open-world-browser-part-21-visibility-buffer</guid>
            <pubDate>Wed, 06 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 40 membuat visibility buffer untuk rerumputan lebat, teknik yang menurut semua orang unggul dalam menangani overdraw, lalu mengukurnya kalah 44% dari forward rendering biasa pada kepadatan tinggi di Apple Silicon. Berikut alasannya dan kapan teknik ini benar-benar layak digunakan.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 21: Renderer lebih cepat yang ternyata tidak lebih cepat</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru mengikuti seri ini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan itu menjelaskan apa yang dimaksud dengan spike dan menautkan semua bagiannya.</p>
<p><a href="/id/blog/2026-05-05-open-world-browser-part-20-parallax-occlusion">Bagian 20</a> menyimulasikan kedalaman permukaan pada quad datar. Bagian ini membahas keputusan arsitektur rendering, dan inilah spike ketika jawaban dari buku teks ternyata keliru untuk perangkat keras kami. Pertanyaannya: untuk rerumputan alpha-tested dengan kepadatan sinematik di bawah kamera orang ketiga, apakah kami memerlukan visibility buffer sebelum meningkatkan kepadatan untuk 200 pemain? Saran yang umum beredar adalah ya, dengan sangat tegas. Kami membuatnya, mengukurnya, dan jawabannya ternyata tidak.</p>
<h2>Teknik yang direkomendasikan semua orang</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/40-visibility-buffer/" title="Visibility Buffer Spike 40" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/40-visibility-buffer/" target="_blank">Buka Spike 40 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=40-visibility-buffer">Lihat kode sumber</a></p>
<p>Visibility buffer membagi rendering menjadi dua pass. Pass 1 merasterisasi geometri dan hanya menulis ID segitiga serta instans ke target integer ringkas beserta depth, tanpa melakukan shading sama sekali. Pass 2 adalah pass layar penuh yang membaca ID pada setiap piksel yang tercakup, mengambil kembali vertex segitiga tersebut, merekonstruksi atribut hasil interpolasi, lalu melakukan shading tepat satu kali pada setiap piksel yang terlihat. Keunggulan yang dijanjikan adalah penolakan overdraw secara sempurna: depth test dijalankan terhadap fragmen yang belum mengerjakan shading apa pun, sehingga material yang mahal hanya dijalankan pada bagian yang benar-benar terlihat.</p>
<p>Spike ini menjalankan dua jalur pada satu kanvas dan satu perangkat sehingga satu-satunya variabel adalah tempat shading dilakukan. Jalur forward menggunakan <code>MeshStandardNodeMaterial</code> biasa melalui three.js. Jalur vis-buffer menggunakan pipeline WebGPU dua pass mentah yang berjalan di luar three.js, membaca tekstur rumput three.js langsung dari backend, menulis <code>(instanceId, triId)</code> ke target <code>RG32Uint</code> pada pass 1, lalu menyelesaikan pencahayaan pada pass 2. Keduanya berbagi satu konfigurasi pencahayaan acuan.</p>
<p>Ada dua catatan implementasi yang layak dipertahankan. WebGPU masih belum memiliki builtin <code>primitive_index</code> portabel dalam fragment shader, sehingga triknya adalah menanamkan ID segitiga per vertex ke geometri non-indeks dan membacanya dengan interpolasi <code>flat</code>. Ini menambah jumlah vertex hingga 3×, tetapi dampaknya dapat diabaikan pada kartu rumput dengan 12 vertex. Selain itu, berbagi kanvas dengan renderer three.js pada dasarnya tidak menimbulkan masalah selama Anda tidak pernah mengonfigurasi ulang context atau menyentuh dimensi kanvas, karena keduanya dikelola oleh three.js. Mengukur waktu jalur forward adalah bagian yang merepotkan karena three.js tidak menyediakan hook untuk menyisipkan GPU timestamp query ke dalam render pass-nya. Solusinya adalah mengapit pekerjaannya dengan dua timestamp pass tanpa operasi yang dikirimkan sebelum dan sesudahnya, yang dijalankan GPU sesuai urutan pengiriman.</p>
<h2>Angkanya bergerak ke arah yang salah</h2>
<p>Pada Mac seri M dengan resolusi sekitar 1080p, menggunakan bilah rumput berbentuk kartu silang di lahan seluas 80 m:</p>
<p>Pada 50.000 instans, jalur vis-buffer unggul 25%, yakni 4,13 md dibandingkan 5,51 md untuk forward. Pada 100.000 instans, keduanya berimbang. Pada 200.000 instans, forward unggul 44%, yakni 5,44 md dibandingkan 7,80 md untuk vis-buffer. Jalur vis-buffer menjadi <em>relatif lebih buruk</em> saat kepadatan meningkat, persis berkebalikan dengan anggapan umum bahwa teknik ini unggul justru ketika overdraw tinggi.</p>
<h2>Mengapa forward tetap tangguh</h2>
<p>GPU Apple Silicon adalah tile-based deferred renderer, dan itu mengubah seluruh perhitungannya. Forward shading pada TBDR memiliki tahap penghapusan permukaan tersembunyi yang berjalan sebelum fragment shader: rasterizer mengumpulkan setiap fragmen yang dipetakan ke sebuah tile, mengurutkannya berdasarkan depth, dan hanya fragmen yang bertahan (setelah alpha test) yang mencapai fragment shader. Jadi, jalur forward sebenarnya sudah mendapatkan sebagian besar janji visibility buffer untuk “melakukan shading satu kali per piksel” secara gratis di dalam perangkat keras. Saat bilah rumput semakin memenuhi layar, semakin banyak fragmen ditolak oleh HSR sebelum shading apa pun dijalankan, dan biaya efektif forward per piksel tetap kurang lebih datar alih-alih meningkat bersama overdraw.</p>
<p>Pass 1 pada jalur vis-buffer mendapatkan manfaat TBDR yang sama. Masalahnya sepenuhnya ada pada pass 2. Pass 2 membaca matriks instans setiap piksel dari sebuah buffer yang, pada 200.000 instans, berukuran 12,8 MB, jauh lebih besar daripada cache GPU mana pun. Piksel yang bersebelahan di layar biasanya berasal dari instans rumput yang berbeda (penyebarannya menggunakan grid berjitter, sehingga bilah yang bertetangga memiliki ID instans acak), jadi setiap wave yang mengakses buffer tersebut mengalami cache miss secara divergen. Akses acak yang tidak koheren itu sendiri menghabiskan sekitar 4 md per frame. Forward sepenuhnya menghindarinya karena matriks instans tiba bersama vertex melalui jalur atribut per instans. Dengan demikian, saat fragment shader berjalan, data vertex yang telah ditransformasikan sudah berada di register lokal tile, tanpa memerlukan pembacaan acak berskala megabyte.</p>
<p>Inilah tepatnya biaya yang ingin diamortisasi oleh pass klasifikasi material Nanite: mengelompokkan piksel berdasarkan instans dan menjalankan wave komputasi yang telah diurutkan agar pembacaan setiap wave menjadi koheren. Kami tidak memiliki itu. Perhitungan kasar menunjukkan bahwa mengurutkan piksel berdasarkan instans akan menurunkan biaya 4 md tersebut menjadi mungkin 1,5 hingga 2 md dan mendorong titik peralihan ke 400.000 hingga 500.000 instans. Namun, itu berarti menumpuk optimasi pada arsitektur yang sejak awal tidak unggul dalam kasus ini.</p>
<h2>Kesimpulan yang jujur, serta audit yang membuatnya layak dipercaya</h2>
<p>Untuk dedaunan berbentuk kartu silang alpha-tested pada WebGPU di Apple Silicon, jalur forward dengan pipeline TSL three.js sudah setara atau lebih murah daripada vis-buffer. Infrastruktur vis-buffer tidak menghasilkan manfaat yang terlihat hingga jauh melampaui 200.000 instans, itu pun hanya jika Anda juga menambahkan pass pengurutan atau pengelompokan. Keputusan praktis untuk engine produksi adalah mempertahankan tumpukan forward, LOD, dan imposter dari spike sebelumnya, serta tidak berinvestasi pada infrastruktur vis-buffer sampai kami menargetkan GPU diskret NVIDIA atau AMD sebagai platform penerapan utama—yang biaya overdraw-nya lebih linear—atau beralih ke arsitektur meshlet, tempat vis-buffer memang menjadi output alaminya.</p>
<p>Karena hasil tersebut berlawanan dengan intuisi, kesimpulannya hanya bernilai jika perbandingannya adil. Karena itu, spike ini menjalani audit menyeluruh. Beberapa bug nyata ditemukan dan diperbaiki: slider skala bilah yang diam-diam membuat kedua jalur tidak sinkron, separuh bilah forward dirender sangat gelap akibat normal yang anti-paralel (diperbaiki dengan trik standar dedaunan ber-normal ke atas), serta pembacaan vis-buffer yang sekitar 2× terlalu terang akibat faktor Lambert yang dipilih secara manual alih-alih <code>1/π</code> yang mempertahankan energi, komponen ambient yang di-hardcode, dan tone mapping yang hilang. Perbaikannya menyalin kurva filmik ACES three.js yang persis sama ke WGSL serta membaca warna dan intensitas cahaya dari objek lampu yang sebenarnya di scene pada setiap frame. Kekurangan yang masih diketahui, yaitu tidak adanya specular langsung pada pass 2, membuat perbandingan menjadi <em>lebih menguntungkan</em> vis-buffer. Artinya, forward melakukan lebih banyak pekerjaan per piksel tetapi tetap unggul pada kepadatan tinggi. Hal ini membuat kesimpulan utama kami konservatif, bukan optimistis. Satu peringatan yang tetap berlaku: semua ini khusus untuk seri M, dan titik peralihannya sangat mungkin terbalik pada GPU diskret. Jadi, pengujian ulang layak dilakukan sebelum menetapkan tumpukan teknologi untuk target non-Apple.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Rendering visibility buffer.</strong> Pass 1 merasterisasi geometri dan hanya menulis ID segitiga dan instans beserta depth, tanpa melakukan shading. Pass 2 adalah penyelesaian layar penuh yang membaca ID per piksel yang tercakup, mengambil kembali segitiga sumber, merekonstruksi atribut barycentric yang dikoreksi perspektif, lalu melakukan shading satu kali pada setiap piksel yang terlihat. Karena WebGPU tidak memiliki <code>primitive_index</code> fragmen yang portabel, ID segitiga ditanamkan sebagai atribut per vertex berinterpolasi <code>flat</code> pada geometri non-indeks.</p>
<p><strong>Penghapusan permukaan tersembunyi TBDR dibandingkan deferred resolve.</strong> Pada GPU tile-based deferred (Apple Silicon), forward shading sudah menolak fragmen yang tertutup sebelum fragment shader berjalan. Karena itu, forward memperoleh sebagian besar manfaat visibility buffer berupa shading satu kali secara gratis, dan biaya per pikselnya tetap kurang lebih datar saat overdraw meningkat. Sebaliknya, pass resolve vis-buffer menanggung biaya akses acak yang tidak koheren ke buffer per instans berukuran besar (12,8 MB pada 200 ribu instans), yang menjadi faktor dominan pada kepadatan tinggi kecuali piksel terlebih dahulu diurutkan atau dikelompokkan berdasarkan instans, seperti yang dilakukan klasifikasi material Nanite.</p>
<p><strong>Berbagi kanvas dengan WebGPURenderer milik three.js.</strong> Command buffer WebGPU mentah dapat diselingi dengan benar di antara pengiriman three.js pada antrean bersama selama Anda tidak pernah memanggil <code>context.configure()</code> lagi atau menulis ke <code>canvas.width/height</code>, karena keduanya dikelola oleh renderer. Pengukuran waktu GPU pada jalur forward, yang tidak memiliki hook terbuka di three.js, dapat diapit oleh dua timestamp render pass tanpa operasi yang dikirimkan sebelum dan sesudah pemanggilan render-nya, karena GPU menjalankan command buffer sesuai urutan pengiriman.</p>
<p><strong>Memvalidasi benchmark yang berlawanan dengan intuisi.</strong> Hasil performa yang mengejutkan hanya dapat dipercaya sejauh perbandingannya adil. Audit terhadap kedua jalur agar memiliki konten scene dan shading yang identik—tone mapping ACES yang cocok, Lambert yang mempertahankan energi, cahaya yang dibaca dari objek yang sama, serta skala bilah yang identik—mengubah “vis-buffer lebih lambat” dari kemungkinan artefak pengukuran menjadi kesimpulan yang dapat dipertanggungjawabkan, dengan satu-satunya asimetri yang tersisa justru condong ke arah konservatif.</p>
<hr>
<p>Bagian 21 dari 29.
Sebelumnya: <a href="/id/blog/2026-05-05-open-world-browser-part-20-parallax-occlusion">Bagian 20 - Menyimulasikan kedalaman pada bidang datar</a>
Berikutnya: <a href="/id/blog/2026-05-07-open-world-browser-part-22-clouds-and-meshlets">Bagian 22 - Awan yang bisa diterobos, dan culling yang sepadan</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 20: Memalsukan kedalaman pada bidang datar]]></title>
            <link>https://app.cinevva.com/id/blog/2026-05-05-open-world-browser-part-20-parallax-occlusion</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-05-05-open-world-browser-part-20-parallax-occlusion</guid>
            <pubDate>Tue, 05 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 39 mem-porting parallax occlusion mapping ke TSL, menghadapi dua kendala alur kontrol shader WebGPU, menemukan bahwa bug tersebut berasal dari kegagalan disiplin porting verbatim, dan membuat bidang referensi dengan geometri nyata untuk menjaga validitas hasilnya.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 20: Memalsukan kedalaman pada bidang datar</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Salah Satu Pendiri Cinevva</em></p>
<p>Baru di sini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menautkan semua bagian.</p>
<p><a href="/id/blog/2026-05-04-open-world-browser-part-19-imposters">Bagian 19</a> menggunakan quad datar untuk memalsukan sebuah pohon utuh dari kejauhan. Bagian ini menggunakan quad datar untuk memalsukan kedalaman dari dekat: parallax occlusion mapping, trik yang membuat jalan berbatu terlihat memiliki nat sedalam 5 cm tanpa menggunakan satu pun vertex tambahan. Tujuannya adalah menerapkannya pada stack produksi (Three.js r184, WebGPU, TSL), sehingga material detail medan dapat menghadirkan ilusi kedalaman tersebut di tempat yang diperlukan dan hanya menanggung biaya tekstur datar di tempat lain.</p>
<h2>Tiga cara memalsukan kedalaman, ditampilkan berdampingan</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/39-parallax-pom/" title="Spike 39 Parallax Occlusion Mapping" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/39-parallax-pom/" target="_blank">Buka Spike 39 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=39-parallax-pom">Lihat kode sumber</a></p>
<p>Spike ini menempatkan tiga bidang datar berukuran 5×5 m secara berdampingan. Semuanya menggunakan kerangka material yang sama dan hanya berbeda pada UV yang diteruskan ke sampler. Flat mengambil sampel tekstur secara langsung sebagai baseline referensi. Parallax sampel tunggal menggeser UV satu kali sepanjang arah pandang berdasarkan ketinggian pada titik tersebut. Teknik ini murah dan cukup baik pada amplitudo rendah, tetapi tampak bergeser pada sudut pandang landai. POM melakukan ray marching dalam ruang tangen: bergerak sepanjang sinar pandang, menemukan lapisan pertama tempat sinar melewati bagian bawah heightfield, lalu menyempurnakan titik perpotongannya. Ruang tangen tetap sederhana karena setiap bidang pengujian sejajar dengan sumbu, sehingga arah pandang dapat dikemas ke dalam ruang tangen hanya dengan beberapa pembalikan tanda, alih-alih matriks TBN lengkap per vertex. Set teksturnya diambil secara langsung dari API berkas Polyhaven, melalui jalur yang sama dengan pencarian model pada Bagian 17.</p>
<h2>Dua kendala WebGPU dan ray marching tanpa percabangan</h2>
<p>Loop POM standar berhenti dari pencarian pada perpotongan pertama. Pada r184, cara ini tidak berfungsi karena dua alasan terpisah. <code>If(...).and(...)</code> dapat dikompilasi tanpa error, tetapi menghasilkan WGSL yang tidak pernah menjalankan isi loop. Akibatnya, penyempurnaan setelah loop dijalankan pada data sampah dan bidang dirender hampir putih. Selain itu, <code>Break()</code> sebagai node mandiri belum tersedia dalam build r184, sehingga bahkan dengan <code>If</code> yang berfungsi, tidak ada cara untuk menyatakan &quot;berhenti pada perpotongan pertama.&quot; Keduanya berkaitan dengan masalah three.js yang telah diketahui seputar alur kontrol TSL yang dioptimalkan secara berlebihan melintasi batas <code>If</code> dan <code>Loop</code> pada rentang versi ini.</p>
<p>Versi yang ditulis ulang tidak menggunakan percabangan. Setiap iterasi selalu mengambil sampel tekstur, sehingga akses tekstur tetap berada dalam alur kontrol seragam sebagaimana diharuskan spesifikasi WGSL. Kemudian, state baru digabungkan melalui flag <code>done</code> yang disimpan sebagai float. Setelah <code>done</code> berubah menjadi 1, pemanggilan <code>mix</code> per iterasi menyederhana menjadi &quot;pertahankan state tanpa perubahan,&quot; yang merupakan padanan tanpa percabangan dari break. Flag <code>done</code> dibuat dengan helper <code>step</code> yang diimplementasikan sebagai <code>0.5 + 0.5 × sign(x + ε)</code> karena konversi boolean ke float tidak konsisten pada seri r18x, sedangkan <code>sign()</code> aman digunakan di semua versi. Konsekuensinya, setiap fragmen menjalankan seluruh 64 iterasi, terlepas dari posisi perpotongan sebenarnya. Namun, itu adalah kompromi yang tepat pada skala fragmen: runtime tetap membatasi berdasarkan jumlah langkah maksimum, dan GPU nyata juga akan melakukan spekulasi melewati break &quot;nyata&quot;. Fallback yang bersih sangat penting di sini, yaitu <code>mix(baseUV, refined, done)</code>, sehingga pada amplitudo nol (ujung jauh dari fade berdasarkan jarak), tidak ada fragmen yang berpotongan, <code>done</code> tetap 0, dan material POM identik secara bit dengan material datar. Itulah inti trik LOD berbasis jarak: kembali ke biaya material datar ketika efeknya sudah berada di bawah ukuran piksel.</p>
<h2>Bug tersebut adalah kegagalan disiplin, bukan kegagalan matematika</h2>
<p>Versi tanpa percabangan dapat berjalan, tetapi tampil terdistorsi, dengan artefak horizontal memanjang pada amplitudo sedang dan hasil yang agak keliru tetapi tidak tampak jelas pada amplitudo rendah. Perbaikannya berawal dari prompt satu baris: baca referensi kanonisnya. Tutorial LlamAcademy yang menginspirasi pekerjaan ini hanyalah sebuah node Unity ShaderGraph, jadi implementasi sebenarnya berada dalam <code>PerPixelDisplacement.hlsl</code> milik Unity. Membacanya baris demi baris mengungkap tiga perbedaan semantik yang tanpa sadar saya perkenalkan: kesalahan off-by-one pada baseline ketinggian sinar (Unity melakukan perpindahan awal sebelum loop, sehingga kerangka acuan saya berbeda satu langkah penuh dan membuat perpotongan berada di lapisan yang salah sekitar separuh waktu), konvensi tanda pada offset maksimum yang diperlukan oleh langkah penyempurnaan, serta pilihan pencatatan offset kumulatif versus UV kumulatif yang membuat matematika penyempurnaan saya bekerja lebih keras dan mengacaukan tandanya.</p>
<p>Penyebab utamanya bukan satu kesalahan tertentu, melainkan pencampuran dua referensi. Saya menggunakan tutorial POM LearnOpenGL sebagai panduan. Tutorial tersebut memakai konvensi tanda yang serupa tetapi berbeda serta rumus penyempurnaan yang berbeda. Akibatnya, saya berakhir dengan gabungan yang tidak konsisten: dua pertiga matematikanya mengikuti satu sumber dan sepertiga lainnya mengikuti sumber lain. Versi baru merupakan porting hampir verbatim dari HLSL Unity ke TSL, dengan nama variabel, perpindahan awal, dan penyempurnaan yang sama, ditambah flag <code>done</code> tanpa percabangan. Pelajarannya layak diingat: saat mem-porting shader yang telah terbukti berfungsi dari stack lain, porting terlebih dahulu baris demi baris dengan nama yang sama, lalu lakukan refactor agar sesuai dengan gaya lokal. Jangan melakukan derivasi ulang berdasarkan referensi kedua di tengah proses porting.</p>
<h2>Bidang referensi yang tidak bisa berbohong</h2>
<p>Perbandingan berdampingan tersebut belum menyertakan hal yang paling jelas: bidang dengan geometri nyata. Tanpanya, pernyataan &quot;POM terlihat cukup bagus&quot; tidak dapat diuji kebenarannya. Cukup bagus dibandingkan dengan apa? Karena itu, spike menambahkan bidang keempat dengan heightmap yang sama, tetapi diterapkan pada posisi vertex sebenarnya. WebGPU tidak memiliki tessellation perangkat keras (fitur tersebut memang tidak ada dalam spesifikasi karena dihapus demi kompatibilitas dengan Metal), sehingga penggantinya adalah bidang dengan subdivisi padat (256×256 segmen, 131.072 segitiga) dan displacement vertex pada tahap vertex. Uniform amplitudo yang sama mengendalikan POM dan bidang geometri, sehingga keduanya mengalami fade bersama dan perbandingannya tetap setara pada setiap jarak.</p>
<p>Dengan ground truth di layar, klaim kualitatif menjadi dapat diukur. Pada orbit 16° yang mengarah ke bawah, POM dan bidang yang ditessellasi menghasilkan shading internal yang serupa. Pada sudut pandang landai, keduanya menyimpang tepat di tempat yang semestinya: POM dibatasi oleh tepi persegi panjang geometri yang sepenuhnya lurus, sedangkan mesh nyata memperlihatkan profil horizon bergelombang dari puncak dan lembah aktual yang menangkap cahaya. Dengan demikian, efek &quot;swimming&quot; pada tepi POM kini dapat dibuktikan sebagai sifat bawaan algoritma, bukan artefak tekstur atau pencahayaan. Karakteristik biaya keduanya juga menjadi jelas: POM dibatasi oleh pemrosesan fragmen (biaya meningkat sesuai jumlah piksel yang dicakup), sedangkan bidang yang ditessellasi dibatasi oleh pemrosesan vertex (biaya meningkat sesuai kepadatan mesh, terlepas dari cakupannya). Untuk chunk medan yang sudah menanggung biaya vertex dari bidang berbasis heightmap, POM adalah pilihan yang tepat untuk detail yang lebih kecil daripada mesh.</p>
<p>Bidang referensi tersebut juga menemukan bug UX yang samar. Pengguna melihat permukaan seolah tenggelam ketika amplitudo ditingkatkan. Penyebabnya adalah konvensi Unity yang memperlakukan bidang geometris sebagai bagian teratas heightfield. Akibatnya, puncak tetap rata dengan bidang dan bagian lainnya mengalami parallax ke bawah, sehingga permukaan rata-rata turun di bawah baseline datar sebesar <code>(1 − mean_h) × amplitude</code>. Perbaikannya memusatkan ulang konvensi tersebut agar <code>h = 0.5</code> menjadi posisi bidang, puncak naik menuju kamera, dan lembah masuk ke dalam. Algoritmanya tetap berjalan persis seperti yang ditentukan Unity; spike hanya melakukan pascapemrosesan pada output sebesar setengah offset agar sesuai dengan arti &quot;amplitudo&quot; yang diharapkan seseorang saat menggeser slider.</p>
<p>Bidang referensi juga menyelesaikan satu persoalan lain. Slider &quot;Langkah&quot; tampak tidak melakukan apa pun, sehingga terlihat seperti bug pada rangkaian data, padahal bukan. Penyempurnaan secant tiga iterasi setelah pencarian linear sangat efektif (makalah POM Tatarchuk tahun 2006 menyatakan bahwa pencarian 4 langkah ditambah secant 3 langkah secara visual tidak dapat dibedakan dari pencarian 64 langkah). Karena itu, pada heightmap yang halus, setiap jumlah langkah dari 4 hingga 64 menghasilkan UV subteksel yang sama. Perbaikannya adalah toggle, bukan merombak rangkaian data: nonaktifkan secant dan slider langkah menjadi satu-satunya kontrol atas presisi perpotongan. Menurunkannya ke 4 akan membuat batu jalan terlihat berundak, sedangkan meningkatkannya ke 64 akan menghaluskannya kembali. Toggle tersebut adalah uniform 0/1 yang menggunakan <code>mix</code> untuk mengubah setiap pembaruan state secant menjadi no-op saat dinonaktifkan, sehingga toggle tidak pernah membangun ulang material dan tidak pernah menimbulkan stutter.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Parallax occlusion mapping dalam TSL.</strong> POM melakukan ray marching terhadap arah pandang melalui heightfield dalam ruang tangen, menemukan lapisan pertama tempat sinar turun ke bawah permukaan, lalu menyempurnakan titik perpotongannya. Hasilnya adalah kedalaman nat cekung pada quad datar tanpa geometri tambahan. <code>mix(baseUV, refined, done)</code> terakhir membuat material identik secara bit dengan material datar ketika tidak ada fragmen yang berpotongan. Hal inilah yang memungkinkan atenuasi amplitudo LOD berbasis jarak menurunkan biayanya menjadi biaya tekstur datar pada jarak jauh. Lihat <a href="/id/guides/landscape-generation-browser#terrain-materials">material medan</a>.</p>
<p><strong>Loop tanpa percabangan untuk alur kontrol WebGPU.</strong> Pada Three.js r184, <code>If(...).and(...)</code> dalam TSL dapat dikompilasi menjadi WGSL yang tidak pernah menjalankan isi loop, sedangkan <code>Break()</code> mandiri belum tersedia. Pola yang portabel adalah mengambil sampel tekstur tanpa syarat pada setiap iterasi (menjaga akses tekstur dalam alur kontrol seragam sesuai spesifikasi WGSL), ditambah flag <code>done</code> yang disimpan sebagai float dan menggunakan <code>mix</code> untuk mengubah setiap pembaruan state menjadi no-op setelah flag ditetapkan. Helper <code>step</code> yang dibuat dari <code>sign(x + ε)</code> menghindari konversi boolean ke float yang tidak andal. Biayanya selalu sebesar jumlah iterasi maksimum, terlepas dari titik penghentian awal, yang merupakan kompromi tepat pada skala fragmen.</p>
<p><strong>Porting shader secara verbatim.</strong> Shader yang telah terbukti berfungsi dari engine lain sebaiknya terlebih dahulu di-porting baris demi baris dengan nama variabel asli, baru kemudian di-refactor agar sesuai dengan gaya lokal. Mencampurkan dua referensi (<code>PerPixelDisplacement.hlsl</code> milik Unity dan tutorial LearnOpenGL) menghasilkan gabungan yang tidak konsisten, dengan baseline sinar yang off-by-one, tanda offset yang terbalik, dan rumus penyempurnaan yang clamp-nya menyamarkan bobot di luar rentang sebagai diskontinuitas spasial. Gunakan satu ground truth kanonis, bukan derivasi ulang.</p>
<p><strong>Referensi ground truth dengan displacement vertex.</strong> Karena WebGPU tidak memiliki tessellation perangkat keras, bidang dengan subdivisi padat (256² segmen) yang diberi displacement pada tahap vertex berperan sebagai geometri nyata untuk memvalidasi efek palsu pada tahap fragmen. Mengendalikan keduanya dengan uniform amplitudo yang sama menjaga kejujuran perbandingan pada berbagai jarak. POM dibatasi oleh fragmen (meningkat sesuai piksel yang dicakup), sedangkan bidang geometri dibatasi oleh vertex (meningkat sesuai kepadatan mesh). Karena itu, keduanya menyimpang tepat pada tepi siluet, membuktikan bahwa efek swimming pada tepi POM merupakan sifat bawaan, bukan artefak.</p>
<hr>
<p>Bagian 20 dari 29.
Sebelumnya: <a href="/id/blog/2026-05-04-open-world-browser-part-19-imposters">Bagian 19 - Imposter yang harus bertahan di dalam hutan</a>
Berikutnya: <a href="/id/blog/2026-05-06-open-world-browser-part-21-visibility-buffer">Bagian 21 - Renderer lebih cepat yang ternyata tidak lebih cepat</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 19: Imposter yang harus bertahan di tengah hutan]]></title>
            <link>https://app.cinevva.com/id/blog/2026-05-04-open-world-browser-part-19-imposters</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-05-04-open-world-browser-part-19-imposters</guid>
            <pubDate>Mon, 04 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 38 memanggang sebuah pohon menjadi dua tekstur pada billboard, lalu penulisan ulang dengan prinsip KISS dan perbaikan N ganjil membuatnya cocok. Spike 41-42 menghilangkan lompatan dengan blending hemi-oktahedral dan memindahkan sejuta pohon ke GPU.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 19: Imposter yang harus bertahan di tengah hutan</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Salah Satu Pendiri Cinevva</em></p>
<p>Baru mengikuti seri ini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menyediakan tautan ke semua bagian.</p>
<p><a href="/id/blog/2026-05-02-open-world-browser-part-18-ai-scattering">Bagian 18</a> memberi kreator kuas yang dapat memenuhi lereng bukit dengan pepohonan. Masalahnya adalah biaya rendering pohon-pohon tersebut ketika ada puluhan ribu di layar. Pohon yang jauh tidak memerlukan 2.000 segitiga hanya untuk menghasilkan empat piksel. Bagian ini membahas LOD terdalam: imposter, sebuah quad datar yang mengenakan foto pohon, serta perjalanan dari &quot;satu pohon yang terlihat benar&quot; hingga sejuta pohon di GPU.</p>
<h2>Sebuah pohon adalah dua tekstur pada billboard</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/38-imposters/" title="Spike 38 Imposter Oktahedral" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/38-imposters/" target="_blank">Buka Spike 38 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=38-imposters">Lihat kode sumber</a></p>
<p>Imposter melakukan pra-render sebuah prop dari kisi sudut pandang ke dalam dua atlas tekstur, satu untuk warna dan satu untuk normal ruang dunia, lalu saat runtime menampilkan satu quad yang menghadap kamera dan mengambil sampel dari tile yang cocok dengan sudut pandang saat ini. Proses bake terdiri dari dua pass per tile: diffuse dengan material tanpa pencahayaan agar pencahayaan tidak ikut terpanggang ke dalam tekstur, serta normal yang dienkode sebagai <code>normalWorld × 0.5 + 0.5</code>, dengan alpha diteruskan dari sumber agar siluetnya cocok piksel demi piksel. Material runtime-nya adalah <code>MeshStandardNodeMaterial</code> penuh, sehingga imposter tetap menerima cahaya matahari dan IBL dari scene seperti permukaan lainnya. Keuntungannya ada pada geometri: satu quad alih-alih ribuan segitiga, dengan detail yang tersimpan dalam tekstur berukuran 1 MB.</p>
<p>Memisahkan ini menjadi spike tersendiri juga memberikan pelajaran. Imposter bermula sebagai LOD terdalam di dalam sistem scatter spike 37, dan setiap iterasi pada proses bake harus diuji melalui seluruh pipeline scatter, sementara kebenaran hasil bake bercampur dengan migrasi matriks instance dan pergantian LOD. Memisahkannya menjadi satu prop dan satu quad yang ditampilkan berdampingan dengan versi asli memangkas waktu iterasi dari hitungan menit menjadi detik.</p>
<h2>Ketika jawaban dari buku teks adalah jawaban yang keliru</h2>
<p>Implementasi pertama menggunakan encoding oktahedral, pemetaan standar dari buku teks untuk memadatkan arah pada bola ke dalam persegi. Implementasi tersebut lolos pengujian roundtrip numerik, tetapi pengguna terus mengirimkan tangkapan layar imposter yang melompat ke tile yang membuat pohon terlihat sedikit dari atas, bukan lurus dari depan. Enam putaran perbaikan menyusul (uniform arah pandang per quad, aspek bake persegi, material debug, billboarding statis), dan semuanya memang diperlukan, tetapi tidak satu pun merupakan bug yang sebenarnya. Perbaikannya baru ditemukan setelah kami memutuskan untuk &quot;memikirkannya ulang dari awal, KISS, tanpa tambalan.&quot;</p>
<p>Penulisan ulang tersebut membuang lipatan oktahedral dan menggantinya dengan azimut berdasarkan elevasi biasa: <code>az = atan2(dir.x, dir.z)</code>, <code>el = asin(dir.y)</code>, <code>uv = (az/2π, el/π + ½)</code>. Itulah keseluruhan encoding-nya, tanpa normalisasi L1 dan tanpa kasus sudut sign-of-zero. Alasan pendekatan ini lebih baik bukan karena lebih akurat (pengambilan sampelnya pada bola kurang seragam), melainkan karena pemilih sel di CPU dan shader GPU menggunakan primitif yang sama, sehingga keduanya tidak mungkin berselisih pada arah batas seperti yang diam-diam terjadi pada pasangan oktahedral. Atlas tersebut terbaca seperti lembar kontak: kolom menunjukkan sudut mengelilingi prop, baris menunjukkan elevasi, dan semuanya langsung terlihat jelas pada overlay.</p>
<p>Bahkan setelah itu, keluhan &quot;terlihat sedikit dari atas&quot; tetap ada, dan penyebabnya adalah pilihan kuantisasi, bukan encoding. Dengan kisi 4×4, pusat baris berada pada ±22,5° dan ±67,5°, sehingga tidak ada baris yang tepat berada pada elevasi 0°. Penonton yang melihat secara horizontal—kasus yang jauh paling umum—selalu masuk ke baris yang dipanggang dalam posisi miring. Solusinya adalah N ganjil: kisi 5×5 menempatkan pusat baris pada 0°, ±36°, dan ±72°, sehingga penonton horizontal mendapatkan tile yang dipanggang tepat secara horizontal. Keluarga kesalahan &quot;meleset setengah sel&quot; yang sama muncul lagi dalam pembahasan paralaks di bagian berikutnya, dan penyembuhnya adalah pertanyaan yang sama: apakah titik sampel diskret saya benar-benar berada di tempat yang saya kira untuk input kanonis?</p>
<p>Dua bagian lain juga penting. Billboard harus bersifat statis per segmen, bukan terus-menerus menghadap kamera. Imposter adalah foto datar yang diambil dari arah bake tertentu, sehingga bidang gambar quad saat runtime harus cocok dengan bidang kamera bake tersebut. Artinya, orientasinya dipertahankan sepanjang busur tempat satu sel tetap terpilih, lalu melompat pada batasnya. Selain itu, anggaran sebaiknya mengikuti arah pandang pemain yang sebenarnya: pass berikutnya membuang seluruh baris miring dari atas dan menggantinya dengan 24 slot cincin horizontal berjarak 15° serta satu tile lurus dari atas, karena pohon hampir selalu dilihat dari ketinggian mata.</p>
<h2>Lompatan, dan bagaimana blending menghapusnya</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/42-imposter-flicker/" title="Perbandingan Kedipan Imposter Spike 42" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/42-imposter-flicker/" target="_blank">Buka Spike 42 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=42-imposter-flicker">Lihat kode sumber</a></p>
<p>Billboard yang statis per segmen tidak terlihat dari kejauhan tetapi menimbulkan pop dari jarak dekat, yang tidak menjadi masalah sampai Anda mengorbit kamera. Spike 42 menempatkan empat varian berdampingan (prop asli, baseline az/el 5×5, dan dua kisi hemi-oktahedral) untuk mengisolasi kedipan tersebut dan menghilangkannya. Dua artefak mendorong terjadinya lompatan. Pop sel terjadi karena fragment shader mengkuantisasi arah pandang menjadi salah satu dari 25 sel, sehingga ketika melewati batas, tile yang diambil sebagai sampel diganti dan quad diarahkan ulang pada frame yang sama. Degenerasi kutub terjadi pada tampilan lurus dari atas, ketika setiap azimut runtuh menjadi satu titik dan jembatan antara cincin dengan tile atas menjadi transisi terburuk dalam atlas.</p>
<p>Pemetaan hemi-oktahedral memperbaiki keduanya. Pemetaan ini memetakan belahan bola atas secara kontinu ke persegi satuan, sehingga arah 3D yang berdekatan berakhir pada UV yang berdekatan, tanpa singularitas kutub dan tanpa memerlukan tile khusus untuk pandangan lurus dari atas. Kedipan diatasi dengan blending sel bilinear: alih-alih melompat ke tile terdekat, temukan kelompok tile 2×2 yang mengapit arah hasil encoding dan blend keempatnya, dengan total 8 pengambilan sampel tekstur (4 diffuse, 4 normal). Tampilan yang berdekatan kini saling bertransisi dengan cross-fade alih-alih mengalami pop. Hasil blending dua vektor normal satuan bukanlah vektor satuan, sehingga hasilnya dinormalisasi ulang, yang berperilaku seperti slerp untuk sudut kecil di antara tile yang berdekatan. Biayanya memang nyata (atlas 12×12 berukuran sekitar 9 MB dibandingkan 1,6 MB untuk az/el, dan proses bake berlangsung kira-kira 5× lebih lama dengan 288 pass render target), tetapi bake hanya dilakukan sekali saat pemuatan dan blending menghasilkan tampilan tanpa pop. Inilah yang membuat imposter dapat digunakan ketika kamera benar-benar bergerak.</p>
<h2>Sejuta pohon, satu penyalinan posisi kamera per frame</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/41-imposter-forest/" title="Hutan Imposter Spike 41" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/41-imposter-forest/" target="_blank">Buka Spike 41 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=41-imposter-forest">Lihat kode sumber</a></p>
<p>Runtime Spike 38 menjalankan satu <code>lookAt</code> CPU per quad per frame, yang baik-baik saja untuk satu pohon tetapi mematikan bagi sebuah hutan. Dengan sejuta pohon, pembaruan matriks per frame dan pengunggahan buffer instance akan mendominasi semuanya. Spike 41 memindahkan seluruh pipeline per frame ke GPU. Pusat, yaw, dan skala setiap instance diunggah satu kali saat build sebagai atribut instance dan tidak pernah berubah. Vertex shader membangun basis billboard dari arah pandang ruang dunia <code>camPos − center</code> dan memperluas sebuah quad satuan bersama ke ruang dunia. Fragment shader menjalankan encoding hemi-oktahedral dan blending bilinear per piksel. Satu-satunya pekerjaan CPU per frame untuk seluruh hutan adalah satu <code>Vector3.copy</code> untuk memperbarui uniform posisi kamera, yang sama sekali tidak meningkat seiring jumlah pohon.</p>
<p>Bagian menarik dari perhitungannya adalah bahwa yaw per instance saling meniadakan dalam decoding normal. Bake menyimpan normal dalam kerangka kamera bake, dan karena rotasi yaw di sekitar sumbu atas dunia mempertahankan +Y serta cross product bersifat ekuivarian terhadap rotasi, basis runtime yang dibangun dengan acuan sumbu atas dunia sudah sama dengan basis bake yang telah diputar. Jadi shader menerjemahkan normal secara langsung melalui varying basis runtime tanpa pernah menyentuh yaw per instance. Penempatan menggunakan kisi berjitter alih-alih scatter acak murni: area dibagi menjadi sel, lalu satu pohon ditempatkan per sel pada titik tengah ditambah offset terbatas. Ini menjamin jarak minimum (tidak ada dua pohon yang saling bertumpuk) sambil tetap terlihat seperti hutan alami. Satu detail yang mudah terlewat adalah bounding sphere. Template geometrinya hanyalah quad satuan, sehingga three.js akan melakukan frustum culling terhadap seluruh hutan begitu kamera memandang menjauh dari titik asal. Menetapkan bounding sphere secara eksplisit yang mencakup seluruh area ditambah margin quad mencegah pohon-pohon di sudut terpotong pada sudut pandang menyerong.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Atlas imposter oktahedral dan azimut-elevasi.</strong> Imposter memanggang sebuah prop dari kisi arah pandang ke dalam atlas diffuse dan atlas normal ruang dunia, lalu merender satu billboard yang mengambil sampel tile yang cocok, menggantikan ribuan segitiga dengan dua tekstur. Pemetaan oktahedral standar dari buku teks memberikan cakupan bola yang seragam, tetapi rentan terhadap perbedaan CPU/GPU pada batas lipatan. Kisi azimut berdasarkan elevasi biasa mengambil sampel bola dengan distribusi yang kurang seragam, tetapi secara konstruksi menjamin pemilih sel dan shader selalu sepakat. Gunakan N ganjil agar satu baris berada tepat pada elevasi 0°, dan alokasikan anggaran tile untuk cincin horizontal karena prop biasanya dilihat dari ketinggian mata.</p>
<p><strong>Orientasi billboard statis per segmen.</strong> Imposter adalah foto dari arah bake tertentu, sehingga bidang gambar quad saat runtime harus cocok dengan bidang kamera bake, bukan terus-menerus menghadap kamera runtime. Quad mempertahankan orientasi sepanjang busur tempat satu sel tetap terpilih, lalu melompat pada batasnya. Hal ini tidak terlihat pada jarak penggunaan imposter dan hanya menimbulkan pop dari dekat, tempat imposter memang tidak digunakan.</p>
<p><strong>Atlas hemi-oktahedral dengan blending sel bilinear.</strong> Pemetaan belahan bola atas secara kontinu ke persegi satuan menghapus singularitas kutub dan kebutuhan akan tile khusus untuk pandangan lurus dari atas. Lompatan dihilangkan dengan mengambil sampel kelompok tile 2×2 yang mengapit arah pandang hasil encoding dan melakukan blending bilinear terhadap keempat tile tersebut (8 pengambilan sampel), sehingga tampilan yang berdekatan saling bertransisi dengan cross-fade. Normal hasil blending dinormalisasi ulang, mendekati slerp untuk sudut kecil antartile. Biayanya adalah atlas yang lebih besar (sekitar 9 MB pada 12×12) dan proses bake satu kali yang lebih lama, sebagai imbalan atas shading bebas pop saat kamera bergerak.</p>
<p><strong>Imposter instance berbasis GPU.</strong> Pusat, yaw, dan skala per instance diunggah satu kali sebagai atribut instance; vertex shader membangun basis billboard dan memperluas sebuah quad satuan bersama, sementara fragment shader melakukan encoding dan blending per piksel. Biaya CPU per frame untuk seluruh hutan hanyalah satu penyalinan uniform posisi kamera, terlepas dari jumlah instance. Yaw per instance saling meniadakan dalam decoding normal karena yaw di sekitar sumbu atas dunia dipertahankan oleh konstruksi basis cross product. Bounding sphere eksplisit yang mencakup seluruh hutan mencegah three.js melakukan frustum culling terhadap seluruh mesh instance ketika kamera memandang menjauh dari titik asal template quad satuan. Lihat <a href="/id/guides/landscape-generation-browser#gpu-driven-lod-with-webgpu">LOD berbasis GPU</a>.</p>
<hr>
<p>Bagian 19 dari 29.
Sebelumnya: <a href="/id/blog/2026-05-02-open-world-browser-part-18-ai-scattering">Bagian 18 - Kuas scatter yang terasa seperti ditempatkan oleh AI</a>
Berikutnya: <a href="/id/blog/2026-05-05-open-world-browser-part-20-parallax-occlusion">Bagian 20 - Memalsukan kedalaman pada bidang datar</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Awan volumetrik dan efek cuaca dalam game modern]]></title>
            <link>https://app.cinevva.com/id/blog/2026-05-04-volumetric-clouds-and-weather</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-05-04-volumetric-clouds-and-weather</guid>
            <pubDate>Mon, 04 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Cara game modern merender awan volumetrik, hamburan atmosfer, kabut, hujan, salju, dan cuaca dinamis, beserta makalah dasar dan presentasi engine di balik setiap teknik.]]></description>
            <content:encoded><![CDATA[<h1>Awan volumetrik dan efek cuaca dalam game modern</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<img src="/img/blog/clouds_weather_hero.webp" alt="Adegan AAA bergaya dengan awan badai volumetrik yang menjulang, kilat, tirai hujan, dan jalan batu basah yang memantulkan langit" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Beberapa minggu lalu saya menulis tentang <a href="/id/blog/2026-05-03-aaa-rendering-techniques">teknik rendering yang benar-benar digunakan dalam game AAA modern</a>. Salah satu bagian yang belum banyak saya bahas adalah langit dan cuaca, karena topik ini layak mendapatkan daftarnya sendiri. Awan, kabut, hujan, dan salju adalah sistem yang mengubah demo medan menjadi sebuah tempat yang terasa nyata. Sistem-sistem ini juga berbagi lebih banyak kode daripada yang terlihat. Awan volumetrik, kabut permukaan, dan sinar dewa semuanya menggunakan ray-march yang sama. Jalan basah, timbunan salju, dan jejak kaki semuanya menggunakan perpindahan permukaan serta trik PBR yang sama. Angin adalah satu vektor arah yang dibaca oleh semua elemen dalam adegan.</p>
<p>Berikut tur singkat dan subjektif mengenai cara studio-studio besar membangun semua ini pada 2026, beserta makalah dan presentasi engine di balik setiap bagiannya.</p>
<h2>1. Langit dan atmosfer berbasis fisika</h2>
<p>Hamburan atmosfer adalah fondasinya. Warna langit, kabut di cakrawala, perubahan warna pegunungan jauh menjadi biru, serta rona jingga matahari terbenam, semuanya berasal dari hamburan cahaya di udara. Engine modern menghitungnya berdasarkan fisika: hamburan Rayleigh untuk warna biru, hamburan Mie untuk kabut di sekitar matahari, dan penyerapan ozon untuk warna ungu tua di zenit.</p>
<p>Metode Bruneton tahun 2008 yang asli memanggang semuanya ke dalam lookup table 4D, sehingga membatasi perubahan waktu secara dinamis dan menimbulkan artefak LUT ketika sudut matahari rendah. Pembaruan Sébastien Hillaire pada 2020, yang digunakan oleh komponen Sky Atmosphere UE5, mengganti LUT berdimensi tinggi dengan beberapa tekstur 2D dan pendekatan hamburan berganda yang diperbarui setiap frame. Teknik ini dapat berjalan dari ponsel hingga PC kelas atas.</p>
<img src="/img/blog/clouds_weather_atmosphere.webp" alt="Langit berbasis fisika pada jam keemasan dengan gradasi halus dari jingga ke biru di atas siluet pegunungan jauh" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Hillaire, <a href="https://sebh.github.io/publications/egsr2020.pdf">Teknik Rendering Langit dan Atmosfer yang Skalabel dan Siap Produksi</a> (EGSR 2020, standar modern yang digunakan di UE5).</li>
<li>Bruneton dan Neyret, <a href="https://hal.inria.fr/inria-00288758/document">Hamburan Atmosfer yang Diprakomputasi</a> (EGSR 2008, pendekatan LUT orisinal).</li>
<li>Bruneton, <a href="https://ebruneton.github.io/precomputed_atmospheric_scattering/">Hamburan Atmosfer yang Diprakomputasi: Implementasi Baru</a> (referensi sumber terbuka, dengan dukungan ozon dan multi-planet).</li>
<li>Epic Games, <a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/sky-atmosphere-component-in-unreal-engine">Komponen Sky Atmosphere</a> (dokumentasi UE5).</li>
</ul>
<h2>2. Awan volumetrik dengan noise Perlin-Worley</h2>
<p>Teknik awan yang menjadi fondasi dalam game modern bermula dari presentasi Andrew Schneider tentang Horizon Zero Dawn pada 2015. Awan bukanlah mesh. Awan merupakan fungsi densitas 3D yang didefinisikan oleh noise berlapis: campuran Perlin-Worley berfrekuensi rendah menghasilkan bentuk awan secara keseluruhan, sementara noise Worley berfrekuensi lebih tinggi mengikis siluetnya menjadi tepian tipis menyerupai serabut. Peta cuaca (tekstur 2D yang diambil sampelnya berdasarkan XZ dunia) mengendalikan cakupan, jenis awan, dan presipitasi di setiap wilayah. Gradasi berbasis ketinggian memadukan profil kumulus, stratus, dan sirus berdasarkan ketinggian.</p>
<p>Renderer menelusuri sinar dari kamera menembus volume awan sambil mengakumulasi densitas dan hamburan. Iterasi &quot;Nubis&quot; pada 2017 menambahkan pembuatan konten dan animasi skala regional, sementara implementasi PS4 aslinya merender seluruh langit dalam waktu sekitar 2 milidetik. Sebagian besar studio yang kini merilis awan volumetrik masih menelusuri asal-usul teknik mereka ke makalah ini.</p>
<img src="/img/blog/clouds_weather_noise.webp" alt="Bentuk awan 3D yang diuraikan menjadi pola noise Perlin dan Worley bertumpuk, memperlihatkan cara detail mengikis siluetnya" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Schneider, <a href="https://www.guerrilla-games.com/read/the-real-time-volumetric-cloudscapes-of-horizon-zero-dawn">Bentang Awan Volumetrik Real-Time di Horizon Zero Dawn</a> (SIGGRAPH 2015, referensi kanonis).</li>
<li>Schneider, <a href="https://advances.realtimerendering.com/s2017/Nubis%20-%20Authoring%20Realtime%20Volumetric%20Cloudscapes%20with%20the%20Decima%20Engine%20-%20Final%20.pdf">Nubis: Membuat Bentang Awan Volumetrik Real-Time dengan Decima Engine</a> (SIGGRAPH 2017, tindak lanjut berskala regional).</li>
<li>Hillaire, <a href="https://media.contentapi.ea.com/content/dam/eacom/frostbite/files/s2016-pbs-frostbite-sky-clouds-new.pdf">Rendering Langit, Atmosfer, dan Awan Berbasis Fisika di Frostbite</a> (SIGGRAPH 2016, versi Frostbite).</li>
<li>Häggström, <a href="https://www.diva-portal.org/smash/get/diva2:1223894/FULLTEXT01.pdf">Rendering awan volumetrik secara real-time</a> (tesis yang jelas dan mudah dipahami, dengan kode shader lengkap).</li>
</ul>
<h2>3. Awan voxel dan Nubis³</h2>
<p>Evolusi Nubis pada 2023 sepenuhnya meninggalkan representasi bentuk 2,5D dan beralih ke voxel 3D sejati. Setiap voxel menyimpan densitas awan secara langsung, sehingga seniman dapat memahat dan menganimasikan bentuk awan seperti ketika mereka memahat medan. Biaya untuk beralih ke representasi yang lebih padat dikompensasi oleh akselerasi ray-march menggunakan signed distance field terkompresi dan teknik cerdas untuk meningkatkan resolusi data voxel yang jarang.</p>
<p>Hasilnya adalah bentang awan yang dapat diterbangi <em>dari dalam</em> tanpa membuat trik di baliknya terlihat rusak. Teknik ini berlebihan bagi kebanyakan studio, tetapi inilah arah perkembangan di kelas atas.</p>
<img src="/img/blog/clouds_weather_voxel_clouds.webp" alt="Awan kumulus yang diperlihatkan sebagai susunan grid voxel 3D, dengan tepian halus menyerupai serabut yang menyatu dengan bagian dalamnya yang tebal" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Schneider, <a href="https://www.guerrilla-games.com/read/nubis-cubed">Nubis³: Metode (dan kegilaan) untuk memodelkan dan merender awan berbasis voxel real-time yang imersif</a> (SIGGRAPH 2023, presentasi awan voxel).</li>
<li>Schneider, <a href="https://www.guerrilla-games.com/read/nubis-evolved">Nubis, Berevolusi</a> (SIGGRAPH 2022, jembatan antara 2,5D dan 3D penuh).</li>
<li>Schneider, <a href="https://www.schneidervfx.com/">Volumetrik dan VFX Real-Time</a> (situs pribadi Andrew, dengan catatan kursus dan uraian teknis).</li>
</ul>
<h2>4. Rendering awan berlapis dan latar 2D</h2>
<p>Tidak semua studio mampu menjalankan awan bervolume penuh, dan tidak semua sudut kamera membutuhkannya. Banyak game menggabungkan beberapa teknik: sirus di ketinggian tinggi dirender sebagai lapisan 2D yang bergulir, kumulus di ketinggian menengah sebagai sinar volumetrik, dan stratus di ketinggian rendah sebagai lapisan tipis media partisipatif. Cakrawala sering kali menggunakan cubemap langit yang telah dipanggang sebelumnya, lalu dipadukan oleh pass volumetrik setelah melewati jarak pemudaran.</p>
<p>Pelapisan inilah yang menjaga anggaran awan tetap masuk akal. Satu jenis awan pada kualitas penuh dapat menghabiskan 4–6 milidetik; melapiskan kualitas berbeda untuk ketinggian awan yang berbeda dapat mempertahankan tampilan yang sama dengan setengah biayanya.</p>
<img src="/img/blog/clouds_weather_cloud_layers.webp" alt="Langit matahari terbenam yang dibagi menjadi tiga lapisan awan: serabut sirus tinggi, gumpalan kumulus menengah, dan kabut stratus rendah di dekat cakrawala" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Vos, <a href="https://www.gdcvault.com/play/1023327/The-Real-Time-Volumetric-Cloudscapes">Bentang Awan Volumetrik Real-Time di Horizon Zero Dawn</a> (video GDC 2016, uraian pelapisan terdapat pada paruh kedua).</li>
<li>Bauer, <a href="https://www.youtube.com/watch?v=IYxtqlD1-Ac">Menciptakan Dunia Atmosferik Red Dead Redemption 2</a> (SIGGRAPH 2019, pipeline gabungan langit, awan, dan volumetrik RDR2).</li>
<li>Hillaire, <a href="https://www.gdcvault.com/play/1029105/Volumetric-Clouds-and">Awan volumetrik dan mega-partikel di REDengine 4</a> (GDC 2025, pipeline awan Cyberpunk 2077).</li>
</ul>
<h2>5. Kabut volumetrik dengan grid froxel</h2>
<p>Kabut adalah bidang 3D, bukan efek layar 2D. Pendekatan modern yang menjadi standar adalah grid froxel: tekstur 3D yang disejajarkan dengan frustum pandang kamera, dengan setiap sel (&quot;froxel&quot; = frustum + voxel) menyimpan densitas dan warna yang telah menerima pencahayaan. Compute shader memasukkan hamburan dari setiap sumber cahaya ke dalam grid, mengakumulasi ekstingsi sepanjang sinar pandang, lalu menerapkan hasilnya sebagai pass layar penuh.</p>
<p>Inilah yang menghasilkan berkas cahaya melalui jendela, kabut berwarna di sekitar lampu titik, dan volume yang terlihat di sekitar ledakan. Ini juga merupakan mekanisme dasar untuk &quot;perspektif atmosferik&quot; yang memudarkan objek jauh ke udara. Teknik ini diperkenalkan oleh Bart Wronski untuk Assassin's Creed 4 dan distandardisasi oleh Sébastien Hillaire di Frostbite.</p>
<img src="/img/blog/clouds_weather_froxel_fog.webp" alt="Frustum kamera yang divisualisasikan sebagai grid froxel 3D dengan sel lebih kecil di dekat kamera dan sel lebih besar di kejauhan, serta partikel kabut di dalamnya" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Wronski, <a href="https://bartwronski.com/wp-content/uploads/2014/08/bwronski_volumetric_fog_siggraph2014.pdf">Kabut Volumetrik: Solusi Terpadu Berbasis Compute Shader untuk Hamburan Atmosfer</a> (SIGGRAPH 2014, makalah grid froxel orisinal).</li>
<li>Hillaire, <a href="http://www.frostbite.com/2015/08/physically-based-unified-volumetric-rendering-in-frostbite/">Rendering Volumetrik Berbasis Fisika dan Terpadu di Frostbite</a> (SIGGRAPH 2015, implementasi siap produksi).</li>
<li>Kovalovs, <a href="https://history.siggraph.org/wp-content/uploads/2022/08/2020-Talks-Kovalovs_Volumetric-Effects-of-The-Last-of-Us-Part-Two.pdf">Efek Volumetrik The Last of Us Part Two</a> (SIGGRAPH 2020, dengan catatan tentang jitter temporal dan compositing yang memperhitungkan kedalaman).</li>
<li>Wright et al., <a href="https://advances.realtimerendering.com/s2022/SIGGRAPH2022-Advances-Lumen-Wright%20et%20al.pdf">Lumen: Iluminasi Global Real-Time di Unreal Engine 5</a> (SIGGRAPH 2022, mencakup interaksi Lumen dengan kabut volumetrik).</li>
</ul>
<h2>6. Sinar dewa dan berkas krepuskular</h2>
<p>Sinar matahari yang terlihat di udara berkabut bukanlah efek terpisah. Efek ini muncul dari sistem kabut yang sama, selama densitas kabut dan shadow map tersedia bagi compute shader yang sama. Ketika shader memasukkan cahaya ke dalam sebuah froxel, shader mengambil sampel shadow map pada posisi dunia froxel tersebut. Sel yang berada dalam bayangan tetap gelap, sementara sel yang terkena cahaya memperoleh warna matahari. Lakukan ray-march kamera melalui hasilnya dan sel-sel terang akan membentuk berkas yang berkesinambungan.</p>
<p>Varian screen-space yang lebih murah juga tersedia (radial blur dari posisi matahari ke dalam depth buffer) dan tetap menjadi pilihan tepat untuk perangkat seluler atau perangkat keras kelas bawah. Varian ini tidak dapat menangani posisi matahari di luar layar, tetapi biayanya nyaris nol.</p>
<img src="/img/blog/clouds_weather_god_rays.webp" alt="Hutan saat fajar dengan sinar matahari membelah sela-sela batang pohon dan kabut permukaan, membentuk berkas sinar dewa yang jelas" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Mitchell, <a href="https://developer.nvidia.com/gpugems/gpugems3/part-ii-light-and-shadows/chapter-13-volumetric-light-scattering-post-process">Hamburan Cahaya Volumetrik sebagai Pascaproses</a> (GPU Gems 3, pendekatan radial blur dalam screen-space).</li>
<li>Engelhardt dan Dachsbacher, <a href="https://cg.ivd.kit.edu/publications/2010/epipolar/EpipolarSampling.pdf">Sampling Epipolar untuk Bayangan dan Sinar Krepuskular dalam Media Partisipatif</a> (I3D 2010, teknik GPU yang lebih akurat).</li>
<li>Vos, <a href="https://www.guerrilla-games.com/read/volumetric-light-effects-in-killzone-shadow-fall">Efek Cahaya Volumetrik di Killzone: Shadow Fall</a> (SIGGRAPH 2014, versi produksi dengan integrasi bayangan).</li>
</ul>
<h2>7. Kilat dan peristiwa cuaca stokastik</h2>
<p>Kilat adalah efek satu frame dengan dua bagian: mesh sambaran kilat serta respons tonemap dan pencahayaan seluruh adegan. Kilat itu sendiri biasanya berupa mesh billboard prosedural yang dibuat menggunakan algoritma pembagian rekursif segmen garis, diberi jitter agar tampak acak, dan meruncing ke arah tanah. Beberapa engine merendernya sebagai kilatan aditif dalam screen-space, sementara yang lain menggunakan geometri emisif dengan pencahayaan penuh yang menerangi dunia melalui injeksi lampu titik selama satu frame.</p>
<p>Bagian yang menarik justru adalah semua hal <em>lainnya</em>: bagian bawah awan diterangi dari bawah, tanah menjadi lebih terang selama dua frame, pengukuran eksposur otomatis membutuhkan beberapa frame untuk pulih, dan suara guntur yang tertunda diputar berdasarkan jarak. Jika dikerjakan dengan baik, semua ini mengubah kilatan 16 milidetik menjadi rangkaian lima detik yang membuat cuaca terasa sebagai sesuatu yang terjadi di dalam dunia, bukan sekadar di atasnya.</p>
<img src="/img/blog/clouds_weather_lightning.webp" alt="Kilat bercabang yang menyambar dari awan badai saat senja, menerangi bagian bawah awan dan siluet desa kecil" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Reed dan Wyvill, <a href="https://dl.acm.org/doi/10.1145/192161.192256">Simulasi Visual Kilat</a> (SIGGRAPH 1994, algoritma sambaran rekursif yang masih digunakan semua orang).</li>
<li>Kim dan Lin, <a href="https://gamma.cs.unc.edu/POWER/">Animasi Kilat Cepat Menggunakan Mesh Adaptif</a> (IEEE TVCG 2007, lebih berlandaskan fisika).</li>
<li>Bauer, <a href="https://www.youtube.com/watch?v=IYxtqlD1-Ac">Menciptakan Dunia Atmosferik Red Dead Redemption 2</a> (SIGGRAPH 2019, pipeline badai RDR2, termasuk pengaturan waktu kilat).</li>
</ul>
<h2>8. Partikel hujan, mesh hujan, dan tetesan dalam screen-space</h2>
<p>Hujan yang turun dalam game modern jarang hanya berupa partikel. Solusi yang murah dan meyakinkan adalah sejumlah kecil tekstur bergulir yang direntangkan di atas quad vertikal atau quad yang sejajar dengan layar, lalu diterangi oleh probe matahari dan langit yang sama seperti semua elemen lainnya. Lebih dekat ke kamera, partikel guratan individual menambahkan detail. Pada lensa kamera itu sendiri, tekstur tetesan, jejak air yang mengalir, dan riak benturan menghadirkan kesan bahwa &quot;Anda berada di dalam badai&quot;.</p>
<p>Angin memengaruhi arah hujan. Vektor angin yang sama mendorong peta cuaca awan, membengkokkan rumput, dan memiringkan quad hujan. Satu vektor untuk seluruh adegan, puluhan penggunanya.
<img src="/img/blog/clouds_weather_rain_storm.webp" alt="Badai hujan lebat pada malam hari dengan curahan hujan yang diterangi lampu depan dari kejauhan dan riak di jalan basah" style="width:100%;border-radius:8px;margin:1.5rem 0" /></p>
<p>Bahasan mendalam:</p>
<ul>
<li>Tatarchuk, <a href="https://gpuopen.com/wp-content/uploads/2018/04/Tatarchuk-Rain-Rendering-EGSR2006.pdf">Rendering Hujan Real-Time yang Dapat Diarahkan Seniman di Lingkungan Perkotaan</a> (EGSR 2006, referensi utama untuk hujan berlapis).</li>
<li>Garg dan Nayar, <a href="https://www1.cs.columbia.edu/CAVE/projects/rain_ren/rain_ren.php">Rendering Fotorealistis Jejak Hujan</a> (SIGGRAPH 2006, fisika cahaya yang melewati tetes hujan).</li>
<li>Wojciechowski, <a href="https://www.gdcvault.com/play/1027382/Rain-In-Cyberpunk-2077">Hujan di Cyberpunk 2077</a> (GDC 2021, panduan produksi modern).</li>
</ul>
<h2>9. Permukaan basah, genangan, dan riak</h2>
<p>Hujan yang tidak mengubah tanah akan langsung terlihat palsu. Permukaan basah merespons dengan menggelapkan albedo (air menyerap cahaya yang datang), meratakan normal (lapisan air menghaluskan mikropermukaan), dan menurunkan kekasaran (air hampir menjadi cermin sempurna pada sudut pandang landai). Perubahan shader-nya kecil, tetapi perubahan visualnya sangat besar.</p>
<p>Genangan digerakkan oleh mask: mask berbasis ketinggian atau yang dilukis pada vertex menentukan titik-titik rendah yang terisi air seiring meningkatnya parameter &quot;wetness&quot;. Riak menggunakan tekstur normal map flipbook yang dipicu oleh benturan tetes hujan. Implementasi yang benar-benar bagus membangun kondisi kebasahan secara bertahap, sehingga badai hujan yang panjang perlahan membasahi dunia, sedangkan hujan singkat hanya menggelapkan bagian-bagian tinggi.</p>
<img src="/img/blog/clouds_weather_wet_surfaces.webp" alt="Jalan berbatu basah pada malam hari dengan genangan dangkal yang memantulkan papan neon dan lingkaran riak akibat benturan tetes hujan" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Bahasan mendalam:</p>
<ul>
<li>Lagarde dan de Rousiers, <a href="https://seblagarde.wordpress.com/2015/07/14/siggraph-2014-moving-frostbite-to-physically-based-rendering/">Memindahkan Frostbite ke Rendering Berbasis Fisika 3.0, bagian 5.5</a> (SIGGRAPH 2014, penyesuaian PBR permukaan basah yang menjadi rujukan utama).</li>
<li>Lagarde, <a href="https://seblagarde.wordpress.com/2011/08/17/feeding-a-physical-based-lighting-mode/">Mengadopsi Model Shading Berbasis Fisika</a> (seri blog asli dengan perhitungan PBR untuk permukaan basah).</li>
<li>Cyanilux, <a href="https://www.cyanilux.com/tutorials/rain-effects-breakdown/">Uraian Efek Hujan</a> (panduan Shader Graph yang mudah diikuti tentang genangan, riak, dan tetesan).</li>
</ul>
<h2>10. Akumulasi dan deformasi salju</h2>
<p>Salju adalah masalah yang simetris dengan hujan: dunia harus mengingatnya, bukan sekadar menerimanya. Pendekatan standar menggunakan tekstur &quot;akumulasi salju&quot; dari atas yang terbentuk seiring waktu di mana pun langit terlihat (dihitung terhadap depth map atau shadow map dari atas). Shader terrain mengambil sampel mask ini dan memadukan material salju di area teduh serta displacement salju yang dalam di area terbuka.</p>
<p>Jejak kaki dan bekas ban dirender ke deformation map bergeser yang berpusat pada pemain. Saat kamera bergerak, jejak kaki lama bergulir keluar dan teksturnya berulang dari sisi lainnya. Shader terrain atau salju mengambil sampel deformation map ini dan mendorong vertex ke bawah pada area yang telah ditulisi. Salju di Battlefield 5 melakukan ini dengan tessellation perangkat keras; pendekatan yang lebih ringan menggunakan mesh terrain berkepadatan tinggi hanya dengan vertex displacement.</p>
<img src="/img/blog/clouds_weather_snow_deformation.webp" alt="Lanskap bersalju bergaya dengan jejak kaki baru, timbunan salju di sekitar bebatuan, serpihan salju yang berjatuhan, dan pegunungan jauh yang berkabut" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Bahasan mendalam:</p>
<ul>
<li>Barré-Brisebois, <a href="https://www.digitalfoundry.net/articles/digitalfoundry-2018-hands-on-with-battlefield-5s-closed-alpha">Mencoba Langsung Battlefield 5: Mengapa Hal-Hal Kecil Itu Penting</a> (ulasan produksi tentang salju Frostbite).</li>
<li>St-Amour, <a href="https://is.muni.cz/th/m2v6i/real-time_snow_deformation.txt?lang=cs">Deformasi Salju Real-Time</a> (tesis dengan detail lengkap implementasi GPU).</li>
<li>Andersson, <a href="https://media.contentapi.ea.com/content/dam/eacom/frostbite/files/chapter5-andersson-terrain-rendering-in-frostbite.pdf">Rendering Terrain di Frostbite Menggunakan Procedural Shader Splatting</a> (fondasi sistem splat yang menjadi landasan akumulasi salju).</li>
</ul>
<h2>11. Angin sebagai sistem global</h2>
<p>Angin bukan efek partikel. Dalam engine produksi, angin adalah satu vektor global (terkadang field 3D beresolusi rendah) yang dibaca oleh <em>setiap</em> sistem dinamis dalam vertex shader-nya. Bilah rumput melengkung, cabang pohon bergoyang, kain berkibar, daun beterbangan, hujan menjadi miring, asap terbawa, dan weather map awan bergulir. Satu uniform diperbarui per frame, dengan puluhan konsumen.</p>
<p>Versi yang lebih kaya adalah &quot;wind grid&quot; yang menyimpan arah dan kekuatan berdasarkan sampel posisi dunia, sehingga memungkinkan badai dengan embusan terlokalisasi, lembah yang terlindungi, dan olakan di belakang bangunan. Vegetasi juga biasanya mendapatkan offset per vertex yang disematkan saat proses authoring agar pohon-pohon identik tidak bergoyang serempak. Hasilnya adalah dunia yang bernapas dengan irama yang sama.</p>
<img src="/img/blog/clouds_weather_wind_foliage.webp" alt="Angin kencang meniup rumput dan pepohonan ke samping, dengan dedaunan berpusar di latar depan di bawah awan badai" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Bahasan mendalam:</p>
<ul>
<li>McAuley, <a href="https://www.gdcvault.com/play/1022235/Rendering-the-World-of-Far">Merender Dunia Far Cry 4</a> (GDC 2015, mencakup wind grid Far Cry 4 untuk vegetasi).</li>
<li>Habel dan Wimmer, <a href="https://www.cg.tuwien.ac.at/research/publications/2007/HABEL-2007-IIM/">Rendering Lanskap Realistis Secara Real-Time Menggunakan Billboard Clouds</a> (lebih lama, tetapi perhitungan angin pada vegetasinya tidak berubah).</li>
<li>Frostbite, <a href="https://www.guerrilla-games.com/read/the-vegetation-of-horizon-zero-dawn">Vegetasi Horizon Zero Dawn</a> (SIGGRAPH 2017, dengan arsitektur sistem anginnya).</li>
</ul>
<h2>12. Badai pasir, badai salju, dan cuaca pekat</h2>
<p>Cuaca ekstrem merupakan kategori rendering tersendiri. Badai pasir adalah kabut tebal dan buram yang sejajar dengan permukaan tanah, dengan bias arah yang kuat dan kabut jarak jauh yang agresif. Badai salju menambahkan semburan partikel di dekat kamera dan mengurangi jarak pandang. Abu vulkanik dan asap menggunakan arsitektur yang sama dengan warna berbeda.</p>
<p>Yang membuat semua ini meyakinkan bukanlah partikelnya, melainkan <em>keterpaduannya</em>: matahari meredup, langit berubah warna, color grading pascaproses bergeser, audio ambien berganti, suara langkah kaki berubah, dan suara pemain menjadi teredam jika mereka memilikinya. Renderer hanyalah pembawa pesan; imersi tercipta ketika setiap sistem dalam game merespons secara bersamaan.</p>
<img src="/img/blog/clouds_weather_sandstorm.webp" alt="Dinding debu dan pasir jingga bergulung melintasi dataran gurun, dengan langit kelam di atasnya dan langit biru cerah di belakangnya" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Bahasan mendalam:</p>
<ul>
<li>Burley, <a href="https://www.gdcvault.com/play/1024954/The-Real-time-Sky-and">Langit dan Atmosfer Real-Time di Uncharted: The Lost Legacy</a> (GDC 2018, dengan catatan tentang komposisi cuaca pekat).</li>
<li>Khalifa, <a href="https://www.gdcvault.com/play/1027587/Atmospheric-Weather-Effects-in-Forza">Efek Cuaca Atmosfer di Forza Horizon 5</a> (GDC 2022, cuaca dunia terbuka modern).</li>
<li>Karis, <a href="https://advances.realtimerendering.com/s2021/">Teknologi di Balik Demo Unreal Engine 5 &quot;Lumen in the Land of Nanite&quot;</a> (SIGGRAPH 2021, tumpukan volumetrik pada adegan debu gua).</li>
</ul>
<h2>13. Waktu dan langit dinamis</h2>
<p>Waktu real-time adalah pengganda yang membuat setiap sistem lain dalam daftar ini layak dirilis. Arah dan warna matahari diperbarui dalam siklus 24 menit atau 24 jam. LUT atmosfer diperbarui mengikuti sudut matahari. Pencahayaan awan dihitung ulang per frame. Shadow cascade diarahkan ulang. Reflection probe disegarkan. Warna ambien bergeser. Eksposur pascaproses beradaptasi.</p>
<p>Melakukan semua ini tanpa artefak yang terlihat sebagian besar bergantung pada caching tekstur dan stabilitas temporal. Teknik cepat melakukan prakomputasi langit pada sudut matahari tertentu lalu menginterpolasinya; teknik yang lebih lambat menghitung ulang setiap frame. Model atmosfer Hillaire 2020 cukup cepat untuk dihitung ulang, itulah sebabnya UE5 menyertakannya. Weather map awan bergulir bersama angin, sehingga cakupan awan berubah secara alami tanpa perlu membuat keyframe secara manual.</p>
<img src="/img/blog/clouds_weather_time_of_day.webp" alt="Tiga bidang vertikal pada satu lanskap: fajar merah muda, siang biru, dan senja merah, semuanya memiliki siluet bukit yang sama" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Bahasan mendalam:</p>
<ul>
<li>Hillaire, <a href="https://sebh.github.io/publications/egsr2020.pdf">Teknik Rendering Langit dan Atmosfer yang Skalabel dan Siap Produksi</a> (EGSR 2020, dengan pembahasan waktu dinamis).</li>
<li>Pesce, <a href="https://www.realtimerendering.com/raytracinggems/rtg2/index.html">Rendering Langit Real-Time: Teknik dan Kompromi</a> (bab Ray Tracing Gems II, tinjauan modern).</li>
<li>Bauer, <a href="https://www.youtube.com/watch?v=IYxtqlD1-Ac">Menciptakan Dunia Atmosferik Red Dead Redemption 2</a> (SIGGRAPH 2019, dengan pipeline 24 jam).</li>
</ul>
<h2>14. State machine cuaca</h2>
<p>Di balik semua ini terdapat state machine kecil. Sebagian besar game memiliki antara 4 hingga 12 kondisi cuaca (cerah, berawan sebagian, mendung, hujan ringan, hujan lebat, badai petir, berkabut, bersalju, badai salju, badai pasir), yang masing-masing ditentukan oleh sekumpulan parameter: cakupan dan jenis awan, kecepatan dan arah angin, jenis dan intensitas presipitasi, rona warna ambien, profil audio, serta grade pascaproses.</p>
<p>Transisi adalah interpolasi linear di antara kumpulan parameter selama 30 hingga 120 detik. Transisi bukanlah kasus khusus, melainkan hanya dua state yang di-lerp, dengan setiap subsistem rendering membaca nilai parameter saat ini pada frame tersebut. Cuaca dapat diatur oleh skrip (cutscene membutuhkan badai), menggunakan seed (deterministik per wilayah per hari dalam game agar dua pemain di dunia yang sama melihat cuaca yang sama), atau di-authoring sepenuhnya pada grid wilayah. Pipeline yang paling rapi memperlakukan ketiganya sebagai scheduler berbeda yang menulis ke buffer parameter yang sama.</p>
<img src="/img/blog/clouds_weather_state_machine.webp" alt="Adegan yang sama berdampingan, dengan matahari cerah di sebelah kiri dan hujan badai di sebelah kanan serta permukaan basah yang berkilau" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Bahasan mendalam:</p>
<ul>
<li>Bauer, <a href="https://www.youtube.com/watch?v=IYxtqlD1-Ac">Menciptakan Dunia Atmosferik Red Dead Redemption 2</a> (SIGGRAPH 2019, dengan pipeline state cuaca).</li>
<li>Khalifa, <a href="https://www.gdcvault.com/play/1027587/Atmospheric-Weather-Effects-in-Forza">Efek Cuaca Atmosfer di Forza Horizon 5</a> (GDC 2022, dengan pendekatan perpaduan parameter).</li>
<li>Schneider, <a href="https://www.guerrilla-games.com/read/the-real-time-volumetric-cloudscapes-of-horizon-zero-dawn">Bentang Awan Volumetrik Real-Time di Horizon Zero Dawn</a> (SIGGRAPH 2015, dengan evolusi awan berbasis weather map).</li>
</ul>
<h2>15. Momen sinematik</h2>
<p>Seluruh tumpukan ini dibuat demi beberapa momen khas. Berdiri di punggung bukit saat garis depan badai mendekat. Menyaksikan berkas sinar matahari menembus celah di antara kanopi. Berjalan keluar dari gua menuju salju. Terbang menembus awan kumulus dan melihat cahaya di bagian dalamnya.</p>
<p>Inilah momen-momen yang diabadikan pemain dalam tangkapan layar. Ini juga momen ketika setiap sistem di atas harus bekerja secara bersamaan: volumetrik awan, hamburan atmosfer, kabut dengan integrasi bayangan, PBR basah, angin pada vegetasi, color grading berdasarkan waktu, dan transisi antar-kondisi cuaca, semuanya dikomposisikan menjadi satu frame. Jika satu saja keliru, keajaibannya langsung sirna.</p>
<img src="/img/blog/clouds_weather_cloud_sea.webp" alt="Pemandangan dari atas lautan awan menuju satu puncak gunung yang menjulang, dengan puncak awan tersinari matahari dan lembah gelap di bawahnya" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<h2>Artinya bagi browser</h2>
<p>Sebagian besar teknik ini dapat dipetakan dengan mudah ke WebGPU. Kami telah merilis kabut atmosfer dasar, perpaduan skybox equirectangular, dan kabut jarak berbasis screen-space dalam <a href="/id/blog/2026-02-25-open-world-browser-series-guide">engine dunia terbuka untuk browser</a>. Bagian yang lebih sulit (awan volumetrik penuh, kabut grid froxel, PBR basah dengan genangan dinamis, dan deformation map salju) adalah langkah berikutnya yang jelas setelah pipeline terrain stabil. Pengambilan sampel warna kabut per fragmen dari skybox pada Spike 24 adalah salah satu bagian dari teka-teki ini. Berikutnya adalah cloud raymarcher berbasis compute shader yang mengirimkan hasilnya ke LUT atmosfer yang sama.</p>
<p>Kabar baiknya, standar minimum perangkat keras browser kini sudah cukup tinggi. WebGPU compute, tekstur 3D, indirect dispatch, dan timestamp query semuanya tersedia. Atmosfer Hillaire 2020 telah beberapa kali di-porting ke WebGL. Nubis karya Schneider memiliki implementasi referensi sumber terbuka dalam GLSL yang dapat diterjemahkan ke WGSL dengan perubahan mekanis. Tidak ada lagi alasan dari sisi rendering yang membuat game browser tidak dapat memiliki langit yang sama dengan game konsol. Yang tersisa hanyalah alasan rekayasa, dan alasan rekayasa adalah jenis tantangan yang kami sukai.</p>
<h2>Bacaan lebih lanjut tentang seluruh tumpukan</h2>
<p>Jika Anda menginginkan satu sumber yang menyatukan semua ini, arsip SIGGRAPH &quot;Advances in Real-Time Rendering in Games&quot; (<a href="https://advances.realtimerendering.com/">advances.realtimerendering.com</a>) memiliki presentasi utama tentang cuaca dan atmosfer sejak 2014. Untuk analisis produksi mengenai cara game tertentu merender langit dan cuacanya, <a href="http://www.adriancourreges.com/blog/">artikel profiling GPU Adrian Courrèges</a> mencakup uraian mendetail frame demi frame untuk GTA V, Horizon Zero Dawn, dan Doom Eternal. Khusus untuk perhitungan langit dan atmosfer, <a href="https://www.scratchapixel.com/lessons/3d-basic-rendering/volume-rendering-for-developers/intro-volume-rendering.html">bab rendering volume di scratchapixel.com</a> adalah pengantar yang paling mudah diikuti, sedangkan <a href="https://github.com/sebh/UnrealEngineSkyAtmosphere">repositori implementasi</a> sumber terbuka Hillaire merupakan referensi berkualitas produksi.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Daftar singkat teknik rendering yang digunakan dalam game AAA modern]]></title>
            <link>https://app.cinevva.com/id/blog/2026-05-03-aaa-rendering-techniques</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-05-03-aaa-rendering-techniques</guid>
            <pubDate>Sun, 03 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Teknik rendering inti di balik visual AAA masa kini, dari geometri tervirtualisasi Nanite hingga path tracing ReSTIR dan peningkatan resolusi berbasis ML, lengkap dengan referensi teknis mendalam untuk masing-masing teknik.]]></description>
            <content:encoded><![CDATA[<h1>Daftar singkat teknik rendering yang digunakan dalam game AAA modern</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<img src="/img/blog/aaa_rendering_hero.webp" alt="Adegan komposit yang menampilkan material PBR, geometri tervirtualisasi, dan pencahayaan ray tracing dalam game AAA modern" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Jika Anda membedah pipeline rendering sebuah game AAA tahun 2026, sebagian besar hal yang ditemukan dapat ditelusuri kembali ke sejumlah kecil teknik yang digunakan oleh berbagai studio. Namanya berbeda-beda di setiap engine, tetapi gagasannya sama. Berikut daftar singkat teknik yang benar-benar bekerja di layar, lengkap dengan ilustrasi dan beberapa referensi teknis mendalam untuk masing-masing teknik.</p>
<h2>1. Rendering berbasis fisika (PBR)</h2>
<p>Material dideskripsikan melalui tekstur albedo, kekasaran, metalik, normal, dan oklusi ambien, lalu disinari oleh shader yang mempertahankan energi (spekular Cook-Torrance serta difus Lambertian atau Disney). Ini adalah standar dasar yang diasumsikan oleh setiap engine AAA modern. Jika sebuah permukaan tampak konsisten di bawah sinar matahari, cahaya lampu, dan senter, PBR adalah alasannya.</p>
<img src="/img/blog/aaa_pbr_materials.webp" alt="Helm besi yang dirender dengan material PBR, disertai sampel tekstur melayang yang menampilkan peta albedo, kekasaran, metalik, dan normal" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Burley, <a href="https://media.disneyanimation.com/uploads/production/publication_asset/48/asset/s2012_pbs_disney_brdf_notes_v3.pdf">Shading Berbasis Fisika di Disney</a> (catatan kursus &quot;Disney BRDF&quot; asli, SIGGRAPH 2012).</li>
<li>Karis, <a href="https://cdn2.unrealengine.com/Resources/files/2013SiggraphPresentationsNotes-26915738.pdf">Shading Nyata di Unreal Engine 4</a> (SIGGRAPH 2013, presentasi PBR UE4 yang menjadi acuan).</li>
<li>Lagarde dan de Rousiers, <a href="https://seblagarde.wordpress.com/2015/07/14/siggraph-2014-moving-frostbite-to-physically-based-rendering/">Memindahkan Frostbite ke Rendering Berbasis Fisika 3.0</a> (SIGGRAPH 2014, pipeline Frostbite lengkap).</li>
<li><a href="https://www.realtimerendering.com/">Real-Time Rendering, edisi ke-4, bab 9</a> (referensi buku teks).</li>
</ul>
<h2>2. Deferred shading dan visibility-buffer shading</h2>
<p>Geometri terlebih dahulu menulis atribut (normal, ID material, kedalaman) ke dalam G-buffer atau visibility buffer. Pencahayaan dijalankan sebagai pass layar penuh yang membaca buffer tersebut dan melakukan shading pada setiap piksel satu kali. Visibility buffer (yang digunakan oleh Nanite dan teknologi serupa) mengembangkan pendekatan ini lebih lanjut dengan hanya menyimpan ID segitiga, kemudian menghitung parameter material per piksel pada tahap berikutnya. Hal ini menjaga biaya overdraw tetap rendah pada geometri yang padat.</p>
<img src="/img/blog/aaa_deferred_gbuffer.webp" alt="G-buffer deferred shading yang dibagi menjadi panel warna akhir, normal dunia, kedalaman, dan ID material" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Engel, <a href="https://download.nvidia.com/developer/presentations/2004/6800_Leagues/6800_Leagues_Deferred_Shading.pdf">Deferred Shading</a> (NVIDIA, presentasi yang menjadi landasan).</li>
<li>Burns dan Hunt, <a href="http://jcgt.org/published/0002/02/04/">Visibility Buffer: Pendekatan Ramah Cache untuk Deferred Shading</a> (JCGT 2013, makalah visibility buffer asli).</li>
<li>Wihlidal, <a href="http://www.frostbite.com/2016/03/optimizing-the-graphics-pipeline-with-compute/">&quot;Mengoptimalkan Pipeline Grafis dengan Compute&quot;</a> (GDC 2016, jalur deferred berbasis compute milik Frostbite).</li>
<li>Karis, Stubbe, Wihlidal, <a href="https://advances.realtimerendering.com/s2021/Karis_Nanite_SIGGRAPH_Advances_2021_final.pdf">Pembahasan Mendalam Geometri Tervirtualisasi Nanite</a> (SIGGRAPH 2021, mencakup visibility buffer Nanite secara mendetail).</li>
</ul>
<h2>3. Geometri tervirtualisasi (gaya Nanite)</h2>
<p>Mesh diproses terlebih dahulu menjadi hierarki cluster. Saat runtime, GPU melakukan streaming dan memilih cluster pada resolusi yang sesuai dengan setiap piksel, sehingga Anda mendapatkan detail akurat hingga tingkat subpiksel tanpa LOD manual. Nanite dari Unreal adalah contoh yang paling dikenal. Engine lain kini juga menyediakan variannya masing-masing. Hasil praktisnya adalah aset berkualitas film secara real-time tanpa perlu membuat LOD secara manual.</p>
<img src="/img/blog/aaa_virtualized_geometry.webp" alt="Render mulus di sebelah kiri dan cluster meshlet subpiksel berwarna cerah di sebelah kanan" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Karis, Stubbe, Wihlidal, <a href="https://advances.realtimerendering.com/s2021/Karis_Nanite_SIGGRAPH_Advances_2021_final.pdf">Pembahasan Mendalam Geometri Tervirtualisasi Nanite</a> (SIGGRAPH 2021).</li>
<li>Brian Karis, <a href="https://www.youtube.com/watch?v=eviSykqSUUw">Presentasi Nanite di GDC 2021</a> (penjelasan video yang mudah diikuti).</li>
<li>Liktor, <a href="https://research.activision.com/publications/2021/09/geometry-rendering-pipeline-architecture-at-activision">Arsitektur Pipeline Rendering Geometri di Activision</a> (rendering berbasis cluster, 2021).</li>
<li>Schied et al., <a href="https://research.nvidia.com/publication/2017-07_spatiotemporal-variance-guided-filtering-real-time-reconstruction-path-traced">Pemfilteran Berpanduan Varians Spasiotemporal</a> (teknik culling cluster terkait).</li>
</ul>
<h2>4. Ray tracing real-time untuk bayangan, pantulan, dan AO</h2>
<p>Ray tracing berbasis perangkat keras (DXR, Vulkan RT) menelusuri sinar bayangan, sinar pantulan cermin dan mengilap, serta sinar oklusi ambien terhadap BVH yang dibuat pada setiap frame. Bahkan beberapa sinar per piksel mampu mengungguli teknik screen-space, terutama untuk pantulan objek di luar layar dan bayangan kontak. Sebagian besar game menggunakannya secara selektif, bukan untuk segala hal.</p>
<img src="/img/blog/aaa_hardware_raytracing.webp" alt="Mobil sport merah mengilap di ruang pamer mewah dengan pantulan ray tracing dan bayangan kontak yang akurat" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Microsoft, <a href="https://microsoft.github.io/DirectX-Specs/d3d/Raytracing.html">Spesifikasi Fungsional DirectX Raytracing (DXR)</a> (referensi API).</li>
<li>Wyman, <a href="http://intro-to-dxr.cwyman.org/">Pengantar DirectX Raytracing</a> (catatan kursus SIGGRAPH yang sangat mudah dipahami).</li>
<li>Boksansky dan Marrs, <a href="https://www.realtimerendering.com/raytracinggems/rtg2/index.html">Ray Tracing Gems II, bab 17–19</a> (PDF gratis, teknik DXR modern).</li>
<li>Stachowiak, <a href="https://www.ea.com/frostbite/news/stochastic-screen-space-reflections">Pantulan Screen-Space Stokastik</a> (Frostbite, jembatan dari SSR menuju RT).</li>
</ul>
<h2>5. Ray tracing berbasis perangkat lunak (gaya Lumen)</h2>
<p>Tidak semua pemain memiliki kartu RTX, sehingga engine juga menyediakan fallback berbasis distance field atau surface cache. Lumen dari Unreal, misalnya, melakukan tracing terhadap signed distance field dan surface cache untuk menghasilkan GI difus berbiaya rendah, lalu hanya beralih ke sinar berbasis perangkat keras saat diperlukan. Inilah cara game AAA menghadirkan “tampilan ray tracing” pada konsol.</p>
<img src="/img/blog/aaa_software_rt_lumen.webp" alt="Interior katedral dengan pantulan warna kaca patri dan overlay wireframe SDF yang memperlihatkan geometri hasil pendekatan" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Wright et al., <a href="https://advances.realtimerendering.com/s2022/SIGGRAPH2022-Advances-Lumen-Wright%20et%20al.pdf">Lumen: Iluminasi Global Real-Time di Unreal Engine 5</a> (SIGGRAPH 2022, makalah Lumen).</li>
<li>Epic Games, <a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/lumen-technical-details-in-unreal-engine">Detail Teknis Lumen</a> (dokumentasi engine resmi).</li>
<li>Wright, <a href="https://advances.realtimerendering.com/s2021/Wright%20et%20al%20-%20Radiance%20Caching%20for%20Real-Time%20Global%20Illumination%20-%20SIGGRAPH%202021.pdf">Radiance Caching untuk Iluminasi Global Real-Time</a> (SIGGRAPH 2021).</li>
<li>Wright, <a href="https://www.youtube.com/watch?v=2GYXuM10riw">Presentasi Lumen di GDC 2022</a> (versi video).</li>
</ul>
<h2>6. ReSTIR dan reservoir sampling</h2>
<p>Untuk pencahayaan langsung dan tidak langsung dengan ribuan sumber cahaya, ReSTIR (Reservoir Spatio-Temporal Importance Resampling) menggunakan kembali sampel cahaya antarpiksel dan antarframe. Inilah cara game seperti Cyberpunk 2077 dengan Path Tracing menjaga noise tetap rendah hanya dengan satu atau dua sinar per piksel. Teknik ini diperkirakan akan muncul di lebih banyak engine seiring path tracing menjadi target untuk perangkat kelas atas.</p>
<img src="/img/blog/aaa_ray_tracing_restir.webp" alt="Jalan bergaya cyberpunk dengan pantulan ray tracing pada permukaan jalan basah dan jalur pantulan cahaya yang terlihat" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Bitterli et al., <a href="https://research.nvidia.com/sites/default/files/pubs/2020-07_Spatiotemporal-reservoir-resampling/ReSTIR.pdf">Reservoir Resampling Spasiotemporal untuk Ray Tracing Real-Time dengan Pencahayaan Langsung Dinamis</a> (SIGGRAPH 2020, makalah ReSTIR asli).</li>
<li>Ouyang et al., <a href="https://research.nvidia.com/publication/2021-06_restir-gi-path-resampling-real-time-path-tracing">ReSTIR GI: Path Resampling untuk Path Tracing Real-Time</a> (HPG 2021, ReSTIR untuk iluminasi tidak langsung).</li>
<li>Lin et al., <a href="https://research.nvidia.com/publication/2022-07_generalized-resampled-importance-sampling-foundations-restir">Generalized Resampled Importance Sampling</a> (SIGGRAPH 2022, landasan matematisnya).</li>
<li>NVIDIA, <a href="https://www.nvidia.com/en-us/geforce/news/cyberpunk-2077-ray-tracing-overdrive-technology-preview-on-rtx-4090/">Pembahasan Teknis Mendalam Path Tracing Cyberpunk 2077</a> (blog engineering).</li>
</ul>
<h2>7. Awan volumetrik, kabut, dan atmosfer</h2>
<p>Langit dirender dengan ray marching melalui noise 3D dan volume densitas. Atmosfer menggunakan tabel scattering yang telah dihitung sebelumnya (gaya Bruneton) untuk transisi matahari dan bulan. Kabut menggunakan grid froxel (bayangkan tekstur 3D yang diselaraskan dengan frustum pandangan) untuk menangkap pencahayaan lokal. Jika digabungkan, teknik-teknik ini menghadirkan “cuaca sebagai sebuah sistem”, bukan sekadar skybox.</p>
<img src="/img/blog/aaa_volumetrics.webp" alt="Lembah pegunungan saat matahari terbenam dengan awan volumetrik dan berkas cahaya yang menembus udara berkabut" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Schneider, <a href="https://www.guerrilla-games.com/read/the-real-time-volumetric-cloudscapes-of-horizon-zero-dawn">Bentang Awan Volumetrik Real-Time di Horizon Zero Dawn</a> (SIGGRAPH 2015, referensi awan yang menjadi acuan).</li>
<li>Hillaire, <a href="https://sebh.github.io/publications/egsr2020.pdf">Teknik Rendering Langit dan Atmosfer yang Skalabel dan Siap Produksi</a> (EGSR 2020, penerus modern Bruneton yang digunakan di UE5).</li>
<li>Wronski, <a href="https://bartwronski.com/2014/08/22/volumetric-fog-siggraph-2014/">Kabut Volumetrik: Solusi Terpadu Berbasis Compute Shader untuk Atmospheric Scattering</a> (SIGGRAPH 2014, kabut froxel Assassin's Creed 4).</li>
<li>Hillaire, <a href="https://www.ea.com/frostbite/news/physically-based-unified-volumetric-rendering-in-frostbite">Rendering Volumetrik Terpadu dan Berbasis Fisika di Frostbite</a> (SIGGRAPH 2015).</li>
</ul>
<h2>8. Cascaded shadow maps dan virtual shadow maps</h2>
<p>Untuk bayangan matahari, cascaded shadow maps membagi frustum menjadi beberapa rentang dan merender setiap rentang pada resolusi yang sesuai. Virtual shadow maps melangkah lebih jauh: satu shadow map berukuran sangat besar dibagi menjadi halaman-halaman, dan hanya halaman yang terlihat dari kamera yang dirender. Dengan cara ini, game AAA dapat mempertahankan bayangan yang tajam di dekat pemain tanpa membutuhkan memori dalam jumlah sangat besar.</p>
<img src="/img/blog/aaa_cascaded_shadows.webp" alt="Adegan luar ruangan dengan overlay tiga frustum cascade berwarna yang memperlihatkan detail bayangan di dekat kamera" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Dimitrov, <a href="https://developer.download.nvidia.com/SDK/10.5/opengl/src/cascaded_shadow_maps/doc/cascaded_shadow_maps.pdf">Cascaded Shadow Maps</a> (whitepaper NVIDIA, referensi standar).</li>
<li>Microsoft, <a href="https://learn.microsoft.com/en-us/windows/win32/dxtecharts/cascaded-shadow-maps">Teknik Umum untuk Meningkatkan Shadow Depth Maps</a> (dokumentasi DirectX).</li>
<li>Wright, <a href="https://advances.realtimerendering.com/s2023/index.html#VirtualShadowMaps">Virtual Shadow Maps di Fortnite Battle Royale Bab 4</a> (SIGGRAPH 2023, presentasi VSM UE5).</li>
<li>Epic Games, <a href="https://dev.epicgames.com/documentation/en-us/unreal-engine/virtual-shadow-maps-in-unreal-engine">Dokumentasi Virtual Shadow Maps</a>.</li>
</ul>
<h2>9. Efek screen-space (SSAO, SSR, SSGI, SSSSS)</h2>
<p>Dengan membaca buffer kedalaman dan normal secara efisien, Anda dapat memperoleh oklusi ambien (SSAO), pantulan (SSR), iluminasi global satu pantulan (SSGI), serta subsurface scattering untuk kulit (SSSSS). Teknik-teknik ini tidak dapat menangkap detail di luar layar, sehingga ray tracing mulai menggantikannya. Meski demikian, semuanya masih digunakan secara luas sebagai solusi dasar yang cepat.</p>
<img src="/img/blog/aaa_screen_space_effects.webp" alt="Perbandingan berdampingan adegan dapur dengan pencahayaan datar di sebelah kiri serta SSAO, SSR, dan SSGI di sebelah kanan" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Mittring, <a href="https://www.crytek.com/wp-content/uploads/Finding%20Next%20Gen%20-%20CryEngine%202.pdf">Menemukan Generasi Berikutnya: CryENGINE 2</a> (SIGGRAPH 2007, makalah SSAO asli).</li>
<li>McGuire et al., <a href="https://research.nvidia.com/publication/scalable-ambient-obscurance">Scalable Ambient Obscurance</a> (HPG 2012, SSAO modern).</li>
<li>Stachowiak dan Uludag, <a href="https://www.ea.com/frostbite/news/stochastic-screen-space-reflections">Pantulan Screen-Space Stokastik</a> (Frostbite, referensi SSR).</li>
<li>Jimenez, <a href="https://www.iryoku.com/separable-sss/">Separable Subsurface Scattering</a> (teknik yang digunakan untuk kulit di sebagian besar engine AAA).</li>
<li>Mara et al., <a href="https://research.activision.com/publications/2016/09/deep-g-buffers-for-stable-global-illumination-approximation">Deep Screen Space</a> (Activision, salah satu cikal bakal SSGI).</li>
</ul>
<h2>10. Temporal anti-aliasing dan peningkatan resolusi berbasis ML (DLSS, FSR, XeSS)</h2>
<p>Frame dirender pada resolusi internal yang lebih rendah, lalu direkonstruksi menggunakan vektor gerakan, kedalaman, dan riwayat frame. Upscaler berbasis ML (DLSS 3/4, FSR 3, XeSS) menambahkan pembuatan frame di atasnya dengan menginterpolasi frame perantara berdasarkan optical flow. Sebagian besar judul AAA kini dirancang dengan asumsi bahwa upscaler akan diaktifkan, yang mengubah cara Anda mengalokasikan anggaran performa untuk bagian frame lainnya.</p>
<img src="/img/blog/aaa_ml_upscaling.webp" alt="Perbandingan berdampingan antara input beresolusi rendah dan output tajam hasil rekonstruksi ML dari karakter yang sama" style="width:100%;border-radius:8px;margin:1.5rem 0" />
Pembahasan mendalam:
- Karis, [Supersampling Temporal Berkualitas Tinggi](http://advances.realtimerendering.com/s2014/index.html#_HIGH-QUALITY_TEMPORAL_SUPERSAMPLING) (SIGGRAPH 2014, presentasi TAA yang menjadi rujukan utama).
- Salvi, [Eksplorasi Supersampling Temporal](https://research.nvidia.com/sites/default/files/pubs/2016-03_An-Excursion-in/dlss_DTAA-2-2.pdf) (NVIDIA, dalam perjalanan menuju DLSS).
- Edelsten, [Benar-Benar Generasi Berikutnya: Menambahkan Deep Learning ke Game dan Grafis](https://www.gdcvault.com/play/1026184/) (GDC 2019, arsitektur DLSS).
- AMD, [Detail teknis FidelityFX Super Resolution 3](https://gpuopen.com/fidelityfx-super-resolution-3/) dan Intel, [Makalah teknis XeSS](https://www.intel.com/content/www/us/en/developer/articles/technical/intel-xess-technical-paper.html).
<h2>11. Rendering berbasis GPU dan mesh shader</h2>
<p>Culling, pemilihan LOD, dan pengiriman perintah draw semuanya berjalan di GPU. Mesh shader menggantikan pipeline vertex/geometri/teselasi dengan tahap bergaya komputasi yang lebih fleksibel dan menghasilkan meshlet. Dipadukan dengan multi-draw indirect, pendekatan ini sepenuhnya mengeluarkan CPU dari loop kritis per objek.</p>
<img src="/img/blog/aaa_gpu_driven_meshlets.webp" alt="Pemandangan pelabuhan antariksa alien dengan overlay klaster meshlet berwarna yang memperlihatkan rendering berbasis GPU" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Haar dan Aaltonen, <a href="https://advances.realtimerendering.com/s2015/aaltonenhaar_siggraph2015_combined_final_footer_220dpi.pdf">Pipeline Rendering Berbasis GPU</a> (SIGGRAPH 2015, presentasi mendasar tentang Assassin's Creed Unity).</li>
<li>Wihlidal, <a href="https://www.frostbite.com/2016/03/optimizing-the-graphics-pipeline-with-compute/">Mengoptimalkan Pipeline Grafis dengan Komputasi</a> (GDC 2016, culling berbasis GPU di Frostbite).</li>
<li>Kubisch, <a href="https://developer.nvidia.com/blog/introduction-turing-mesh-shaders/">Pengantar Mesh Shader Turing</a> (NVIDIA, panduan dasar mesh shader).</li>
<li>Pesce, <a href="https://www.bartwronski.com/">Tur Singkat Mesh Shader</a> (serta blog rekayasa serupa yang dikumpulkan dalam <a href="http://www.adriancourreges.com/blog/">analisis RenderDoc oleh Adrian Courrèges</a>).</li>
</ul>
<h2>12. Rendering rambut, kain, dan kulit</h2>
<p>Rambut menggunakan shading anisotropik bergaya Marschner dengan geometri berbasis helai (NVIDIA HairWorks, AMD TressFX, atau sistem bawaan engine). Kain disimulasikan di GPU dengan dinamika berbasis posisi dan dirender dengan spekular anisotropik. Kulit menggunakan hamburan bawah permukaan berbasis ruang layar ditambah pencahayaan wrap yang telah dipraintegrasikan. Ketiganya biasanya menjadi area tempat kesenjangan anggaran antara produksi AAA dan indie paling terlihat.</p>
<img src="/img/blog/aaa_hair_cloth_skin.webp" alt="Tampilan jarak dekat seorang pejuang dengan rambut berbasis helai, jubah kain, dan kulit dengan hamburan bawah permukaan" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Marschner dkk., <a href="https://www.cs.cornell.edu/~srm/publications/SG03-hair.pdf">Hamburan Cahaya dari Serat Rambut Manusia</a> (SIGGRAPH 2003, model rambut mendasar).</li>
<li>Chiang dkk., <a href="https://benedikt-bitterli.me/pchfm/pchfm.pdf">Model Rambut dan Bulu yang Praktis serta Dapat Dikendalikan untuk Path Tracing Produksi</a> (Disney 2016, banyak digunakan dalam aproksimasi waktu nyata).</li>
<li>Müller dkk., <a href="https://matthias-research.github.io/pages/publications/posBasedDyn.pdf">Dinamika Berbasis Posisi</a> (rujukan standar untuk simulasi kain).</li>
<li>Jimenez dkk., <a href="https://www.iryoku.com/separable-sss/">Hamburan Bawah Permukaan yang Dapat Dipisahkan</a> dan <a href="https://www.iryoku.com/translucency/">Translusensi Kulit Realistis secara Waktu Nyata</a>.</li>
</ul>
<h2>13. Decal, tekstur virtual, dan pelapisan material</h2>
<p>Variasi permukaan berasal dari decal berlapis (lubang peluru, tanah, darah, kerak) yang diproyeksikan ke depth buffer, ditambah tekstur virtual yang melakukan streaming detail beresolusi tinggi tepat saat dibutuhkan. Pelapisan material memadukan beberapa set PBR per piksel menggunakan mask dan proyeksi triplanar, sehingga satu model batu dapat terlihat seperti lima batu berbeda.</p>
<img src="/img/blog/aaa_decals_virtual_textures.webp" alt="Dinding bungker beton yang lapuk dengan decal lubang peluru, grafiti, dan sisipan atlas halaman tekstur virtual" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Pranckevičius, <a href="https://aras-p.info/blog/2009/02/27/deferred-decals/">Decal Deferred</a> dan artikel lanjutannya (seri blog klasik Aras).</li>
<li>Mittring, <a href="http://advances.realtimerendering.com/s2012/Epic/UnrealEngine4_Mittring_SIGGRAPH2012_Final_Cleaned.pdf">Teknologi di Balik &quot;Demo Elemental Unreal Engine 4&quot;</a> (SIGGRAPH 2012, mencakup detail tekstur virtual).</li>
<li>van Waveren, <a href="https://www.realtimerendering.com/blog/id-tech-5-challenges-from-texture-virtualization-to-massive-parallelization/">Tantangan id Tech 5: Dari Virtualisasi Tekstur hingga Paralelisasi Masif</a> (SIGGRAPH 2009, presentasi MegaTexture).</li>
<li>Williams, <a href="https://www.gdcvault.com/play/1022144/Crafting-the-World-of-The">Pelapisan Material dalam The Order: 1886</a> (GDC 2014, material PBR berlapis).</li>
</ul>
<h2>14. Transparansi independen urutan</h2>
<p>Rambut, vegetasi, partikel, dan kaca tidak dapat diurutkan dengan rapi. Engine AAA menggunakan teknik seperti OIT blended berbobot, depth peeling, atau linked list per piksel untuk merendernya dengan benar tanpa tahap pengurutan oleh CPU. Secara diam-diam, ini menjadi salah satu bagian frame yang paling mahal dalam adegan yang dipenuhi vegetasi.</p>
<img src="/img/blog/aaa_oit_transparency.webp" alt="Pemandangan hutan dengan vegetasi translusen yang saling bertumpuk, asap, tetesan kaca, dan rambut translusen" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>McGuire dan Bavoil, <a href="http://jcgt.org/published/0002/02/09/">Transparansi Independen Urutan dengan Blending Berbobot</a> (JCGT 2013, makalah WBOIT).</li>
<li>Bavoil dan Myers, <a href="https://developer.download.nvidia.com/SDK/10/opengl/src/dual_depth_peeling/doc/DualDepthPeeling.pdf">Transparansi Independen Urutan dengan Dual Depth Peeling</a> (makalah teknis NVIDIA).</li>
<li>Yang dkk., <a href="https://www.cse.chalmers.se/edu/year/2017/course/TDA362/Per-Pixel%20Linked%20List.pdf">Konstruksi Linked List Konkuren secara Waktu Nyata di GPU</a> (rujukan linked list per piksel).</li>
<li>Wyman, <a href="https://research.nvidia.com/publication/2016-06_exploring-and-expanding-continuum-oit-algorithms">Menjelajahi dan Memperluas Kontinuum Algoritma OIT</a> (HPG 2016, survei perbandingan).</li>
</ul>
<h2>15. Neural radiance caching dan denoiser ML</h2>
<p>Lapisan terbaru. Neural radiance cache dari NVIDIA mempelajari pencahayaan tidak langsung per adegan dan menguerinya alih-alih menelusuri lebih banyak ray. Denoiser ML (OptiX, Intel Open Image Denoise, atau solusi internal khusus) membersihkan sinyal ray tracing yang jarang dalam hitungan milidetik. Kategori ini diperkirakan akan berkembang pesat selama dua tahun ke depan.</p>
<img src="/img/blog/aaa_neural_radiance_denoise.webp" alt="Katedral hasil ray tracing 1-spp yang berderau di sebelah kiri dan hasil bersih setelah denoising ML di sebelah kanan" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembahasan mendalam:</p>
<ul>
<li>Müller dkk., <a href="https://research.nvidia.com/publication/2021-06_real-time-neural-radiance-caching-path-tracing">Neural Radiance Caching Waktu Nyata untuk Path Tracing</a> (SIGGRAPH 2021, makalah NRC).</li>
<li>Schied dkk., <a href="https://research.nvidia.com/publication/2017-07_spatiotemporal-variance-guided-filtering-real-time-reconstruction-path-traced">Pemfilteran Berpanduan Varians Spasiotemporal: Rekonstruksi Waktu Nyata untuk Iluminasi Global dengan Path Tracing</a> (HPG 2017, SVGF).</li>
<li>Chaitanya dkk., <a href="https://research.nvidia.com/publication/interactive-reconstruction-monte-carlo-image-sequences-using-recurrent-denoising">Rekonstruksi Interaktif Rangkaian Gambar Monte Carlo Menggunakan Autoencoder Denoising Rekuren</a> (SIGGRAPH 2017, denoiser ML rekuren pertama).</li>
<li>Intel, <a href="https://www.openimagedenoise.org/documentation.html">Dokumentasi Open Image Denoise</a> (denoiser produksi sumber terbuka).</li>
</ul>
<h2>Implikasinya bagi browser</h2>
<p>Kami telah menghadirkan beberapa teknik ini di WebGPU untuk <a href="/id/blog/2026-02-25-open-world-browser-series-guide">engine dunia terbuka berbasis browser</a> kami. Cascaded shadow map, instancing berbasis GPU, PBR triplanar, kabut berbasis ruang layar, dan medan tervirtualisasi berbasis clipmap semuanya berjalan pada 120 FPS di sebuah tab. Sisanya (ray tracing perangkat keras, mesh shader, dan upscaling ML) akan hadir di web seiring spesifikasi WebGPU mengejar ketertinggalan. Untuk pembahasan lebih mendalam, lihat panduan kami mengenai <a href="/id/guides/browser-3d-open-world-tech">teknologi dunia terbuka di browser</a> dan <a href="/id/guides/landscape-generation-browser">pembuatan lanskap</a>.</p>
<h2>Bacaan lebih lanjut tentang seluruh rangkaian teknologi</h2>
<p>Jika Anda hanya ingin membaca satu buku, <a href="https://www.realtimerendering.com/">Real-Time Rendering, edisi ke-4</a> adalah rujukan standar yang mencakup sebagian besar topik di atas. Untuk mengikuti riset terbaru, arsip kursus SIGGRAPH &quot;Advances in Real-Time Rendering in Games&quot; (<a href="https://advances.realtimerendering.com/">advances.realtimerendering.com</a>) menyediakan PDF gratis berisi pembahasan mendalam tentang engine AAA sejak 2006. Untuk analisis produksi mengenai cara game tertentu merender setiap frame, <a href="http://www.adriancourreges.com/blog/">artikel profiling GPU Adrian Courrèges</a> merupakan bacaan wajib.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 18: Kuas sebar yang terasa ditempatkan oleh AI]]></title>
            <link>https://app.cinevva.com/id/blog/2026-05-02-open-world-browser-part-18-ai-scattering</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-05-02-open-world-browser-part-18-ai-scattering</guid>
            <pubDate>Sat, 02 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 37 membuat kuas sebar heuristik yang menjauhkan pohon dari tebing dan menempatkan kerikil di garis air tanpa LLM, lalu mengoptimalkannya melalui instancing, LOD berbasis jarak, dan serangkaian bug hingga menghasilkan sapuan kuas 4 ms.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 18: Kuas sebar yang terasa ditempatkan oleh AI</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru di sini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan itu menjelaskan apa itu spike dan menautkan semua bagian.</p>
<p><a href="/id/blog/2026-05-01-open-world-browser-part-17-animations-and-search">Bagian 17</a> memberi pemain satu set animasi berkualitas tempur dan cara untuk memasukkan model CC0 apa pun ke dalam dunia. Bagian ini kembali ke sisi kreator. Palet dari Spike 34 menempatkan satu prop per klik, yang cocok untuk menata objek utama tetapi tidak berguna untuk membuat hutan. Spike 37 adalah kuasnya: seret melintasi medan dan pohon akan mengisi area tempat semestinya pohon tumbuh.</p>
<h2>&quot;Ditempatkan oleh AI&quot; tanpa AI</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/37-ai-scattering/" title="Spike 37 Penyebaran Prop Berbantuan AI" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/37-ai-scattering/" target="_blank">Buka Spike 37 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=37-ai-scattering">Lihat sumber</a></p>
<p>Pertanyaan yang dijawab spike ini adalah apakah kuas yang sepenuhnya heuristik terasa cukup cerdas sehingga kita tidak perlu memakai LLM. Tolok ukur &quot;ditempatkan oleh AI&quot; bersifat konkret: pohon tidak tumbuh di tebing, batu miring mengikuti lereng, dan kerikil pantai berhenti di garis air, semuanya dalam sapuan pertama. Kami mencapainya dengan predikat kemiringan dan ketinggian, pengundian berbobot, serta jarak per keluarga, tanpa satu pun panggilan model.</p>
<p>Kuas ini bekerja pada heightmap CPU berukuran 257×257 dengan fitur yang disetel secara manual agar setiap preset memiliki tempat untuk diterapkan: pegunungan utara untuk pilihan lereng campuran, jalur tebing timur untuk scree, dataran pesisir selatan untuk pantai dan padang rumput, serta cekungan danau di barat daya. Medan membuat bake warna verteks dari pengklasifikasi bioma <code>(altitude, slope)</code>, sehingga sebelum mengecat satu pohon pun, Anda dapat melihat di mana sebuah preset akan aktif. Lima preset disediakan sebagai data datar, masing-masing berupa daftar pilihan seperti <code>{ category, weight, slopeMin, slopeMax, altMin, altMax, minSpacing, alignToSlope }</code>. Cliff and Scree menetapkan <code>slopeMin: 0.3</code> agar batu hanya ditempatkan pada lereng yang benar-benar miring dan <code>alignToSlope: true</code> agar vektor atas setiap bongkahan batu mengikuti normal permukaan.</p>
<p>Untuk setiap sapuan, mesin penyebaran mengambil sampel <code>densityPerM2 × area</code> titik kandidat di dalam cakram kuas, membaca ketinggian dan kemiringan tiap kandidat, menyaring pilihan preset berdasarkan predikat yang terpenuhi, mengundi satu pilihan secara berbobot, lalu menjalankan pemeriksaan jarak terhadap spatial hash dalam radius. Seluruh proses ini deterministik: RNG Mulberry32 yang dapat diberi seed mengendalikan setiap pengundian, sehingga <code>(seed, brush events)</code> dapat mereproduksi sesi apa pun secara persis. Pada medan awal, satu sapuan Mixed Forest di padang rumput datar menempatkan 139 dari 158 kandidat dalam 5 ms, sedangkan preset yang sama pada tebing hanya menempatkan 106 dari 226 kandidat dan HUD melaporkan bahwa 81 di antaranya ditolak karena kemiringan. Rincian penolakan itu merupakan inti UX-nya: Anda dapat melihat <em>mengapa</em> tebing hanya menerima beberapa pohon tanpa harus menebak-nebak.</p>
<p>Tujuan mempertahankan preset sebagai data datar adalah agar versi LLM, saat tersedia nanti, cukup menjadi penggantian JSON alih-alih penulisan ulang. <code>paint({ preset })</code> tidak peduli apakah <code>preset.picks</code> berasal dari resep yang disetel manual atau worker yang mengembangkan &quot;hutan gugur dengan bongkahan batu berlumut&quot; menjadi bobot. Mesin juga tidak pernah melakukan hardcode pada ID prop, sehingga penggunaan katalog lain tidak memerlukan perubahan mesin.</p>
<h2>Dari 300 draw call menjadi 49</h2>
<p>Versi pertama merender setiap penempatan sebagai <code>clone(true)</code> dari grup multi-mesh, yang cukup baik untuk beberapa ratus prop tetapi menjadi penghalang pada batas 2.500, ketika jumlah draw call meningkat hingga ribuan. Kami beralih ke <code>InstancedMesh</code> sebelum mencapai titik itu, dengan satu bucket per <code>(propId, partIndex)</code>. Setiap bucket tumbuh dengan menggandakan kapasitas: alokasikan <code>InstancedMesh</code> yang lebih besar, salin matriks aktif, ganti parent scene, lalu dispose atribut lama. Penghapusan menggunakan swap-remove, sehingga menghapus satu instance berbiaya O(1) terlepas dari ukuran bucket. Determinisme, jarak, dan HUD penolakan semuanya tetap tidak berubah karena pertukaran tersebut sepenuhnya berlangsung di bawah record penempatan.</p>
<p>Diagnostik pada paket MegaKit menjawab pertanyaan arsitektur yang nyata. Mesh glTF multi-primitif (batang ditambah dedaunan) dapat masuk ke three.js sebagai satu mesh dengan material array dan <code>geometry.groups</code>, atau sebagai mesh sibling terpisah dengan satu material untuk masing-masing mesh. Loader mengambil jalur kedua untuk paket ini: setiap bagian merupakan mesh bermaterial tunggal dengan groups kosong. Bentuk ini lebih baik untuk penyebaran karena bucket terpisah per primitif memungkinkan bucket batang tumbuh secara independen dari bucket daun jika jumlahnya berbeda. Jumlah draw call sama untuk kedua pendekatan, tetapi pembagian tersebut menghasilkan susunan memori yang lebih baik. Peningkatan yang terukur tetap bertahan: satu sapuan hutan yang sebelumnya menghasilkan ~300 draw call menjadi 49, dan satu sesi penuh dengan banyak sapuan mencapai 3.221 instance pada 75 FPS dalam 51 draw call, batas yang tidak mungkin dicapai jalur clone sebelum anggaran frame runtuh.</p>
<h2>LOD berbasis jarak, dan empat bug yang bersembunyi di dalamnya</h2>
<p>Instancing memangkas draw call, tetapi setiap instance masih menggambar seluruh jumlah segitiganya, bahkan pohon berjarak 90 m yang detail daunnya hanya menyumbang dua piksel. Karena itu, kami membuat bake tiga tingkat LOD per bagian prop dengan meshoptimizer (penuh, 50%, 15%), memperluas key bucket menjadi <code>(propId, partIndex, lod)</code>, dan menambahkan <code>move()</code> yang memindahkan penempatan antarbucket sibling tanpa alokasi. Band jaraknya adalah 0 hingga 30 m, 30 hingga 90 m, dan selebihnya, dengan histeresis ±4 m di sekitar setiap batas agar kamera yang berada dekat tepi band tidak terus memindahkan penempatan bolak-balik dan mengunggah ulang matriksnya setiap frame. Evaluasi ulang dibatasi hingga 4 Hz dan hanya dijalankan jika kamera benar-benar bergerak, sehingga kamera diam hanya memerlukan satu perbandingan jarak kuadrat per frame.</p>
<p>Jalur LOD itulah yang menyimpan berbagai bug menarik. Bug pertama muncul sebagai penempatan yang menghilang atau terduplikasi saat kamera mengorbit, dan semakin parah ketika scene semakin penuh. Penyebabnya adalah matriks scratch bersama: <code>move()</code> membaca transformasi penempatan ke <code>_tmpMat</code> pada scope modul, tetapi swap-remove milik bucket sumber menggunakan <code>_tmpMat</code> yang sama untuk pengacakan internalnya, sehingga menimpa matriks yang dibawa sebelum bucket tujuan menuliskannya. Bug ini hanya tidak terjadi ketika slot yang dipindahkan sudah menjadi slot terakhir di bucket-nya, dengan peluang kira-kira <code>1/count</code>, yang persis menjelaskan &quot;kedipan langka yang semakin parah saat scene membesar&quot; yang terlihat dalam playtest. Perbaikannya adalah <code>_carryMat</code> khusus yang hanya digunakan oleh <code>move()</code>. Dalam stress test dengan total kumulatif 1.274 perpindahan, cluster tetap identik hingga tingkat piksel.</p>
<p>Bug kedua lebih halus: setiap transisi LOD terasa mulus <em>kecuali</em> transisi pertama. Shading pohon yang beralih ke LOD1 tampak bergeser meskipun siluetnya nyaris tidak berubah, sementara pengurangan jumlah segitiga yang lebih besar pada tahap LOD berikutnya terlihat baik-baik saja. Simplifier dengan <code>LockBorder</code> tidak pernah memindahkan atau membuat verteks, sehingga verteks yang bertahan mempertahankan normalnya secara persis, tetapi kami tetap memanggil <code>computeVertexNormals()</code> setelah setiap penyederhanaan. LOD0 mengembalikan normal asli buatan artis tanpa perubahan; LOD1 dan seterusnya mendapatkan penghitungan ulang rata-rata face generik dari three.js. Batas 0-ke-1 menjadi satu-satunya tempat dalam rangkaian LOD yang mengganti sistem normal, sehingga popping muncul di sana. Menghapus satu baris defensif itu memperbaiki shading dan, sebagai bonus, memangkas waktu bake per prop hingga kira-kira separuh karena kami berhenti menghitung ulang normal pada empat LOD per bagian.</p>
<p>Audit terhadap hasil simplifier mengungkap peningkatan ketiga. Setiap LOD merupakan <code>original.clone()</code> dengan index baru, dan <code>BufferGeometry.clone()</code> menyalin setiap atribut secara mendalam, sehingga lima LOD menyimpan lima salinan independen dari buffer position, normal, UV, dan color yang nilainya identik secara bit. Kami melakukan refactor agar semuanya berbagi referensi atribut dan hanya memiliki buffer index privat per LOD, sehingga jumlah identitas atribut yang berbeda pada bagian pohon tipikal turun dari 20 menjadi 9 dan setiap buffer verteks hanya diunggah ke GPU satu kali. Penyimpanan yang menggunakan alias ini membawa dua kontrak: jangan memutasi data atribut melalui LOD mana pun, dan jangan memanggil <code>dispose()</code> pada satu geometri LOD saja, karena keduanya akan memengaruhi setiap sibling yang berbagi buffer tersebut.</p>
<p>Bug keempat tidak berkaitan dengan pengecatan. Sekadar menggerakkan kursor di atas medan menurunkan frame rate, bahkan tanpa menahan tombol. Handler <code>pointermove</code> melakukan raycast terhadap mesh medan, sebuah bidang dengan 131.072 segitiga tanpa struktur spasial, sehingga three.js menelusuri seluruh buffer index pada setiap event, dengan frekuensi hingga 1.000 event per detik. Kami sama sekali tidak memerlukan mesh untuk pencarian itu karena medan merupakan heightmap parametrik. Ray-march adaptif terhadap <code>sampleHeight</code> (langkah besar jauh di atas permukaan, batas bawah 0,4 m ketika mendekatinya, lalu 12 bisection saat tanda berbalik) membutuhkan sekitar 8 hingga 30 sampel per ray, bukan 131.072 pengujian segitiga, sekitar tiga tingkat besaran lebih murah, dan hover kembali mempertahankan batas frame.</p>
<h2>Biayanya hanya berpindah; pastikan tidak berpindah ke klik</h2>
<p>Setelah mengganti spike ke <code>WebGPURenderer</code> pada three r184 (target produksi), profil DevTools menunjukkan proses paint pertama memblokir selama 265 ms, dengan 79% waktunya dihabiskan di dalam WASM meshoptimizer. Proses bake tersebut memang pekerjaan nyata, sekitar 180 panggilan simplify untuk preset yang masih cold, tetapi proses itu berjalan di dalam handler klik karena <code>preloadProps</code> hanya mengambil dan mengurai scene, tanpa pernah memicu bake LOD. Perbaikannya adalah membuat pemilihan preset menjalankan bake penuh di latar belakang: <code>preloadProps</code> kini memanggil jalur resolusi bagian, menyimpan promise yang sedang berjalan dalam cache agar klik cepat bergabung dengannya alih-alih memulai proses duplikat, dan melakukan memoization terhadap prapemrosesan per geometri yang sebelumnya diulang simplifier empat kali per bagian. Paint pertama turun dari 209 ms menjadi 4 ms di HUD. Waktu WASM tidak lenyap; waktu itu hanya dikeluarkan dari jalur kritis pengguna dan dijalankan ketika mereka sedang melihat medan sambil memutuskan tempat untuk mengecat.</p>
<p>Itulah pelajaran yang terus berulang dari spike ini. Nyaris tidak ada perbaikan tersebut yang mengubah apa yang <em>dilakukan</em> kuas. Semuanya mengubah <em>kapan</em> biaya tersebut muncul: bukan saat klik, bukan saat hover, dan bukan di batas tempat kamera sedang berada. Alat penyebaran yang terasa instan bukan berarti melakukan lebih sedikit pekerjaan, melainkan mengerjakan pekerjaan itu ketika pengguna tidak sedang menunggunya.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Penyebaran kesesuaian heuristik.</strong> Kuas mengambil sampel titik kandidat dalam sebuah cakram, membaca <code>(height, slope)</code> per titik dari heightmap CPU, menyaring pilihan preset berdasarkan predikat kemiringan dan ketinggian, mengundi salah satunya secara berbobot, lalu menolaknya jika melanggar jarak minimum per keluarga yang dilacak dalam spatial hash. Pilihan yang diselaraskan dengan kemiringan memutar vektor atasnya agar mengikuti normal permukaan. Ini menghasilkan penempatan yang tampak disengaja (pohon tidak berada di tebing, batu miring mengikuti lereng, kerikil berhenti di garis air) tanpa bobot hasil pembelajaran, sekaligus mempertahankan preset sebagai data datar agar daftar pilihan buatan LLM dapat langsung dipertukarkan.</p>
<p><strong>Penempatan deterministik di tengah pemuatan asinkron.</strong> RNG Mulberry32 yang dapat diberi seed mengendalikan setiap pengundian, sehingga <code>(seed, brush events)</code> mereproduksi sesi secara persis. Pengundian RNG berlangsung sebelum <code>await</code> apa pun, dan reservasi jarak dimasukkan ke index spasial sebelum clone glTF selesai, sehingga kandidat serentak saling mematuhi jarak dan pemuatan aset asinkron tidak dapat mengganggu urutannya.</p>
<p><strong>InstancedMesh berbucket dengan pengeditan O(1).</strong> Satu <code>InstancedMesh</code> per <code>(propId, partIndex, lod)</code>, dengan kapasitas yang digandakan sesuai kebutuhan melalui penyalinan matriks aktif ke buffer yang lebih besar. Penghapusan dan evict FIFO menggunakan swap-remove dengan array back-reference yang memperbarui index instance yang dipindahkan, sehingga biaya penghapusan tetap O(1) terlepas dari ukuran bucket. Diagnostik mengonfirmasi bahwa bagian glTF masuk sebagai mesh bermaterial tunggal, menjadikan satu bucket per primitif sebagai jalur aktif dan memberi setiap primitif bucket yang dapat tumbuh secara independen.</p>
<p><strong>LOD berbasis jarak dengan histeresis dan buffer atribut bersama.</strong> Tiga tingkat hasil penyederhanaan meshopt per bagian, dipilih berdasarkan band jarak dengan histeresis ±4 m agar kamera di dekat batas tidak terus memindahkan instance, dievaluasi ulang pada frekuensi terbatas dan hanya ketika kamera benar-benar bergerak. Karena penyederhanaan <code>LockBorder</code> tidak pernah memindahkan verteks, semua LOD berbagi satu set buffer position/normal/UV/color dan hanya berbeda pada buffer index privatnya, sehingga jumlah buffer verteks GPU yang berbeda berkurang kira-kira separuh. Melewatkan <code>computeVertexNormals</code> defensif menjaga normal buatan artis tetap identik di semua LOD dan menghapus satu-satunya diskontinuitas shading dalam rangkaian tersebut. Lihat <a href="/id/guides/landscape-generation-browser#gpu-driven-lod-with-webgpu">LOD dan meshoptimizer</a>.</p>
<p><strong>Raycast heightmap analitik untuk pencarian berfrekuensi tinggi.</strong> Pencarian kursor dengan frekuensi <code>pointermove</code> terhadap mesh bidang 131 ribu segitiga menelusuri seluruh buffer index pada setiap event. Menggantinya dengan ray-march adaptif terhadap fungsi ketinggian analitik (langkah besar ketika jauh dari permukaan, batas bawah kecil di dekatnya, bisection ketika tanda $(\text{ray}_y - \text{terrain}_y)$ berbalik) hanya membutuhkan puluhan sampel, bukan puluhan ribu pengujian segitiga, sekitar tiga tingkat besaran lebih murah, dan vektor output yang dialokasikan sebelumnya menjaga hot path tetap bebas alokasi.</p>
<p><strong>Keluarkan pekerjaan dari jalur kritis interaksi.</strong> Pekerjaan satu kali yang mahal (bake LOD meshopt, kompilasi pipeline WGSL) sebaiknya dijalankan selama jeda idle, bukan di dalam handler klik. Memuat lebih awal bake penuh preset aktif saat preset dipilih, menyimpan promise yang sedang berjalan dalam cache agar klik cepat bergabung alih-alih memulai proses baru, dan melakukan memoization terhadap prapemrosesan per geometri menurunkan latensi paint pertama dari 209 ms menjadi 4 ms tanpa mengurangi total pekerjaan yang dilakukan.</p>
<hr>
<p>Bagian 18 dari 29.
Sebelumnya: <a href="/id/blog/2026-05-01-open-world-browser-part-17-animations-and-search">Bagian 17 - Animasi yang tidak memerlukan retargeting, dan pencarian aset langsung</a>
Berikutnya: <a href="/id/blog/2026-05-04-open-world-browser-part-19-imposters">Bagian 19 - Imposter yang harus bertahan di dalam hutan</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 17: Animasi yang tidak memerlukan retargeting, dan pencarian aset langsung]]></title>
            <link>https://app.cinevva.com/id/blog/2026-05-01-open-world-browser-part-17-animations-and-search</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-05-01-open-world-browser-part-17-animations-and-search</guid>
            <pubDate>Fri, 01 May 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 35 melakukan retargeting 262 klip pertarungan dan lokomosi ke rig pemain, serta membangun pengujian paritas offline untuk memastikan hasilnya tetap akurat. Spike 36 menghubungkan pencarian model Polyhaven secara langsung tanpa tahap build.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 17: Animasi yang tidak memerlukan retargeting, dan pencarian aset langsung</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru di sini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan ini menjelaskan apa itu spike dan menyediakan tautan ke semua bagian.</p>
<p><a href="/id/blog/2026-04-28-open-world-browser-part-16-structure-and-authoring">Bagian 16</a> memberi kita dunia tempat objek dapat ditempatkan. Bagian ini memberi pemain sesuatu yang lebih menarik untuk dilakukan di dalamnya: kumpulan animasi kelas pertarungan dan cara memasukkan salah satu dari seribu model CC0 ke dunia hanya dengan mengetikkan pencarian.</p>
<h2>262 klip, satu skeleton, tiga perbaikan retargeting</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/35-combat-animations/" title="Spike 35 Animasi Pertarungan" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/35-combat-animations/" target="_blank">Buka Spike 35 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=35-combat-animations">Lihat kode sumber</a></p>
<p>Rig pemain adalah skeleton <code>3MIKE</code> bergaya CC4 dengan 213 tulang, termasuk rig wajah yang terdiri dari lebih dari 80 tulang dan sendi jari lengkap. Sumber animasinya tidak cocok dengan rig tersebut. Versi pertama melakukan retargeting pada klip pertarungan Mixamo yang dipilih secara manual, tetapi kumpulan sumbernya terbatas dan lokomosi terbagi secara canggung antara Mixamo dan beberapa animasi diam BVH dari Kimodo. Pencapaian sebenarnya terjadi ketika kami mengalihkan pustaka sumber ke dua paket Universal Animation Library dari Quaternius, dengan total 262 klip pada satu manekin bergaya UE5 yang konsisten dan memiliki 65 tulang: kombo pedang, panahan, memanjat, berlari di dinding, mengelak, reaksi terkena serangan, emote, dan kumpulan lokomosi yang jauh lebih rapi.</p>
<p>Artinya, kami memetakan sumber dengan 65 tulang ke target dengan 213 tulang, tanpa kesamaan nama tulang, orientasi T-pose, maupun proporsi anggota tubuh. Setiap klip dipetakan ulang dalam tiga langkah: peta nama tulang, penyelarasan bind pose agar kedua rig memiliki orientasi referensi yang sama, dan penskalaan track posisi agar rig sumber yang lebih pendek tidak membuat karakter terbenam setinggi lutut di lantai. Untuk membuatnya bekerja dengan benar, kami harus memburu serangkaian bug yang masing-masing mengajarkan sesuatu yang spesifik.</p>
<p>Karakter awalnya terlihat terlalu terpuntir, dengan setiap bahu dan siku berputar sekitar 30° terlalu jauh. Penyebabnya adalah ketidakcocokan pose: sumber UAL menggunakan T-pose sejati, bind CC4 berupa A-pose, dan retargeter mengasumsikan kedua rig berada dalam pose referensi yang sama. Akibatnya, selisih A-to-T ditambahkan ke setiap delta per frame. Perbaikannya memaksa rantai lengan CC4 ke T-pose sejati untuk merekam bind, lalu melakukan retargeting agar deltanya tetap kecil.</p>
<p>Kemudian tubuh berhenti berpindah posisi. Animasi knockback membuat tubuh bagian atas terpental, tetapi kaki tetap tertanam di tempat. UAL menempatkan perpindahan pada tulang <code>root</code>, bukan pelvis, sehingga membaca posisi pelvis menghasilkan gerakan yang nyaris nol. Perbaikannya menjumlahkan <code>root.position</code> dan <code>pelvis.position</code>, menskalakan komponen horizontalnya, lalu menulis satu track posisi pinggul. Saat mengerjakannya, kami menemukan offset vertikal meleset sekitar 12% karena kami menggunakan rasio proporsi anggota tubuh global untuk sumbu Y, padahal tinggi pelvis memerlukan rasio pinggul-ke-lantai. Dua rasio, dua sumbu: $\text{verticalRatio} = |{\text{targetHipY}}/{\text{sourceHipY}}|$ untuk Y, dan rasio proporsi untuk arah horizontal. Gerakan berlebih pun hilang. Sementara itu, rentetan peringatan NaN untuk <code>RL_BoneRoot.position</code> ternyata berasal dari pemetaan <code>root</code> UAL (pada $Y=0$) ke tulang target yang track posisinya dinormalisasi dengan membaginya terhadap nilai Y bind. Pembagian dengan nol menghasilkan NaN, lalu track dibuang tanpa peringatan yang jelas. Solusinya adalah menghapus pemetaan root sepenuhnya karena translasinya sudah berada di track pinggul.</p>
<p>Perbaikan terkecil justru paling memuaskan untuk dilihat. Karakter menggenggam pedang dengan jari-jari lemas dalam bind pose karena peta tulang tidak memiliki entri untuk jari, sedangkan retargeter hanya menulis track untuk tulang yang dipetakan. Menambahkan 30 tulang jari—lima jari, tiga segmen, dua tangan, dengan menghapus helper ujung keempat milik UAL yang tidak mendeformasi mesh—membuat tangan menutup pada gagang dan terbuka saat melepaskannya.</p>
<h2>Membuktikan 262 klip tanpa menonton 262 klip</h2>
<p>Pustaka berisi 262 klip tidak mungkin diverifikasi hanya dengan pengamatan visual, jadi kami membangun pengujian paritas lintasan offline: skrip Node headless yang memuat setiap paket, mengambil sampel skeleton sumber pada 60Hz, menjalankan pipeline retargeting, lalu membandingkan posisi dan rotasi dunia setiap tulang dengan sumber setelah penskalaan. Penyimpangan pelvis pada sumbu Y memiliki nilai maksimum 0,003 m. Tangan menunjukkan offset konstan sebesar 2,5° yang awalnya tampak seperti “jari tidak mengikuti animasi”, tetapi offset konstan sebenarnya merupakan delta bind antara tangan UAL yang datar dan bind CC4 yang sedikit melengkung, dan nilainya tidak berubah sepanjang klip. Kesalahan animasi yang sesungguhnya muncul sebagai penyimpangan yang berubah dari frame ke frame. Setelah hal itu dipahami, pengujian tersebut menjadi pemeriksaan regresi sekali jalan: jika penyimpangan suatu klip tidak lagi mempertahankan baseline konstan tersebut, berarti perubahan terbaru merusak retargeting.</p>
<p>Manekin referensi yang ditampilkan berdampingan membuat aspek visual proses debugging menjadi sangat menentukan. Menekan tombol garis miring terbalik menampilkan rig sumber pemilik klip yang sedang aktif di sebelah pemain, sehingga pertanyaan “apakah bahunya terpuntir?” berubah menjadi “apakah puntiran itu sudah ada pada sumber, atau ditambahkan oleh retargeting?” Pengujian numerik menangkap regresi, referensi visual menangkap kesalahan bind pose yang tidak terlihat dalam angka, dan keduanya bersama-sama mengakhiri permainan tebak-tebakan.</p>
<p>Setelah pipeline stabil, peralihan baseline WASD/lompat/berenang dari Mixamo ke UAL cukup menggunakan peta alias sederhana: FSM tetap memakai nama status generik seperti <code>idle</code> dan <code>walk</code>, yang diterjemahkan menjadi nama klip UAL saat pemutaran. Animasi berenang memerlukan offset rig per klip karena pose gaya bebas dan mengapung di tempat menempatkan pelvis pada ketinggian anatomi yang berbeda. Karena itu, kami menenggelamkan rig setengah meter untuk berenang aktif dan lebih dalam untuk mengapung di tempat, lalu melakukan blending di antaranya secara mulus pada 5Hz.</p>
<h2>Ketik satu kata, dapatkan satu model</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/36-polyhaven-models/" title="Spike 36 Model Polyhaven" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/36-polyhaven-models/" target="_blank">Buka Spike 36 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=36-polyhaven-models">Lihat kode sumber</a></p>
<p>Spike 34 menghabiskan satu hari untuk mengurasi paket CC0 secara manual. Solusi jangka panjangnya adalah kotak pencarian. Polyhaven menerbitkan sekitar 1.100 model CC0 melalui API JSON yang permisif dan CDN deterministik, dan spike ini menghubungkan seluruh alurnya—kueri, thumbnail, pemuatan, dan rendering—dari halaman statis tanpa tahap build, dalam sekitar 300 baris JavaScript vanilla ditambah three.js.</p>
<p>Saat dimulai, aplikasi mengambil seluruh katalog satu kali, sekitar 600 KB. Pencarian menggunakan penilaian sepenuhnya di sisi klien—nama memiliki prioritas di atas id, id di atas kategori, dan kategori di atas tag—dengan debounce 120 ms, lalu merender 60 kartu teratas. Thumbnail dimuat secara lazy melalui <code>IntersectionObserver</code> agar mengetik tidak langsung memicu 60 permintaan sekaligus. Bagian yang menarik adalah proses pemuatannya. Endpoint file Polyhaven menyediakan glTF multi-file, bukan GLB, dengan tekstur yang digunakan bersama lintas resolusi dan dipisahkan menjadi file tersendiri. Endpoint tersebut juga mengembalikan peta <code>include</code> dari path relatif ke URL CDN absolut. Alih-alih mengunduh dan memodifikasi JSON sendiri, kami meneruskan peta tersebut melalui <code>LoadingManager.setURLModifier</code>, yang dipanggil untuk setiap dependensi yang dibutuhkan loader—file <code>.bin</code> dan setiap tekstur—lalu menyelesaikan URL-nya melalui CDN. Satu klik, terasa seperti satu file. API dan CDN sama-sama menetapkan CORS permisif, yang diverifikasi menggunakan <code>curl</code> sebelum menulis kode klien apa pun, sehingga proxy tidak diperlukan. Material PBR dirender dengan benar menggunakan <code>RoomEnvironment</code> dan pengaturan default tone mapping ACES tanpa penyesuaian per aset, sementara tekstur 1k menjaga ukuran model umum di kisaran 2 hingga 5 MB, alih-alih 20 hingga 40 MB pada resolusi 4k.</p>
<p>Tahap WASM meshoptimizer melengkapinya dengan reducer non-destruktif: setiap mesh menyimpan klona geometri aslinya, dan perubahan rasio membangun ulang index buffer dari klona tersebut, bukan menyederhanakan hasil sebelumnya secara kumulatif. Geometri multi-material disederhanakan per grup dan <code>geometry.groups</code> dibangun ulang agar slot material tidak menyatu. Sebuah kursi berlengan berkurang dari 5.626 segitiga pada kualitas penuh menjadi 2.812 pada kualitas setengah.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Retargeting skeleton dengan penyelarasan bind pose.</strong> Memetakan animasi dari satu skeleton ke skeleton lain yang memiliki nama tulang, proporsi, dan pose referensi berbeda memerlukan tiga koreksi: peta nama tulang, penyelarasan bind pose agar kedua rig memiliki orientasi referensi yang sama—dengan memaksa rantai lengan A-pose target ke T-pose sumber—dan penskalaan track posisi. Ketidakcocokan pose menambahkan rotasi A-to-T ke setiap delta per frame sehingga menggandakan rotasi sendi. Tulang helper yang tidak dipetakan harus dibuang karena tulang root pada $Y=0$ memicu pembagian dengan nol tanpa peringatan dalam normalisasi track posisi.</p>
<p><strong>Dua rasio skala untuk satu rig.</strong> Perpindahan horizontal menggunakan rasio proporsi anggota tubuh global—ukuran skeleton secara keseluruhan—tetapi offset vertikal pelvis menggunakan rasio pinggul-ke-lantai $|{\text{targetHipY}}/{\text{sourceHipY}}|$ karena proporsi kaki terhadap torso berbeda di antara rig. Menggunakan satu rasio untuk kedua sumbu membuat animasi memanjat bergerak terlalu jauh dan animasi pemulihan tenggelam di bawah lantai. Perpindahan UAL juga berada pada tulang <code>root</code>, bukan pelvis, sehingga keduanya harus dijumlahkan ke dalam satu track posisi pinggul untuk mempertahankan gerakan pada klip knockback, memanjat, dan lokomosi.</p>
<p><strong>Pengujian paritas lintasan offline.</strong> Skrip headless mengambil sampel skeleton sumber pada 60Hz, menjalankan pipeline retargeting, lalu membandingkan transformasi dunia setiap tulang dengan sumber. Offset konstan per frame merupakan delta bind yang tidak berbahaya, sedangkan penyimpangan yang berubah dari frame ke frame merupakan kesalahan nyata. Dengan demikian, pengujian ini menjadi pemeriksaan regresi yang terpicu ketika suatu perubahan menghilangkan atau mendistorsi track. Isolasi GLB per paket—memuat salinan baru dan membebaskannya sebelum paket berikutnya—mencegah perebutan cache selama pengujian menyeluruh.</p>
<p><strong>LoadingManager.setURLModifier untuk graf glTF CDN.</strong> Ketika CDN mengirimkan glTF sebagai graf URI relatif yang disertai peta include—path relatif ke URL absolut—<code>setURLModifier</code> menyelesaikan setiap dependensi yang diminta loader melalui CDN tanpa menulis ulang JSON. Hal ini menyederhanakan distribusi multi-file dan multi-resolusi menjadi pemuatan dengan satu klik. Menghapus geometri, material, dan peta tekstur model sebelumnya sebelum memuat model berikutnya mencegah akumulasi ratusan MB memori GPU selama satu sesi penelusuran.</p>
<p><strong>Penyederhanaan mesh non-destruktif.</strong> Menyimpan klona geometri asli setiap mesh dan hanya membangun ulang index buffer untuk setiap rasio penyederhanaan membuat perubahan tetap cepat serta menghindari kerusakan kumulatif akibat penyederhanaan berulang. Menjalankannya pada setiap irisan <code>geometry.groups</code> dan merekonstruksi grup mempertahankan penetapan multi-material. Lihat <a href="/id/guides/landscape-generation-browser#gpu-driven-lod-with-webgpu">LOD dan meshoptimizer</a> untuk mengetahui bagaimana teknik ini digunakan dalam LOD berbasis jarak.</p>
<hr>
<p>Bagian 17 dari 29.
Sebelumnya: <a href="/id/blog/2026-04-28-open-world-browser-part-16-structure-and-authoring">Bagian 16 - Struktur untuk dunia yang terus berkembang</a>
Berikutnya: <a href="/id/blog/2026-05-02-open-world-browser-part-18-ai-scattering">Bagian 18 - Kuas sebar yang terasa ditempatkan oleh AI</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Anatomi mesin gim AI: apa yang sebenarnya ada di balik prompt]]></title>
            <link>https://app.cinevva.com/id/blog/2026-04-30-anatomy-of-an-ai-game-engine</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-04-30-anatomy-of-an-ai-game-engine</guid>
            <pubDate>Thu, 30 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Cinevva terlihat seperti satu kotak teks. Di baliknya terdapat orkestrator, 26 alat bertipe, sebelas penyedia aset, iframe gim aktif yang dapat dimainkan oleh agen, serta etalase yang terhubung ke reel gameplay. Inilah keseluruhan mesinnya, bagian demi bagian.]]></description>
            <content:encoded><![CDATA[<h1>Anatomi mesin gim AI: apa yang sebenarnya ada di balik prompt</h1>
<p><em>Oleh <a href="/id/about">Mariana Muntean</a>, CEO Cinevva</em></p>
<p>Hal yang paling sering dikatakan orang yang baru mengenal Cinevva adalah bahwa Cinevva hanyalah pembungkus AI. Mereka membuka halaman utama, melihat satu kotak input bertuliskan &quot;Deskripsikan gim Anda&quot;, lalu merasa sudah memahami produknya. Yang mereka pahami baru pintu depannya. Produknya adalah segala sesuatu yang tidak Anda lihat saat mengetik kalimat tersebut, ditambah, mulai minggu ini, sebuah dunia terbuka yang dimasuki pemain Anda untuk menemukan gim Anda sejak awal.</p>
<p>Di balik input tersebut terdapat mesin gim lengkap, orkestrator dengan 26 alat bertipe, sekumpulan model generatif, pencarian aset teragregasi dari sebelas penyedia, iframe gim aktif yang dapat dibaca dan ditulisi oleh agen, serta etalase tempat agen yang sama merilis gim Anda yang sudah selesai sebagai reel gameplay yang dapat digeser. Tidak ada satu pun yang eksotis. Semuanya adalah infrastruktur. Pekerjaan yang menarik adalah memutuskan apa yang harus dihubungkan ke mana.</p>
<p>Tulisan ini membahas mesin tersebut dari atas hingga bawah. Inilah penjelasan yang kami berikan kepada investor teknis dan pengembang yang mempertimbangkan untuk berkontribusi. Mereka menginginkan jawaban yang sama.</p>
<h2>1. Prompt adalah permukaan, bukan sistemnya</h2>
<img src="/img/blog/engine-anatomy/cinevva-engine-prompt.png" alt="Input prompt Cinevva di halaman utama. Satu kolom teks bertuliskan 'Buat gim tembak-tembakan luar angkasa bernuansa neon dengan asteroid, power-up, dan soundtrack synth.' Di bawahnya terdapat tiga chip saran dan logo Cinevva." style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Keputusan desain pertama adalah menyembunyikan semuanya sampai pengguna benar-benar terlibat. Halaman utama hanya memiliki satu tugas, yaitu menerima sebuah kalimat dan mengubahnya menjadi proyek. Kami membagi pengalaman menjadi sisi publik (prompt, etalase karya, feed etalase gim) dan sisi kreator (IDE, alat aset, alur publikasi), agar orang yang hanya ingin bermain tidak perlu melihat kokpitnya.</p>
<p>Itulah sebabnya placeholder berganti-ganti menampilkan teks seperti &quot;Buat gim ular dengan grafis neon&quot; dan &quot;Gim tembak-tembakan zombi dari atas&quot;. Itu bukan tutorial. Itu adalah izin untuk berkreasi. Pengguna jadi tahu bahwa &quot;ide arkade yang aneh&quot; merupakan input yang sah.</p>
<p>Saat Anda mengirimkannya, tiga hal terjadi. Sistem membuat proyek gim baru dengan ID tetap. Sistem menyiapkan struktur berkas kosong (<code>index.html</code>, <code>game.js</code>, <code>style.css</code>, <code>assets/</code>, <code>GDD.md</code>). Lalu sistem meneruskan kalimat Anda ke orkestrator dengan jendela konteks proyek yang mengarah ke berkas-berkas kosong tersebut. Mulai dari sini, Anda berbicara dengan agen yang dapat bertindak langsung.</p>
<h2>2. Di balik input, sebuah IDE peramban lengkap</h2>
<img src="/img/blog/engine-anatomy/cinevva-engine-ide.png" alt="IDE kreator Cinevva dalam mode gelap. Tiga panel: struktur berkas di sebelah kiri berisi GDD.md, index.html, game.js, style.css, dan folder assets; editor kode dengan penyorotan sintaks di tengah yang menampilkan konfigurasi renderer Three.js; serta pratinjau gim aktif di sebelah kanan yang menampilkan gim tembak-tembakan luar angkasa neon dari atas dengan HUD SCORE dan LIVES." style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Ruang kerja kreator adalah IDE tiga panel yang berjalan sepenuhnya di peramban. Struktur berkas di sebelah kiri, editor kode di tengah, iframe gim aktif di sebelah kanan, dan input obrolan memanjang di sepanjang bagian bawah. Kami sengaja memilih tata letak ini. Orang yang sudah terbiasa menulis kode akan langsung mengenalinya. Orang yang tidak terbiasa dapat mengabaikan panel tengah dan cukup berinteraksi melalui obrolan.</p>
<p>Struktur berkas itu bukan sekadar metafora. Setiap proyek benar-benar merupakan situs statis kecil yang terdiri dari HTML, JS, CSS, gambar yang dihasilkan, model GLB, dan berkas audio, yang disajikan langsung dari R2 melalui Cloudflare Worker. Tidak ada tahap build. Alasannya penting. Ini berarti agen dapat membaca dan menulis berkas yang benar-benar akan Anda rilis, dan artefak yang sama dapat berjalan di iframe, di ponsel yang dibungkus dengan Capacitor, di Steam yang dibungkus dengan Tauri, serta di dalam Discord sebagai Embedded Activity. Satu sistem berkas, enam target distribusi.</p>
<p>Setiap gim yang kami hasilkan wajib mengekspos dua fungsi pada <code>window</code>. <code>getGameState()</code> mengembalikan objek biasa yang mendeskripsikan gim yang sedang berjalan (posisi pemain, skor, nyawa, musuh, timer). <code>setGameState(patch)</code> menerapkan pembaruan parsial kembali ke gim aktif. API kecil itu adalah kontrak yang memungkinkan agen memeriksa dan mengubah gim yang sedang berjalan tanpa memuat ulang. Kita akan kembali membahas alasannya di bagian 6.</p>
<h2>3. Orkestrator, tempat mesin yang sebenarnya berada</h2>
<img src="/img/blog/engine-anatomy/cinevva-engine-orchestrator.png" alt="Diagram orkestrator Cinevva. Node pusat berlabel 'Orchestrator (LLM)' terhubung ke delapan node alat yang tersusun di sekelilingnya: list_game_files, read_files, edit_files, write_files, generate_image (Flux), generate_skybox (Blockade), generate_music (ElevenLabs), dan rig_model (Tripo). Garis putus-putus menghubungkan orkestrator ke node 'Game iframe' berlabel 'screenshots + console.'" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Hal yang terlewat ketika orang menyebut ini &quot;pembungkus AI&quot; adalah bahwa AI tidak sekadar menulis kode, melainkan memimpin sebuah orkestra kecil. Orkestratornya merupakan loop pemanggilan alat yang berjalan menggunakan model terdepan, dengan system prompt sepanjang sekitar seribu baris dan permukaan alat bertipe yang terdiri dari 26 fungsi. Definisi alat itulah mesinnya. Model adalah konduktornya.</p>
<p>Ke-26 alat tersebut terbagi menjadi lima kelompok. Alat sistem berkas (<code>list_game_files</code>, <code>read_files</code>, <code>search_game_file</code>, <code>edit_files</code>, <code>write_files</code>, <code>delete_files</code>, <code>rename_files</code>) memungkinkan agen memperlakukan gim Anda seperti basis kode lainnya. Alat proyek (<code>create_new_game</code>, <code>list_games</code>, <code>open_game</code>, <code>ask_user</code>, <code>game_ready</code>) menangani siklus hidup proyek dan penyerahannya kembali kepada manusia. Alat generatif (<code>generate_image</code>, <code>generate_skybox</code>, <code>generate_music</code>, <code>generate_sfx</code>, <code>rig_model</code>, <code>apply_animation</code>, <code>list_animations</code>, <code>list_skybox_styles</code>) memanggil model khusus yang akan kita bahas berikutnya. Alat pengetahuan (<code>search_fonts</code>, <code>list_library_docs</code>, <code>search_library_docs</code>, <code>list_generations</code>) memberi agen sumber kebenaran terindeks yang andal, alih-alih API hasil halusinasi. Sementara itu, alat runtime (<code>read_console_logs</code>, <code>execute_js</code>) memungkinkan agen melihat dan menyentuh gim aktif.</p>
<p>Interaksi pertama yang umum kurang lebih seperti ini. Pengguna mengetik &quot;Buat gim tembak-tembakan luar angkasa neon&quot;. Model mengeluarkan panggilan <code>write_files</code> dengan <code>GDD.md</code> yang mendeskripsikan desainnya, lalu memanggil <code>write_files</code> lagi untuk <code>index.html</code>, <code>game.js</code>, dan <code>style.css</code>. Model memanggil <code>generate_music</code> dengan <code>prompt=&quot;synthwave space shooter, 120 BPM, driving bassline&quot;</code>, yang memulai pekerjaan melalui ElevenLabs Music dan mengembalikan URL MP3 di dalam R2. Model memanggil <code>generate_skybox</code> menggunakan gaya model 3 dari Blockade Labs untuk hamparan bintang. Model memanggil <code>game_ready(title, message)</code> untuk mengalihkan iframe ke build baru, lalu akhirnya memanggil <code>read_console_logs</code> guna memastikan gim dimulai tanpa kesalahan. Jika melihat stack trace, model kembali ke <code>edit_files</code> dan memperbaikinya sebelum pengguna melaporkan apa pun.</p>
<p>Sifat menarik dari desain ini adalah bahwa system prompt dan skema alat merupakan satu-satunya bagian yang khusus untuk produk. Ganti modelnya, dan semuanya tetap berfungsi. Kami telah bermigrasi di antara tiga model terdepan selama setahun terakhir tanpa mengubah permukaannya, karena permukaan itu milik kami.</p>
<h2>4. Sisi aset: penyebaran ke berbagai model</h2>
<img src="/img/blog/engine-anatomy/cinevva-engine-assets.png" alt="Dasbor pembuatan aset dengan tiga panel. Panel kiri adalah generator musik dengan prompt 'synthwave space shooter, 120 BPM, driving bassline,' penggeser durasi 60 detik, tombol Generate, serta kartu bentuk gelombang yang sedang diputar berjudul 'Asteroid Drift Theme.' Panel tengah adalah generator skybox dengan prompt 'deep space, distant nebula, two moons' dan kisi berisi empat thumbnail lingkungan 360 derajat. Panel kanan menampilkan pratinjau model 3D berputar berupa pesawat luar angkasa ungu low-poly, dengan tombol 'Rig + Walk' serta indikator status bertuliskan 'Rigging... 1m 42s left.'" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Agen tidak menghasilkan gambar, musik, suara, atau objek 3D sendiri. Agen memanggil para spesialis. Sisi aset Cinevva menyebarkan pekerjaan ke berbagai model terbaik di kelasnya, yang direkatkan sehingga output dari satu model menjadi input yang valid bagi model berikutnya.</p>
<p>Untuk gambar dan sprite, <code>generate_image</code> memanggil Flux Pro 1.1 dengan lebar dan tinggi yang selalu merupakan kelipatan 32 serta format output yang beralih ke PNG ketika prompt meminta transparansi. Untuk lagu lengkap, agen memanggil ElevenLabs Music dengan prompt gaya dan durasi dalam detik. Untuk efek satu kali, ElevenLabs SFX menghasilkan klip dari teks seperti &quot;laser gun firing, sci-fi blaster&quot; dalam waktu lima hingga lima belas detik. Untuk lingkungan 360 derajat, <code>generate_skybox</code> memanggil Blockade Labs dengan salah satu dari sekitar sembilan puluh gaya, dengan model 3 Digital Painting sebagai default. Untuk karakter 3D, <code>rig_model</code> mengirimkan GLB ke Tripo untuk diberi skin dan rig sebagai makhluk bipedal, berkaki empat, berkaki enam, berkaki delapan, melata seperti ular, atau akuatik. Kemudian <code>apply_animation</code> memutar salah satu dari lima belas preset (diam, berjalan, berlari, melompat, memanjat, menyelam, menebas, menembak, terluka, jatuh, berbalik, ditambah gerakan berjalan untuk karakter non-bipedal).</p>
<p>Masing-masing merupakan pekerjaan, bukan panggilan sinkron. Prosesnya memerlukan waktu beberapa detik hingga beberapa menit. Orkestrator memulainya, segera kembali dengan <code>jobId</code>, lalu saluran terpisah mengirimkan hasilnya kembali ke percakapan ketika aset sudah siap. Hal ini sepenuhnya mengubah pengalaman pengguna. Agen dapat terus membangun logika gim sementara proses rigging model 3D selesai di latar belakang. Pengguna tidak perlu menunggu satu jalur kritis.</p>
<p>Semua artefak berakhir di tempat yang sama. R2, di balik <code>cdn.cinevva.com</code>, dan dapat diakses sebagai URL biasa. Artinya, panggilan <code>write_files</code> agen berikutnya cukup menyematkan <code>&lt;audio src=&quot;https://cdn.cinevva.com/audio/abc.mp3&quot;&gt;</code>, lalu gim langsung berfungsi. Tanpa SDK, tanpa bundler aset, tanpa manifest.</p>
<h2>5. Pencarian aset dari sebelas penyedia</h2>
<img src="/img/blog/engine-anatomy/cinevva-engine-asset-search.png" alt="Halaman pencarian aset Cinevva dalam mode gelap. Bilah pencarian di bagian atas berisi kueri 'asteroid rock' dan deretan pil filter penyedia menampilkan All, PolyHaven, Sketchfab, Kenney, Quaternius, AmbientCG, OpenGameArt, Freesound, Smithsonian, Synty, serta Jamendo, dengan Sketchfab disorot. Di bawahnya terdapat kisi empat kolom berisi thumbnail model asteroid. Setiap kartu menampilkan lencana penyedia, label lisensi CC0 atau CC-BY, dan tombol 'Use in game'. Keterangan kecil di sudut kanan atas menampilkan gelembung obrolan bertuliskan 'ChatGPT: one of the best free asset tools for game devs.'" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pembuatan aset sangat berguna ketika Anda membutuhkan sesuatu yang spesifik. Pencarian lebih cepat ketika aset tersebut sudah tersedia. <a href="/id/assets">Pustaka Aset</a> merupakan pencarian terfederasi dari sebelas penyedia aset gratis dan berlisensi, yang ditampilkan dalam satu feed terurut.</p>
<p>Registri penyedia berada di worker dan menjalankan setiap kueri secara paralel ke PolyHaven, Sketchfab, Freesound, Kenney, AmbientCG, Quaternius, OpenGameArt, koleksi 3D Smithsonian, TurboSquid, Synty, dan Jamendo. Setiap penyedia menerapkan antarmuka umum (<code>search</code>, <code>getMetadata</code>, <code>isBrowsable</code>, <code>getSupportedTypes</code>), sehingga penambahan penyedia baru hanya memerlukan satu berkas TypeScript. Lapisan agregasi menangani paginasi berbasis kursor di berbagai penyedia yang menggunakan metode paginasi berbeda, menghapus duplikasi lisensi, menormalkan jenis aset ke dalam taksonomi umum (model, tekstur, audio, hdri, sprite), serta menandai setiap aset dengan lisensinya agar agen tidak pernah memilih sesuatu yang tidak boleh didistribusikan ulang.</p>
<p>Ketika ChatGPT merekomendasikan alat ini pada kuartal lalu sebagai salah satu pencari aset gratis terbaik bagi pengembang gim, kami membaca rekomendasi tersebut. Rekomendasi itu benar pada bagian yang penting. Intinya bukan bahwa kami memiliki bilah pencarian untuk satu pustaka. Intinya adalah bahwa pengembang indie yang mencari &quot;tekstur dinding batu&quot; mendapatkan hasil dari PolyHaven dan AmbientCG berdampingan dengan versi bergaya dari Kenney serta opsi fotogrametri dari Smithsonian, melalui satu kueri dan dengan metadata lisensi yang konsisten. Agen dapat menggunakan endpoint yang sama dan memilih aset dengan cara yang sama seperti manusia.</p>
<p>Bagian mesin ini sering kali kurang dihargai. Sebagian besar demo AI gim menghasilkan semuanya dari nol dan akhirnya memiliki tampilan seragam, mengilap, dan sedikit janggal. Gim-gim menarik di Cinevva memadukan aset hasil generasi dengan fotogrametri CC0 asli dari Smithsonian dan pohon low-poly buatan tangan dari Quaternius. Orkestrator dapat melakukan semua itu dalam satu interaksi.</p>
<h2>6. Agen memainkan gim</h2>
<img src="/img/blog/engine-anatomy/cinevva-engine-debug.png" alt="Tampilan debugging langsung. Di sebelah kiri, gim tembak-tembakan luar angkasa neon yang sedang berjalan menampilkan pesawat pemain menghindari asteroid dengan SCORE 4820 dan 2 nyawa tersisa. Di sebelah kanan, dua panel bertumpuk: panel execute_js menampilkan panggilan JSON.stringify(getGameState()) dan objek JSON hasilnya yang berisi posisi pemain, kecepatan, health, score, lives, serta jumlah asteroid; dan panel read_console_logs yang menampilkan baris log terbaru, termasuk spawn asteroid, powerup picked, peringatan pemuatan tekstur, serta pembacaan FPS sebesar 58." style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Inilah bagian yang paling mengejutkan sebagian besar engineer ketika kami mendemonstrasikannya. Agen tidak hanya menulis kode ke dalam berkas. Agen menjalankan gim di iframe terisolasi, membaca konsolnya, mengambil tangkapan layar yang dipisahkan menjadi lapisan UI dan adegan 3D, serta menjalankan JavaScript di dalam runtime aktif untuk memeriksa atau mengubah status.
<code>read_console_logs</code> mengembalikan lima puluh baris terakhir dari <code>console.log</code>, <code>console.warn</code>, <code>console.error</code>, dan pengecualian yang tidak tertangani dari iframe. Setelah setiap pemanggilan <code>game_ready</code>, agen diwajibkan oleh prompt sistem untuk memanggil <code>read_console_logs</code> dan memperbaiki semua galat sebelum menyerahkannya kembali kepada pengguna. Satu aturan itu menghilangkan sebagian besar kegagalan &quot;AI bilang sudah selesai, tetapi layarnya hitam&quot; yang dialami alat lain.</p>
<p><code>execute_js</code> adalah alat yang lebih canggih. Alat ini menjalankan JavaScript arbitrer di dalam lingkup global game. Karena setiap game diwajibkan mengimplementasikan <code>getGameState</code> dan <code>setGameState</code>, agen dapat menjalankan <code>JSON.stringify(getGameState())</code> untuk membaca seluruh state game yang sedang berjalan, lalu <code>setGameState({player: {x: 500, y: 100}})</code> untuk memindahkan pemain secara instan, <code>setGameState({lives: 99})</code> untuk memberikan kekebalan, atau <code>setGameState({level: 3})</code> untuk melompat ke level berikutnya. Agen juga dapat memeriksa lapisan yang lebih rendah, seperti <code>scene.children.map(c =&gt; c.type)</code> untuk menginspeksi scene graph Three.js atau <code>document.querySelectorAll('canvas').length</code> untuk memastikan renderer sudah terpasang.</p>
<p>Anda bisa melihat mengapa hal ini penting. Ketika pengguna berkata, &quot;pemain tersangkut di dinding pada level dua&quot;, agen tidak perlu menebak. Agen membuka level dua, menjalankan <code>getGameState()</code>, memeriksa data collision, menjalankan patch <code>execute_js</code> untuk menguji perbaikan, dan baru kemudian menulis perbaikannya ke disk. Agen melakukan debugging seperti Anda melakukan debugging. Kami memperlakukan iframe sebagai rekan, bukan target.</p>
<h2>7. Dokumentasi pustaka, sumber kebenaran yang membosankan</h2>
<p>Kami mengindeks dokumentasi resmi untuk pustaka yang benar-benar digunakan oleh game (Three.js, Tone.js, Cannon, dan terus bertambah) ke dalam penyimpanan JSON terstruktur yang dapat dicari. Agen menggunakan <code>search_library_docs(&quot;threejs&quot;, &quot;Mesh&quot;)</code> sebelum beralih ke web terbuka. Ini lebih cepat, memiliki versi yang jelas, dan tidak pernah mengarang metode yang namanya sudah diubah dua rilis minor lalu.</p>
<p>Ini memang tidak glamor. Namun, inilah perbedaan antara AI yang menghasilkan kode berfungsi dan AI yang menghasilkan kode yang tampak meyakinkan tetapi mengalami crash pada baris keempat puluh. Sebagian besar kualitas yang terlihat dari game buatan Cinevva berasal dari satu keputusan ini.</p>
<h2>8. Dari dapat dimainkan menjadi dapat ditemukan: reel dan etalase</h2>
<img src="/img/blog/engine-anatomy/cinevva-engine-reels.png" alt="Etalase reel gameplay berdurasi pendek. Di tengah, sebuah kartu berbentuk ponsel memutar video vertikal tentang penembak luar angkasa neon di tengah pertempuran, dengan ikon UI sosial bertumpuk di sisi kanan (hati dengan 14 ribu, gelembung chat dengan 3,2 ribu, panah bagikan dengan 1,8 ribu, dan tombol 'Mainkan Sekarang'). Label reel di bagian bawah bertuliskan 'Asteroid Drift • oleh @indiedev • 3,1 juta tayangan.' Di sebelah kiri, cuplikan chat kecil berjudul 'Dari chat kreator' menampilkan pesan asisten 'Game sudah tayang. Reel otomatis dipublikasikan ke etalase Anda.' Di sebelah kanan, panel Etalase mencantumkan tiga game yang sedang tren: Asteroid Drift, Roadhawk Runner, dan Birb Clicker, masing-masing dengan jumlah tayangan dan label 'Sedang Tren'." style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Game yang tidak dimainkan siapa pun hanyalah hobi pribadi. Masalah tersulit yang belum terpecahkan dalam pengembangan indie bukan lagi membuat game. Masalahnya adalah distribusi. Karena itu, engine tidak berhenti pada &quot;dapat dimainkan&quot;. Engine berhenti pada &quot;berada di hadapan pemain&quot;.</p>
<p>Setiap proyek di Cinevva memiliki URL berbagi stabil seperti <code>play.cinevva.com/{game-id}</code> yang membuka build terbaru game dalam iframe sepenuh halaman dengan overlay kecil untuk suka dan bagikan. Ketika agen memanggil <code>game_ready</code>, agen tidak hanya mengaktifkan pratinjau di dalam IDE. Agen juga menawarkan untuk memublikasikan reel gameplay berdurasi 15 detik ke <a href="/id/play">etalase Cinevva</a>. Reel tersebut adalah rekaman nyata dari game yang sedang dimainkan, direkam langsung dari iframe (kami menyertakan skrip perekam kecil yang disuntikkan agen ke runtime game), sehingga yang dilewati penonton saat menggulir adalah gameplay sungguhan, bukan hasil edit pemasaran.</p>
<p>Hal itu mengubah siklus kerja seorang developer. Siklus lama adalah menulis kode, membuat build, mengemas, mengunggah, menulis halaman Steam, bertarung melawan algoritme, lalu mengamati penghitung wishlist. Siklus baru adalah mengetik satu kalimat, melihat agen membangun, menekan publikasikan, lalu melihat game Anda muncul dalam feed geser yang sama bersama semua game lainnya. Penemuan terjadi di produk yang sama dengan tempat proses pembuatan berlangsung, pada URL yang sama, dengan login yang sama.</p>
<p>Bagi pembaca dari komunitas developer, inilah bagian yang perlu dicermati. Distribusi selalu menjadi benteng pertahanan yang tidak disertakan bersama game engine. Unity menyediakan editor, lalu Anda merilis game di Steam. Unreal menyediakan editor, lalu Anda merilisnya di Epic Store. Cinevva menyediakan keduanya. Engine dan etalase saling berkomunikasi melalui orkestrator yang sama dengan yang membangun game.</p>
<h2>9. Top Performers: flywheel penemuan</h2>
<img src="/img/blog/engine-anatomy/cinevva-engine-charts.png" alt="Peringkat Top Performers Cinevva. Tiga tab di bagian atas bertuliskan Sedang Tren, Terbaru, dan Teratas, dengan Teratas dipilih. Di bawahnya terdapat baris podium berisi tiga game unggulan: nomor satu The Breaker Belt dengan 42,1 ribu permainan, nomor dua Roadhawk Runner dengan 27,7 ribu permainan, dan nomor tiga Asteroid Drift dengan 37,1 ribu permainan. Di bawah podium terdapat grid yang lebih padat berisi enam kartu game lebih kecil, termasuk Pixel Platformer, Zombie Shooter, Fruit Ninja Clone, Tower Defense, Card Battler, dan Zombie Builder, masing-masing dengan gambar mini, nama pengguna kreator, dan jumlah permainan." style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Feed reel adalah separuh dari flywheel. Separuh lainnya adalah <a href="/id/charts">peringkat Top Performers</a>. Peringkat ini menyusun game berdasarkan yang sedang tren, terbaru, dan teratas sepanjang masa, dengan bobot berdasarkan tingkat penyelesaian (apakah pemain menyelesaikan satu sesi), bukan sekadar klik mentah. Tingkat penyelesaian lebih sulit dimanipulasi daripada jumlah instalasi. Game yang mampu mempertahankan perhatian selama enam puluh detik mengalahkan game yang hanya dibuka lalu ditutup.</p>
<p>Setiap sinyal menjadi masukan bagi giliran orkestrator berikutnya. Ketika agen berkata, &quot;mari tambahkan power-up&quot;, agen tidak mengambilnya dari pustaka pola yang tetap. Agen mengambilnya dari model yang telah mengamati mekanik apa saja yang benar-benar mempertahankan pemain di Cinevva bulan ini. Flywheel bukan sekadar grafik di bagian bawah halaman. Flywheel adalah sinyal pelatihan bagi seluruh engine.</p>
<p>Bagi investor, inilah benteng datanya. Kami tidak hanya memiliki game yang dihasilkan. Kami memiliki game yang dihasilkan beserta metrik engagement nyata pada tingkat sesi, yang terhubung dengan prompt yang menghasilkannya, terhubung dengan pilihan aset yang dibuat agen, dan terhubung dengan pemain yang menyukainya. Setiap siklus memperkuat siklus berikutnya.</p>
<h2>10. Engine menjadi sebuah game</h2>
<p>Inilah bagian yang sudah saya isyaratkan di media sosial selama berbulan-bulan. Semua yang dijelaskan pada bagian 1 hingga 9 menggambarkan sistem yang membangun game. Hal yang lebih sulit dijelaskan, sampai Anda melihatnya sendiri, adalah apa yang terjadi ketika sistem tersebut menjadi sebuah tempat.</p>
<p>Membuat game adalah pekerjaan berat, bahkan dengan semua yang telah kami hadirkan. Jika Anda belum pernah membuat game, mendadak Anda bertanggung jawab atas plot, karakter, dunia, mekanik, siapa melakukan apa dan kapan, bagaimana cahaya berperilaku, bagaimana lapisan efek khusus disusun, musik, efek suara, dan pergerakan kamera. Itu banyak sekali. Di atas semua itu, Anda ingin hasilnya terasa seperti milik Anda, bukan seperti template yang dimuntahkan alat milik orang lain. Prompt dan orkestrator menangani sebagian besar pekerjaan mekanis untuk Anda. Hal yang tidak dapat mereka lakukan sendiri adalah memberikan panggung bagi karya Anda yang sudah selesai, dengan orang lain menyaksikannya.</p>
<p>Jadi, kami membangun panggungnya. Hampir sepanjang tahun ini, <a href="/id/about">Oleg</a> dan tim engine telah memublikasikan pekerjaan tersebut dalam <a href="/id/blog/2026-02-25-open-world-browser-series-guide">seri 14 bagian</a> tentang menghadirkan open world di browser. Medan pahatan yang dapat Anda ukir secara real time. Bioma yang otomatis mengecat dirinya sendiri menjadi batu atau rumput berdasarkan kemiringan dan ketinggian. 80.000 helai rumput yang melentur tertiup angin di atas medan hasil komputasi. Karakter yang berjalan, berlari cepat, melompat, dan melayang melintasi medan heightmap dan volumetrik dalam langkah yang sama. Semua itu bukanlah demo teknologi demi demo itu sendiri. Semua itu adalah fondasi untuk ini.</p>
<p>Kini open world tersebut sudah tayang dalam bentuk awal. Anda mengenakan avatar dan masuk ke dalamnya. Game yang Anda publikasikan muncul sebagai ruang yang dapat dikunjungi di sekitar Anda, seperti <a href="/id/play">reel etalase</a> dan <a href="/id/charts">peringkat Top Performers</a> menampilkannya sekarang, tetapi Anda tiba dengan berjalan kaki alih-alih menggeser layar. Anda dapat masuk ke game milik orang asing langsung dari dunia tersebut tanpa meninggalkan dunia itu. Anda dapat berdiri di samping orang yang membuat karya yang baru saja Anda mainkan dan memberi tahu mereka apa yang akan Anda tambahkan selanjutnya. Anda dapat memahat sebidang medan bersama seseorang yang baru Anda temui dan mengubahnya menjadi benih proyek baru. Penemuan tidak lagi berupa feed. Penemuan menjadi sebuah perjalanan.</p>
<p>Engine kami selalu merupakan game engine dalam arti teknis. Kini engine tersebut juga menjadi game dalam arti harfiah. Sesuatu yang membangun game Anda kini menjadi game itu sendiri, dan orkestrator yang sama dari bagian 3, jalur aset yang sama dari bagian 4, kontrak <code>getGameState</code> yang sama dari bagian 6, reel yang sama dari bagian 8, serta peringkat yang sama dari bagian 9, semuanya berpadu menjadi satu tempat tempat para pemain Anda berjalan-jalan. Batas antara membuat dan bermain sejak awal memang artifisial. Kini batas itu telah hilang.</p>
<h2>Hal-hal yang menurut kami berhasil kami lakukan dengan benar</h2>
<p>Hal pertama yang kami lakukan dengan benar adalah memperlakukan prompt sebagai kemudahan UI, bukan sebagai produk. Produknya adalah orkestrator, permukaan alat, jalur aset, dan etalase. Prompt adalah cara termurah untuk membawa pengguna masuk ke dalam sistem.</p>
<p>Hal kedua adalah bersikeras menggunakan filesystem datar yang native bagi browser tanpa langkah build. Itulah sebabnya satu game Cinevva dapat dirilis ke perangkat seluler, desktop, Steam, dan Discord dari satu sumber kebenaran. Itulah sebabnya agen dapat membaca apa yang ditulisnya.</p>
<p>Hal ketiga adalah kontrak bahwa setiap game yang dihasilkan mengimplementasikan <code>getGameState</code> dan <code>setGameState</code>. Satu baris dalam prompt sistem itu membuat agen terasa seperti kolaborator, bukan generator kode. Agen dapat bermain, dan sistem yang dapat bermain juga dapat melakukan debugging.</p>
<p>Hal keempat adalah menghubungkan etalase ke dalam siklus yang sama dengan engine. Kami tidak akan menang hanya dari kualitas model mentah. Tidak ada keunggulan yang dapat dipertahankan hanya dengan berada dua bulan di depan generator open-weights. Kami menang ketika agen yang sama yang membangun game Anda juga memublikasikannya, mengukurnya, dan belajar dari cara orang asing memainkannya.</p>
<p>Jika Anda ingin melihat seluruh mesin ini bergerak, prompt di halaman beranda tetap menjadi pintu masuknya. Ketik satu kalimat. Lihat apa yang terjadi di baliknya. Lalu kembali ke sini dan beri tahu kami bagian engine mana yang perlu kami ulas berikutnya.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 16: Struktur untuk dunia yang terus berkembang]]></title>
            <link>https://app.cinevva.com/id/blog/2026-04-28-open-world-browser-part-16-structure-and-authoring</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-04-28-open-world-browser-part-16-structure-and-authoring</guid>
            <pubDate>Tue, 28 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 33 memecah monolit sepanjang 6.285 baris menjadi modul-modul dan mengungkap tiga bug tersembunyi terkait urutan inisialisasi. Spike 34 menggunakan struktur tersebut untuk menambahkan lebih dari 100 prop yang dapat ditempatkan tanpa membuat apa pun membengkak.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 16: Struktur untuk dunia yang terus berkembang</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Salah Satu Pendiri Cinevva</em></p>
<p>Baru mengikuti seri ini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menautkan semua bagian.</p>
<p>Setiap spike sejak <a href="/id/blog/2026-04-13-open-world-browser-part-13-terrain-sculpting">bagian 13</a> mengikuti resep yang sama: salin monolit sebelumnya, lalu tambahkan satu fitur. Pada akhir <a href="/id/blog/2026-04-13-open-world-browser-part-15-multiplayer-and-water">spike 32</a>, monolit tersebut telah mencapai 6.285 baris <code>index.html</code> dalam satu <code>&lt;script type=&quot;module&quot;&gt;</code>. Hasil pencarian kode penuh gangguan, mencari tempat untuk menambahkan fitur membutuhkan waktu lebih lama daripada menulisnya, dan setiap perubahan arsitektur menyentuh berkas yang terlalu besar untuk dipahami perbedaannya hanya dalam pikiran. Sebelum menambahkan fitur lain, kami membenahi strukturnya.</p>
<h2>Memecah monolit tanpa mengubah perilaku</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/33-code-structure/" title="Refaktor Struktur Kode Spike 33" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/33-code-structure/" target="_blank">Buka Spike 33 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=33-code-structure">Lihat kode sumber</a></p>
<p>Batasannya ketat: setiap pemisahan harus berupa refaktor murni, bukan desain ulang. Monolit tersebut berubah menjadi 19 berkas <code>.mjs</code> ditambah shell host sepanjang 151 baris. Ada modul tingkat atas untuk scene, air, rumput, karakter, fisika, multipemain, dan UI; sebuah <code>wgsl.mjs</code> yang menyimpan setiap string sumber WGSL sebagai satu-satunya sumber kebenaran GPU; serta subpohon <code>terrain/</code> untuk heightmap, SDF, chunk, pembungkus buffer GPU, brush, LOD, dan persistensi. Total kodenya menjadi 6.555 baris, pada dasarnya monolit tersebut ditambah boilerplate impor. Tidak ada perubahan bersih pada volumenya, tetapi kemudahan navigasinya berubah drastis.</p>
<p>Lalu halaman dimuat sebagai layar hitam. Dua pesan kesalahan, dengan dua akar masalah yang tidak berkaitan. Yang pertama adalah keluhan WebGPU tentang binding buffer berukuran nol byte. Dalam monolit, buffer brush SDF dialokasikan secara lazy ketika chunk marching cubes pertama muncul, dan factory bind group kebetulan dijalankan belakangan, setelah buffer tersedia. Memisahkan <code>terrain/gpu.mjs</code> dari <code>terrain/brush.mjs</code> mengubah urutan evaluasi modul sehingga factory kini berjalan lebih dahulu dan mencoba melakukan binding pada placeholder <code>null</code>. Solusinya adalah menunda pembuatan bind group hingga dispatch pertama dengan helper <code>getOrCreateBindGroup(chunk)</code>. Pola &quot;buat semuanya di awal&quot; merupakan artefak dari jalur inisialisasi tunggal milik monolit.</p>
<p>Pesan kedua adalah peringatan skeleton FBX yang tampak menakutkan, tetapi ternyata hanya pengalih perhatian. Peringatan itu telah muncul sejak spike 25 dan tidak berbahaya. Karakternya hilang hanya karena bug pertama memicu efek berantai: setiap compute dispatch melempar error, heightmap tidak pernah ditulis, sampel ketinggian mengembalikan 0, dan karakter muncul di titik origin lalu jatuh menembus dunia. Perbaiki buffernya, dan karakter kembali beranimasi dengan baik, meskipun peringatannya tetap ada.</p>
<p>Itulah pelajaran sebenarnya dari refaktor ini. Monolit menyembunyikan setiap hubungan &quot;X harus tersedia sebelum Y dibuat&quot; dalam urutan skrip dari atas ke bawah. Modularisasi mengacak urutan tersebut dan mengungkap tiga bug laten lain terkait urutan: penyebaran rumput sebelum heightmap diunggah, bidang air ditambahkan sebelum environment map selesai didekode, dan pemuatan persistensi selesai setelah frame pertama. Ketiganya hanya memerlukan perbaikan satu baris, dan tidak satu pun akan ditemukan tanpa pemisahan tersebut.</p>
<h2>Seratus prop tanpa membuat apa pun membengkak</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/34-world-authoring/" title="Authoring Dunia Spike 34" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/34-world-authoring/" target="_blank">Buka Spike 34 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=34-world-authoring">Lihat kode sumber</a></p>
<p>Spike 34 menjadi pengujian apakah struktur tersebut benar-benar membuahkan hasil. Tujuannya adalah membuat palet sudut pandang orang pertama untuk menempatkan pohon, batu, semak, jamur, dan jalan setapak dari paket model CC0, lengkap dengan penyelarasan yang mengikuti medan, persistensi, sinkronisasi multipemain, dan collider fisika, semuanya tanpa keluar dari kontrol permainan. Setiap baris kode baru ditempatkan dalam lima berkas baru di bawah <code>src/props/</code>, dan tidak ada modul yang sudah ada bertambah lebih dari sepuluh baris penghubung.</p>
<p>Perjalanan asetnya sempat memutar dan layak dicatat, karena masalah semacam ini dapat menghabiskan satu hari. Kami memulai dengan Ultimate Nature pack dari Quaternius, sebuah pustaka FBX tanpa tekstur tertanam. Material FBX-nya disediakan sebagai <code>MeshPhong</code> tanpa map, jadi kami membuat tabel manual dari nama material ke PNG, mengonversi Phong menjadi Standard, dan mengatur ruang warna secara manual. Sekitar 30% material tidak memiliki PNG yang cocok, dan beberapa nama bersifat ambigu di antara pohon-pohon yang serupa. Paket FBX kedua memiliki kekurangan yang sama. Solusinya bukan menambah tabel pemetaan, melainkan memakai paket dengan authoring yang lebih baik: Stylized Nature MegaKit dari Quaternius menyediakan 116 glTF lengkap dengan material PBR tertanam dan normal yang telah di-bake. Mengganti <code>FBXLoader</code> dengan <code>GLTFLoader</code> menghapus penskalaan cm ke meter, tabel tekstur, dan konversi Phong, serta memangkas <code>library.mjs</code> sekitar 80 baris. Kesimpulannya: glTF dengan PBR adalah pipeline yang tepat untuk paket CC0 yang menyediakannya, sedangkan FBX dengan pemetaan tekstur manual membutuhkan kode dua kali lebih banyak untuk kualitas setengahnya.</p>
<p>Jalur glTF juga memiliki beberapa sisi tajam. Palet merender 116 thumbnail, dan <code>canvas.toDataURL()</code> milik WebGPU menghasilkan gambar kosong untuk permukaan <code>GPUCanvasContext</code>, sehingga thumbnail dirender ke <code>RenderTarget</code>, dibaca kembali dengan <code>readRenderTargetPixelsAsync</code>, lalu disalin ke kanvas 2D, dengan tetap memperhatikan alignment baris 256 byte milik WebGPU. Pratinjau bayangan mengkloning setiap material untuk mewarnainya hijau, tetapi ini gagal pada mesh yang <code>material</code>-nya berupa array; masalah tersebut diperbaiki dengan cabang <code>Array.isArray</code>. Selain itu, normal map 16-bit yang berukuran sekitar 200 MB diperkecil sekali saja dengan <code>mogrify -depth 8</code> menjadi sekitar 32 MB, tanpa perbedaan visual karena browser tetap melakukan downsampling saat mengunggahnya.</p>
<h2>Ketika geometri yang dirender hanya ada di GPU</h2>
<p>Bug yang paling banyak memberi pelajaran adalah pratinjau bayangan yang tersentak dalam langkah 1 hingga 2 meter ketika kursor bergerak. Mesh medan menyimpan posisi vertex dalam <code>StorageBufferAttribute</code> karena compute pipeline menulisnya langsung di GPU, sehingga <code>Raycaster</code> CPU milik three.js tidak dapat melihatnya dan tidak menghasilkan apa pun. Fallback-nya berupa ray march kasar sejauh 1,5 m terhadap heightmap analitis, dan stride tetap itulah grid yang terlihat oleh pengguna. Kami menggantinya dengan march adaptif: stride 2,5 m saat jauh di atas permukaan, mengecil menjadi 0,4 m ketika berada dalam jarak 5 m darinya, lalu melakukan biseksi sebanyak 14 kali ketika tanda $(\text{ray}_y - \text{terrain}_y)$ berbalik. Hasilnya mencapai presisi submilimeter dengan sekitar 30 langkah lebar ditambah 14 biseksi per cast. Ketika geometri yang dirender hanya berada di GPU, jangan melawan raycaster; lakukan march terhadap sumber analitisnya.</p>
<h2>Collider yang tetap akurat saat diedit</h2>
<p>Kami memilih proxy primitif, bukan convex hull atau mesh collider. Prop Quaternius berbentuk gumpalan dan low-poly tanpa cekungan yang berarti, sehingga hull akan membutuhkan kira-kira 50 kali lebih banyak kode dan 10 kali biaya runtime untuk gameplay yang sama. Setiap prop direduksi menjadi satu bentuk yang diturunkan dari bounding box-nya: pohon dan kaktus menjadi kapsul vertikal, batu menjadi bola, batang kayu menjadi kapsul horizontal di sepanjang sumbu panjang, sedangkan semak dan bunga dekoratif tidak memiliki collider. Batu dan batang kayu dapat diinjak (dorongan hanya vertikal agar pemain dapat berdiri di atasnya), sedangkan pohon dan kaktus menghalangi (dorongan 3D penuh agar pemain tidak dapat memanjat batang). Spatial hash 8 m membatasi pengujian per frame pada lingkungan 3×3 di sekitar pemain, biasanya berisi nol hingga enam prop.</p>
<p>Dua keputusan desain menjaga sistem tetap koheren. Penyelarasan dengan medan merupakan flag manifest, bukan enum kategori yang di-hard-code dalam kode, sehingga pratinjau bayangan dan penempatan final membaca nilai <code>placement.alignToTerrain</code> yang sama dan tidak mungkin berbeda. Selain itu, prop yang telah ditempatkan bereaksi terhadap pengeditan medan melalui satu helper: setelah sapuan brush—baik lokal maupun yang diputar ulang dari peer—<code>refreshPlacementsInRadius</code> mengambil ulang sampel permukaan tanah di bawah setiap prop dalam lingkaran yang terdampak, menerapkan kembali penyelarasan, dan menghitung ulang endpoint collider. Pahat bukit di bawah pohon, dan pohon tersebut akan ikut terangkat. Persistensi dan multipemain menggunakan kembali pola spike 31 secara persis, dengan menyimpan daftar datar <code>{uid, propId, x, y, z, rotY, scale}</code> serta mereplikasi event penempatan, penghapusan, dan pergeseran melalui BroadcastChannel.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Dekomposisi modul ES di WebGPU.</strong> Memisahkan <code>&lt;script type=&quot;module&quot;&gt;</code> monolitik menjadi impor <code>.mjs</code> dengan bare path tidak memerlukan bundler ketika modul disajikan sebagai aset statis, dan TSL three.js berfungsi dengan baik melintasi batas modul. Biaya tersembunyinya adalah urutan inisialisasi: monolit menyandikan &quot;buat X sebelum Y&quot; melalui urutan skrip dari atas ke bawah, sedangkan modul dievaluasi berdasarkan urutan impor, yang dapat menjalankan factory bind group GPU sebelum buffernya tersedia. Pola solusinya adalah inisialisasi lazy (<code>getOrCreate...</code> pada penggunaan pertama) dan menunggu promise yang tepat, bukan mengandalkan urutan deklarasi.</p>
<p><strong>glTF dengan PBR tertanam dibandingkan FBX dengan pemetaan manual.</strong> glTF menggunakan satuan meter, mereferensikan teksturnya sendiri, dan langsung menyediakan <code>MeshStandardMaterial</code>, sehingga paket CC0 yang dibuat sebagai glTF dapat langsung dimasukkan ke pipeline PBR. Paket FBX tanpa metadata pengikatan tekstur memerlukan tabel nama-material-ke-PNG yang dipelihara secara manual dan mudah tidak sinkron pada setiap pembaruan paket, ditambah konversi Phong ke Standard serta penandaan ruang warna manual. Sebuah jaring pengaman untuk dedaunan menaikkan material <code>transparent</code> tanpa <code>alphaTest</code> menjadi kartu cutout <code>alphaTest: 0.5</code> agar urutan rendernya benar di belakang geometri opaque.</p>
<p><strong>Thumbnail offscreen WebGPU.</strong> <code>canvas.toDataURL()</code> menghasilkan gambar kosong untuk kanvas yang didukung <code>GPUCanvasContext</code> karena tidak ada jalur dari permukaan presentasi kembali ke konteks 2D. Merender ke <code>RenderTarget</code>, membaca piksel dengan <code>readRenderTargetPixelsAsync</code>, dan menyalinnya ke kanvas 2D dapat bekerja, selama proses penyalinan melangkah mengikuti stride read-back WebGPU yang diselaraskan ke 256 byte. Hasilnya di-cache dalam <code>localStorage</code> dengan key yang versinya dinaikkan agar perubahan paket membatalkan hasil render lama.</p>
<p><strong>Ray march adaptif terhadap heightmap analitis.</strong> Ketika vertex medan berada dalam <code>StorageBufferAttribute</code> GPU, raycaster CPU tidak dapat melihatnya. Melakukan march pada fungsi ketinggian analitis dengan stride besar ketika jauh dari permukaan, stride kecil ketika mendekatinya, dan penyempurnaan pencarian biner saat tanda $(\text{ray}_y - \text{terrain}_y)$ berbalik menghasilkan presisi kursor submilimeter dengan jumlah sampel terbatas. Primitif yang sama digunakan oleh kursor brush dan bayangan prop.</p>
<p><strong>Collider kapsul primitif dengan spatial hash.</strong> Setiap prop direduksi menjadi kapsul atau bola yang diturunkan dari kategorinya berdasarkan bounding box, dicatat sebagai <code>{kind, walkable, radius, p1, p2}</code>, dan didaftarkan ke setiap bucket hash 8 m yang disentuhnya. Pada setiap frame, pemain hanya menguji prop dalam lingkungan bucket 3×3, masing-masing dengan satu penyelesaian kapsul-lawan-kapsul. Proxy yang dapat diinjak (batu, batang kayu) mendapat dorongan vertikal saja, sedangkan proxy penghalang (pohon) mendapat dorongan 3D penuh. Lihat <a href="/id/guides/landscape-generation-browser#physics-on-sdf-terrain">tabrakan medan SDF</a> untuk matematika kapsul yang menjadi dasar sistem ini.</p>
<hr>
<p>Bagian 16 dari 29.
Sebelumnya: <a href="/id/blog/2026-04-13-open-world-browser-part-15-multiplayer-and-water">Bagian 15 - Ganti baseline, lalu sinkronkan</a>
Berikutnya: <a href="/id/blog/2026-05-01-open-world-browser-part-17-animations-and-search">Bagian 17 - Animasi yang tidak memerlukan retargeting, dan pencarian aset langsung</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Empat taruhan saya tentang industri game pada 2022. Bagaimana hasilnya sekarang.]]></title>
            <link>https://app.cinevva.com/id/blog/2026-04-24-2022-predictions-aging-well</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-04-24-2022-predictions-aging-well</guid>
            <pubDate>Fri, 24 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Dalam wawancara tahun 2022, saya menjagokan engine game WebGL, GPT-3 untuk dialog, kolaborasi kreatif real-time, dan kebangkitan indie. Empat tahun kemudian, inilah hasil dari masing-masing taruhan tersebut.]]></description>
            <content:encoded><![CDATA[<h1>Empat taruhan saya tentang industri game pada 2022. Bagaimana hasilnya sekarang.</h1>
<p><em>Oleh <a href="/id/about">Mariana Muntean</a>, CEO Cinevva</em></p>
<img src="/img/blog/tech-done-different.jpg" alt="Wawancara podcast Tech Done Different, Mei 2022" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Pada Mei 2022, saya menjalani wawancara dengan podcast <em>Tech Done Different</em> milik Ted Harrington. Tulisan aslinya <a href="https://medium.com/@vio-202020/interview-with-tech-done-different-3b9bf74d99c2">masih tersedia di Medium</a>. Saat itu, saya telah menjalankan Cinevva selama sekitar dua tahun. Kami memiliki lima orang, pendanaan sebesar $200 ribu, penghargaan Mozilla Builders yang terpajang di dinding, dan banyak pendapat tentang arah perkembangan pembuatan game.</p>
<p>Sebagian besar pendapat tersebut tidak populer pada 2022. Web3 sedang ramai dibicarakan, studio AAA mendominasi percakapan, GPT-3 masih berupa mainan riset, dan WebGL adalah sesuatu yang digunakan para penghobi untuk membuat game jam. Mengatakan dengan lantang bahwa &quot;setiap insan kreatif akan menjadi developer game&quot; hanya menghasilkan anggukan sopan dan nol cek investasi.</p>
<p>Minggu lalu, saya membaca kembali wawancara itu. Sebagian perkataan saya terdengar seperti angan-angan. Sebagian lainnya terdengar seolah-olah saya memiliki mesin waktu. Berikut empat taruhan yang paling terbukti, disandingkan dengan kenyataan pada 2026.</p>
<h2>Taruhan 1: Engine game semestinya berada di browser</h2>
<p>Yang saya katakan pada 2022:</p>
<blockquote>
<p>Teknologi WebGL dapat digunakan di berbagai platform, termasuk perangkat seluler, tidak seperti API lain yang mungkin terbatas hanya untuk PC. Jadi, baik saat berada dalam kenyamanan rumah maupun saat bepergian, Anda tetap dapat membuat dan menerbitkan karya. Game WebGL hanya menggunakan sebagian kecil daya CPU dan GPU yang dibutuhkan oleh game PC tradisional.</p>
</blockquote>
<p>Pada 2022, ini adalah taruhan yang berlawanan dengan arus. Semua engine besar mengandalkan unduhan, instalasi, dan siklus patch. Game browser identik dengan nostalgia Flash dan Friv.</p>
<p>Pada 2026, <a href="/id/blog/2026-02-25-open-world-browser-series-guide">engine dunia terbuka kami berjalan pada 120 FPS di tab browser</a>. Medan, pepohonan, fisika, sinkronisasi multipemain—semuanya dalam satu URL. Tanpa unduhan, tanpa toko aplikasi, tanpa instalasi.</p>
<img src="/img/blog/open-world-browser-120fps.png" alt="Dunia terbuka Cinevva berjalan pada 120 FPS di tab browser, dengan medan, pepohonan, fisika, dan kapsul pemain yang dirender dalam satu tab" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Browser berhasil mengejar ketertinggalan karena tiga hal hadir secara bersamaan. WebGPU diluncurkan di setiap browser utama. SharedArrayBuffer dan isolasi lintas origin menjadi andal. WebAssembly menjadi cukup cepat untuk menjalankan engine fisika sungguhan yang dikompilasi dari Rust. Tim kami <a href="/id/blog/2026-02-25-open-world-browser-series-guide">menerbitkan jurnal lapangan 12 bagian</a> tentang biaya nyata dari setiap langkah tersebut. Singkatnya, browser kini merupakan runtime game sungguhan, bukan sekadar tempat untuk menaruh demo dari game yang sebenarnya.</p>
<p>Taruhan di dalam taruhan ini yang luput dari saya: saya meremehkan seberapa besar pekerjaan yang diperlukan dari sisi budaya engineering. Engine game browser tidak lagi terhambat oleh browser. Hambatannya adalah asumsi bahwa game sungguhan harus memiliki launcher.</p>
<h2>Taruhan 2: AI adalah bagian dari pipeline, bukan fitur sampingan</h2>
<p>Yang saya katakan pada 2022:</p>
<blockquote>
<p>Agar platform kami bekerja tanpa hambatan, kami menggunakan berbagai alat game open source, sekaligus mengembangkan teknologi sendiri menggunakan Natural Language Processing, Computer Vision, dan solusi Open AI, seperti GPT3 untuk dialog serta DALL:E untuk menghasilkan gambar dari teks.</p>
</blockquote>
<p>Pada Mei 2022, GPT-3 adalah API berbayar yang belum pernah digunakan oleh kebanyakan orang. DALL·E baru berusia sekitar satu tahun dan masih memiliki daftar tunggu. Mengatakan bahwa kami akan menggunakannya sebagai alat produksi untuk pengembangan game, paling banter, merupakan ambisi yang sekadar bergaya.</p>
<p>Pada 2026, setiap pipeline kreatif yang serius menggunakan model bahasa dan pembuatan gambar, termasuk pipeline kami. Di Cinevva saat ini: ElevenLabs Music untuk soundtrack, ElevenLabs SFX untuk efek suara, Hunyuan3D dan SAM3D untuk aset, Flux untuk visual, Mubert untuk audio adaptif, serta AceStep untuk instrumentasi. Prompt dimasukkan, aset siap pakai dihasilkan, dan seluruh proses berlangsung di dalam editor.</p>
<img src="/img/blog/prompting-3d-games.png" alt="Pembuatan aset 3D berbasis prompt di dalam editor Cinevva" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Buktinya terdapat dalam laporan GDC 2026 <em>State of the Game Industry</em>. <a href="/id/signals/2026-03-28-the-52-52-split">Sebanyak 52% perusahaan game mengatakan bahwa AI generatif digunakan dalam produksi</a>. Sebanyak 52% developer yang sama mengatakan bahwa penggunaan AI berdampak negatif terhadap industri. Kedua angka tersebut benar. Intinya, teknologi yang mendasarinya menjadi kebutuhan standar jauh lebih cepat daripada yang ingin diakui oleh siapa pun.</p>
<p>Hal yang keliru dari perkiraan saya: saya mengira penolakan akan datang dari engineer yang mengkhawatirkan kualitas. Sebagian besar justru datang dari seniman yang mengkhawatirkan pekerjaan mereka. Percakapan itu <a href="/id/signals/2026-03-16-when-ai-overrides-the-artist">jauh lebih rumit daripada yang saya perkirakan</a>, dan orang-orang yang menganggapnya sebagai kemenangan mutlak tidak benar-benar memperhatikan.</p>
<h2>Taruhan 3: Pengembangan game membutuhkan kolaborasi ala Google Docs</h2>
<p>Yang saya katakan pada 2022:</p>
<blockquote>
<p>Source control dan pengelolaan versi aplikasi sering kali berkaitan dengan kolaborasi jarak jauh. Saat ini, untuk melakukannya, Anda harus tahu harus pergi ke mana, versi aplikasi mana yang perlu diunduh, dan tetap sinkron dengan semua orang. Jangan sampai salah satu anggota tim menggunakan versi aplikasi yang keliru karena itu akan menjadi masalah. Kami ingin menghadirkan pengalaman real-time yang menyerupai Google Docs: sederhana, mudah, tetapi tetap menyenangkan.</p>
</blockquote>
<p>Kolaborasi real-time dalam alat pemrograman masih merupakan gagasan pinggiran pada 2022. Replit memilikinya. VS Code Live Share juga sudah ada. Sebagian besar engine profesional membutuhkan Perforce, VPN, dan engineer senior yang mengawasi branch Anda.</p>
<p>Pada 2026, kolaborasi real-time menjadi standar bagi setiap alat kreatif yang ingin dianggap serius. Figma menjadikannya hal biasa dalam desain. Cursor dan Bolt menjadikannya hal biasa dalam pemrograman. Lovable menjadikannya hal biasa dalam pembuatan prototipe aplikasi. Engine game justru tertinggal, bukan memimpin.</p>
<img src="/img/blog/open-world-chunk-streaming.png" alt="Streaming chunk game dunia terbuka antarpemain secara real-time" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Di dalam engine kami sendiri, sinkronisasi multipemain kini berfungsi sebagai <a href="/id/blog/2026-02-25-open-world-browser-part-04-streaming-before-fancy">eksperimen teknis kelas utama</a>, dengan streaming chunk, presence, dan state bersama di browser. Pengalamannya lebih mendekati &quot;buka tautannya, langsung masuk&quot; daripada &quot;siapkan Perforce, tanyakan versi yang benar lewat Slack, lalu instal launcher&quot;.</p>
<p>Bagian yang saya remehkan: aspek tersulit dari kolaborasi real-time dalam game bukanlah jaringan. Aspek tersulitnya adalah menyelesaikan konflik dalam maksud kreatif. Dua orang yang mengedit level yang sama secara bersamaan merupakan masalah UX sebelum menjadi masalah sinkronisasi, dan sebagian besar alat belum berhasil mengatasinya.</p>
<h2>Taruhan 4: Masa depan adalah indie</h2>
<p>Yang saya katakan pada 2022:</p>
<blockquote>
<p>Para insan kreatif yang sebelumnya tidak mampu membuat konten game akan dapat melakukannya. Kita akan menemukan berlimpah cara baru bagi orang-orang untuk memahami dan mengekspresikan kreativitas. Kali ini, prosesnya tidak hanya akan dikendalikan oleh korporasi atau studio AAA besar. Masa depan adalah indie.</p>
</blockquote>
<p>Ini adalah kalimat paling romantis dalam wawancara tersebut, sekaligus yang paling mudah diabaikan pada 2022. Anggaran AAA belum pernah setinggi itu. Proyek indie belum pernah mengalami kesulitan sebesar itu untuk mendapatkan visibilitas. Secara matematis, arahnya tampak berkebalikan.</p>
<p>Pada 2026, perhitungannya berbalik. Kami membuat <a href="/id/blog/2026-02-18-a-breaker-belt">A Breaker Belt</a> dalam tiga hari, dengan dua orang, untuk web, perangkat seluler, dan PC dari satu codebase. Dahulu, hal itu membutuhkan satu tim kecil selama tiga bulan. <a href="/id/signals/2026-03-23-solo-devs-shipping-not-vibing">Developer solo benar-benar merilis game, bukan sekadar mengikuti tren vibe coding</a>, dan Steam Next Fest 2026 mencatat rekor jumlah peserta dari tim beranggotakan satu orang.</p>
<img src="/img/social/industry-solo-dev-shipping.png" alt="Developer solo merilis game berkualitas produksi menggunakan alat AI dan engine browser" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Biaya untuk mengetahui apakah ide aneh dapat berhasil telah anjlok. Itulah perubahan yang sesungguhnya, dan semua hal lainnya—AI dalam pipeline, browser sebagai runtime, serta kolaborasi real-time—hadir untuk mendukungnya. Developer solo dengan perangkat yang tepat kini memiliki kapasitas produksi setara studio beranggotakan 20 orang pada 2018.</p>
<p>Hal yang tidak saya perkirakan dengan cukup jelas pada 2022: hambatan berpindah dari produksi ke penemuan. Ketika semua orang dapat merilis game, ditemukan oleh pemain menjadi masalah tersulit. Itulah rangkaian taruhan berikutnya, dan kami sedang berada di tengah proses untuk mewujudkannya.</p>
<h2>Hal yang sengaja saya prediksi dengan keliru</h2>
<p>Beberapa taruhan dari 2022 masih belum terbukti atau perlu direvisi.</p>
<p>Sudut pandang Web3 dalam wawancara tersebut lebih dominan daripada yang seharusnya. Bagian enkripsi dan zero-knowledge proof tetap relevan sebagai fondasi hak atas konten. Framing seputar token dan marketplace tidak bertahan dengan baik, dan sebagian besar energi yang saya curahkan untuknya pada 2022 seharusnya digunakan untuk alat AI, tempat potensi sesungguhnya berada.</p>
<p>Saya juga meremehkan bahwa sebagian besar dari gagasan &quot;siapa pun dapat membuat game&quot; merupakan masalah penemuan dan distribusi, bukan masalah alat. Membuat game kini mudah. Ditemukan dan mendapatkan bayaran masih sulit, dan di situlah sebagian besar pekerjaan kami saat ini tercurah.</p>
<p>Itulah taruhan yang sedang kami buat sekarang. Kami baru saja meluncurkan feed reels ala TikTok di <a href="/id/play">cinevva.com/play</a>. Klip gameplay sungguhan dengan gestur geser vertikal, masing-masing berdurasi lima belas detik, tanpa trailer dan tanpa rekaman pemasaran. Jika sesuatu menarik perhatian Anda, cukup satu ketukan dan Anda langsung memainkannya di browser. Tanpa unduhan, tanpa instalasi, tanpa tutorial yang menghalangi Anda dari game tersebut.</p>
<p>Alasan hal ini penting bagi developer indie adalah perhitungan yang kejam. Steam Next Fest 2026 mencatat rekor jumlah peserta, yang terdengar bagus sampai Anda menghitung jatah perhatian untuk setiap game. Sebagian besar demo mendapatkan kurang dari seribu impresi. Funnel halaman toko sudah bermasalah bahkan sebelum AI memperburuknya. Permukaan scroll-and-swipe yang menjadikan gameplay sebagai iklan merangkum siklus penemuan menjadi satu gerakan. Sistem ini mempertemukan developer solo dengan pemain seperti TikTok mempertemukan musisi yang belum dikenal dengan pendengar. Inilah bagian yang hilang di antara &quot;siapa pun dapat merilis game&quot; dan &quot;siapa pun dapat sukses&quot;.</p>
<p>Jika Anda ingin membaca wawancara aslinya secara lengkap, <a href="https://medium.com/@vio-202020/interview-with-tech-done-different-3b9bf74d99c2">wawancaranya ada di sini</a>. Membacanya kembali sangat berguna. Sebagian besar hal yang kami katakan dengan lantang pada 2022 ternyata menjadi roadmap yang benar-benar dapat dijalankan, hanya saja dengan jadwal yang lebih cepat daripada perkiraan kami.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 13: Memahat medan dan matinya fungsi matematika]]></title>
            <link>https://app.cinevva.com/id/blog/2026-04-13-open-world-browser-part-13-terrain-sculpting</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-04-13-open-world-browser-part-13-terrain-sculpting</guid>
            <pubDate>Mon, 13 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Tiga kegagalan awal, mesh yang meledak, dan bug sambungan yang memaksa kami memikirkan ulang cara kerja data medan.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 13: Memahat medan dan matinya fungsi matematika</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Salah Satu Pendiri Cinevva</em></p>
<p>Baru mengikuti seri ini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menyediakan tautan ke semua bagian.</p>
<p>Selama dua belas bagian, kami membangun mesin medan yang bisa dilihat. Terbang di atasnya. Mengagumi sambungannya yang tidak retak. Kali ini kami ingin menyentuhnya.</p>
<p>Tujuannya terdengar sederhana: memungkinkan pemain memahat medan dengan kuas secara real-time, tanpa merusak sistem apa pun yang telah kami bangun selama 24 spike. Dibutuhkan tiga percobaan, dua bug yang tampak seperti kegagalan rendering tetapi ternyata merupakan kegagalan model data, serta pemikiran ulang yang mendasar tentang cara kerja data medan.</p>
<h2>Tiga kegagalan awal</h2>
<p>Spike 25 seharusnya menjadi bagian yang mudah. Basis kode produksi sudah memiliki raycaster yang mengenai mesh medan. Alat penempatan menggunakannya untuk meletakkan objek. Alat kuas mengikuti pola yang sama, hanya saja alat ini mengubah nilai heightmap alih-alih memunculkan prefab. Sederhana.</p>
<p>Percobaan pertama: saya membangunnya langsung di dalam kode TypeScript produksi <code>world/client/</code>. <code>terrain-brush.ts</code> baru, modifikasi pada <code>chunk.ts</code>, perubahan protokol, pembaruan komponen Vue. Dalam waktu satu jam, saya memiliki kuas yang kurang lebih berfungsi, tetapi batas chunk memperlihatkan diskontinuitas normal yang terlihat jelas. Saya tidak bisa memastikan apakah bug tersebut berasal dari kode kuas saya, sistem penyambungan chunk yang sudah ada, atau interaksi tertentu dengan loop rendering lengkap. Inilah persisnya situasi yang ingin dicegah oleh metodologi spike. Saya melewatkan aturannya dan langsung menanggung akibatnya. Semuanya dikembalikan.</p>
<p>Percobaan kedua: spike mandiri, tetapi saya memilih Three.js 0.170.0 dan WebGL. Kode produksi menggunakan WebGL, jadi pilihan itu terasa wajar. Namun, Spike 13–24 semuanya sudah beralih ke WebGPU. Membangun spike kuas WebGL hanya akan membuktikan bahwa sistem tersebut bekerja pada renderer lama, bukan renderer yang sedang menjadi tujuan migrasi kami. Salah arah. Mulai lagi dari awal.</p>
<p>Percobaan ketiga: WebGPU, <code>WebGPURenderer</code>, shader komputasi untuk pembuatan vertex, dengan stack yang sama seperti Spike 22. Kali ini arsitekturnya benar. Lima operasi kuas berfungsi: naikkan, turunkan, haluskan, ratakan, noise. P95 siklus kuas di bawah 4 md pada M1.</p>
<p>Dan bug sambungannya masih ada.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/25-heightmap-brush/" title="Spike 25 Kuas Heightmap" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/25-heightmap-brush/" target="_blank">Buka Spike 25 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=25-heightmap-brush">Lihat kode sumber</a></p>
<h2>Bug sambungan yang tak kunjung mati</h2>
<p>Perbaikan standar untuk perhitungan normal lintas chunk adalah tumpang tindih perbatasan: setiap chunk menyimpan satu lapisan data tambahan dari chunk tetangganya, sehingga perhitungan normal pada batas dapat mengambil sampel dari kedua sisi. Saya menerapkannya. Data tepi tetangga disalin ke buffer yang diperluas. Sambungannya masih retak.</p>
<p>Saya menyelidiki perhitungannya. Pada batas antara chunk A (cx=-1) dan chunk B (cx=0), kedua chunk harus menghitung normal yang sama pada vertex bersama. Shader chunk A mengambil sampel <code>mix(own_col31, own_col32, 0.85)</code>. Chunk B mengambil sampel <code>mix(neighbor_edge, own_col0, 0.85)</code>. Keduanya merupakan jalur interpolasi bilinear yang berbeda melalui data yang berbeda. Bahkan dengan data perbatasan yang benar, kedua chunk menghitung normal yang berbeda untuk titik yang sama.</p>
<p>Pada saat itulah saya menyadari bahwa penyalinan perbatasan bukanlah bug yang sebenarnya. Bug yang sebenarnya ada pada model datanya.</p>
<p>Setiap spike dari 1 hingga 24 menggunakan fungsi matematika prosedural bernama <code>height_at()</code>. Berikan koordinat dunia, dapatkan ketinggian. Bersih, global, tanpa status. Kuas tidak dapat mengubah fungsi matematika, jadi saya menambahkan buffer <code>displacement</code> di atasnya. Medannya kini menjadi <code>height_at(x,z) + displacement[i]</code>. Shader GPU memuat 30 baris fungsi noise untuk medan dasar, ditambah kode interpolasi bilinear untuk lapisan displacement. Kuas perataan harus mengurangi <code>height_at()</code> untuk mengetahui nilai displacement yang akan menghasilkan ketinggian target. Dua sistem yang ditumpuk satu sama lain, menghitung hal berbeda dengan strategi pengambilan sampel yang berbeda.</p>
<p>Bukan begitu cara kerja game sungguhan. Dalam produksi, medan yang dibuat kreator merupakan data sampel yang disimpan dalam buffer. Fungsi prosedural hanyalah pengganti praktis dari spike awal. Fungsi itu telah menunaikan tugasnya. Sekarang fungsi tersebut justru secara aktif menyebabkan bug.</p>
<p>Saya menghapusnya.</p>
<p>Setiap chunk kini memiliki <code>heightmap</code> Float32Array dengan nilai ketinggian aktual. Saat dibuat, noise prosedural mengisinya. Setelah itu, fungsi noise tidak pernah dipanggil lagi. Kuas mengubah langsung ketinggian yang tersimpan. Shader GPU membaca dari satu buffer menggunakan satu fungsi: <code>hm_at(i,j)</code>. Normal menggunakan central difference yang selaras dengan grid pada data yang sama. Tidak ada ambiguitas interpolasi bilinear. Tidak ada ketidakselarasan antara dua sistem. Panjang shader berkurang dari 90 baris menjadi 40.</p>
<p>Sambungannya memperbaiki diri sendiri. Kedua chunk pada tepi bersama kini membaca nilai ketinggian diskret yang sama dari buffer masing-masing (dengan titik interior tetangga yang benar dalam tumpang tindih perbatasan). Data masuk sama, normal keluar pun sama.</p>
<p>Ini bukan pelajaran tentang kuas. Ini adalah pelajaran tentang arsitektur data yang terungkap karena kuas.</p>
<h2>Mesh yang meledak</h2>
<p>Spike 26 adalah versi volumetriknya. Ubah volume SDF berukuran 64 kubik dengan kuas, lalu buat ulang mesh menggunakan marching cubes. Pertanyaannya sama seperti Spike 25, tetapi dalam 3D.</p>
<p>Saat pertama kali menjalankannya, mesh itu meledak. Duri-duri panjang mencuat ke segala arah, seperti bulu babi yang sedang mengalami hari buruk.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/26-sdf-brush/" title="Spike 26 Kuas SDF" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/26-sdf-brush/" target="_blank">Buka Spike 26 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=26-sdf-brush">Lihat kode sumber</a></p>
<p>Tabel kasus MC yang saya buat memiliki 3840 entri, bukan 4096. Tabel lengkapnya adalah $256\ \text{kasus} \times 16\ \text{slot} = 4096$, tetapi tabel saya berukuran $256 \times 15 = 3840$, dengan enam belas baris yang hilang mulai dari kasus 112. Setiap pencarian setelah indeks tersebut bergeser, sehingga nomor kasus tidak lagi cocok dengan data triangulasi. Ketika marching cubes membaca entri yang salah, ia membuat edge yang kedua titik ujungnya berada di sisi permukaan yang sama. Pada edge perpotongan yang sebenarnya, parameter interpolasi</p>
<p>$$
t = \frac{-v_a}{v_b - v_a}
$$</p>
<p>berada dalam $[0, 1]$ karena $v_a$ dan $v_b$ memiliki tanda yang berlawanan. Pada edge palsu, keduanya memiliki tanda yang sama, sehingga $v_b - v_a$ mendekati nol atau berganti tanda dan $t$ melesat keluar dari $[0, 1]`, menempatkan vertex jauh di luar volume. Kalikan hal itu dengan beberapa ratus sel yang salah dan Anda mendapatkan seekor landak.</p>
<p>Perbaikannya sangat sederhana: salin tabel yang telah terbukti dari Spike 12, byte demi byte. Pelajaran dipetik. Jangan pernah membuat ulang lookup table ketika salinan yang telah terbukti sudah tersedia.</p>
<p>Bug kedua lebih rumit. Kuas penghalus seharusnya melembutkan fitur medan. Namun, kuas itu justru menciptakan lipatan tajam. Masalahnya: saya menarik setiap nilai SDF menuju nol (isosurface). Kedengarannya seolah-olah itu akan menghaluskan permukaan, tetapi tindakan tersebut justru meruntuhkan distance field. Voxel di atas dan di bawah permukaan sama-sama bergerak cepat menuju nol, meratakan semuanya dalam radius kuas. Pada batasnya, voxel yang dihaluskan bertemu voxel yang tidak dihaluskan dengan perubahan mendadak. Kuas &quot;penghalus&quot; itu sebenarnya merupakan pembuat lipatan.</p>
<p>Solusinya adalah penghalusan Laplacian yang benar. Alih-alih menarik setiap nilai menuju nol, tarik nilainya menuju rata-rata dari 6 tetangga langsungnya:</p>
<p>$$
\phi_i \leftarrow \phi_i + \lambda\left(\frac{1}{6}\sum_{j \in N(i)} \phi_j - \phi_i\right)
$$</p>
<p>Suku dalam tanda kurung adalah Laplacian diskret, dan $\lambda \in (0, 1]$ adalah kekuatan penghalusan. Cara ini merata-ratakan geometri di sekitarnya, melembutkan bentuk permukaan sembari mempertahankan gradien distance field alih-alih meruntuhkannya.</p>
<h2>Semuanya sekaligus</h2>
<p>Spike 27 adalah gerbang integrasi. Ambil pipeline lengkap dari Spike 24 (patch heightmap, chunk MC, sambungan Transvoxel, LOD geomorph), lalu gabungkan dengan model data berbasis sampel dari Spike 25 dan kedua jenis kuas.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/27-hm-mc-brush/" title="Spike 27 Integrasi HM + MC + Kuas" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/27-hm-mc-brush/" target="_blank">Buka Spike 27 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=27-hm-mc-brush">Lihat kode sumber</a></p>
<p>Hal pertama yang saya lakukan adalah mencabut <code>height_at()</code> dari setiap shader. Ketiga shader komputasi (pengisian SDF, patch heightmap, sambungan Transvoxel) kini mengikat buffer GPU heightmap 129x129 yang sama dan menggunakan fungsi interpolasi bilinear <code>hm_sample()</code> yang sama melalui preamble WGSL bersama. Satu sumber data, banyak pemakai. Fungsi noise prosedural yang telah menghuni setiap shader sejak Spike 1 kini hilang.</p>
<p>Lalu masalah-masalah menarik mulai bermunculan.</p>
<p>Ketika kuas SDF mengunci sebuah chunk dalam mode MC, sambungan Transvoxel antara chunk tersebut dan tetangga heightmap-nya perlu mengambil sampel dari volume SDF, bukan heightmap. Saya memperluas shader sambungan dengan binding storage buffer tambahan dan flag MC per chunk. Ada empat kombinasi batas yang harus ditangani: HM-HM, HM-MC, MC-HM, MC-MC.</p>
<p>LOD menjadi teka-teki lain. Pada spike sebelumnya, mengalihkan chunk MC ke LOD yang lebih rendah berarti mengisi ulang SDF pada resolusi yang lebih kasar. Saya menggantinya dengan pengambilan sampel berbasis stride: data SDF tetap pada resolusi penuh (65 titik grid). Shader MC menghitung stride dari rasio ukuran grid terhadap jumlah sel. Pada LOD0, stride-nya 1. Pada LOD1, stride-nya 2, dengan mengambil sampel setiap dua voxel. Chunk dapat mengubah LOD dengan bebas tanpa menyentuh data SDF-nya.</p>
<p>Perbaikan yang paling memuaskan adalah pemunculan chunk vertikal secara dinamis. Pahat ke atas hingga melewati puncak chunk, maka chunk khusus MC baru akan muncul di atasnya dengan SDF yang diinisialisasi dari sisi batas chunk di bawahnya. Pahat ke bawah, hal yang sama terjadi. Dunia berkembang untuk mengakomodasi perubahan.</p>
<p>Masalah terakhir adalah kuas heightmap yang diam-diam tidak melakukan apa pun terhadap chunk yang terkunci ke MC. Kuas HM mengubah <code>heightmapCPU</code> dan mengunggahnya kembali. Chunk MC tidak lagi membaca dari heightmap karena SDF-nya sudah diisi dari heightmap tersebut lalu berkembang secara terpisah. Saya menambahkan <code>syncHeightmapToSdf()</code>: setelah heightmap berubah, turunkan ulang kolom SDF untuk setiap chunk MC dalam radius kuas dan unggah nilai barunya. Kedua jenis kuas kini berfungsi pada kedua jenis chunk.</p>
<h2>Apa yang sebenarnya kami pelajari</h2>
<p>Spike kuas seharusnya menjawab pertanyaan tentang performa: bisakah pemahatan berjalan dalam batas anggaran frame? Bisa. Itu bagian yang mudah.</p>
<p>Bagian tersulitnya adalah menyadari bahwa penggunaan <code>height_at()</code> sebagai sumber kebenaran medan selama 24 spike telah menciptakan dependensi tak terlihat yang rusak begitu kami mencoba mengedit apa pun. Fungsi prosedural itu bersih, global, dan tanpa status—hingga akhirnya fungsi tersebut bukan lagi medannya.</p>
<p>Aturan yang kami catat dan tidak akan kami lupakan:</p>
<ol>
<li>Ketinggian medan berasal dari data sampel. Chunk memiliki buffernya sendiri.</li>
<li>Pembuatan prosedural mengisi data awal. Itu bukan sumber kebenaran saat runtime.</li>
<li>Kuas mengubah data chunk secara langsung. Tidak ada lapisan displacement.</li>
<li>Normal berasal dari data yang sama melalui central difference yang selaras dengan grid.</li>
<li>Tumpang tindih perbatasan (1 sel dari interior tetangga) menangani normal lintas chunk.</li>
<li>Jangan pernah membuat ulang lookup table ketika salinan yang telah terbukti sudah tersedia.</li>
</ol>
<p>Dalam <a href="/id/blog/2026-04-13-open-world-browser-part-14-world-comes-alive">bagian 14</a>, kami berhenti memahat geometri debug dan mulai membuatnya terlihat dan terasa seperti tempat sungguhan.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Arsitektur heightmap berbasis sampel.</strong> Medan disimpan sebagai data milik masing-masing chunk, bukan dievaluasi dari fungsi prosedural saat runtime. Setiap chunk menyimpan <code>Float32Array</code> berisi nilai ketinggian aktual. Noise prosedural mengisi data awal pada saat pembuatan, lalu fungsi tersebut tidak pernah dipanggil lagi. Pendekatan ini menghilangkan ketidakselarasan sistem ganda antara medan berbasis matematika dan lapisan pengeditan, menyederhanakan operasi kuas (langsung mengedit nilai yang tersimpan), serta membuat shader GPU sangat sederhana (membaca dari buffer, menghitung normal melalui central difference yang selaras dengan grid). Untuk dunia terbuka dengan streaming, kepemilikan per chunk dengan tumpang tindih perbatasan 1 sel dari tetangga merupakan pendekatan standar. Lihat <a href="/id/guides/landscape-generation-browser#terrain-data-representation">panduan pembuatan lanskap</a> kami.</p>
<p><strong>Operasi kuas SDF.</strong> Mengubah signed distance field untuk memahat medan. Tambah (mengembungkan) menggunakan falloff smooth-step di sekitar bola. Kurangi (mengukir) menggunakan bentuk yang sama dengan nilai terbalik. Penghalusan menggunakan perataan Laplacian: baca 6 tetangga langsung, hitung nilai rata-ratanya, lalu tarik nilainya menuju rata-rata tersebut. Pendekatan naif dengan menarik nilai menuju nol akan meruntuhkan distance field dan menciptakan tepi tajam. Penghalusan Laplacian mempertahankan gradien medan sembari melembutkan fitur. Lihat <a href="/id/guides/landscape-generation-browser#signed-distance-fields-sdfs">representasi medan SDF</a>.</p>
<p><strong>Transvoxel dengan sumber data campuran.</strong> Sel transisi pada batas antara chunk MC dan chunk heightmap perlu mengambil sampel dari data yang berbeda pada setiap sisi. Shader sambungan membawa flag per chunk dan binding buffer untuk menangani keempat kombinasi (HM-HM, HM-MC, MC-HM, MC-MC). Ketika salah satu sisi terkunci ke MC, shader melakukan interpolasi trilinear pada buffer SDF alih-alih mengambil sampel dari heightmap.
<strong>LOD berbasis stride untuk marching cubes.</strong> Data SDF disimpan pada resolusi penuh terlepas dari level LOD chunk saat ini. Shader MC menghitung stride sampling dari rasio jumlah titik grid SDF terhadap jumlah sel MC. Pada resolusi penuh, stride-nya adalah 1; pada setengah resolusi, stride-nya adalah 2. Hal ini memisahkan data SDF dari perubahan LOD, sehingga chunk dapat bertransisi antar-LOD secara bebas tanpa membangun ulang SDF.</p>
<hr>
<p>Bagian 13 dari 14.
Sebelumnya: <a href="/id/blog/2026-02-25-open-world-browser-part-12-lessons">Bagian 12 - Cincin, kabut langit, dan hal yang akan kami lakukan lagi</a>
Berikutnya: <a href="/id/blog/2026-04-13-open-world-browser-part-14-world-comes-alive">Bagian 14 - Dunia menjadi hidup</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 14: Dunia menjadi hidup]]></title>
            <link>https://app.cinevva.com/id/blog/2026-04-13-open-world-browser-part-14-world-comes-alive</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-04-13-open-world-browser-part-14-world-comes-alive</guid>
            <pubDate>Mon, 13 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Material yang bereaksi terhadap pemahatan, rumput yang tumbuh di langit-langit gua, dan glider yang membuat Anda lupa bahwa Anda berada di tab browser.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 14: Dunia menjadi hidup</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Salah Satu Pendiri Cinevva</em></p>
<p>Baru mengikuti seri ini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menautkan semua bagiannya.</p>
<p>Setelah <a href="/id/blog/2026-04-13-open-world-browser-part-13-terrain-sculpting">bagian 13</a>, kami memiliki fitur pemahatan. Meninggikan medan, mengukir gua, menghaluskan tebing, semuanya secara waktu nyata dengan sambungan yang tetap utuh. Namun, dunianya tampak seperti demo teknologi. Shading datar dengan warna debug, overlay wireframe, serta geometri abu-abu dengan warna LOD untuk membedakan chunk. Anda bisa mengeditnya. Namun, Anda belum bisa merasakannya.</p>
<p>Tiga spike mengubah hal itu. Bukan arsitekturnya. Pipeline, buffer, dan penyambungan seam-nya sama persis seperti di Bagian 13. Kami hanya menambahkan lapisan-lapisan yang membuat medan terasa seperti sebuah tempat: permukaan yang merespons bentuknya, kehidupan yang tumbuh di permukaan tersebut, dan tubuh yang berjalan di atasnya.</p>
<p>Perbedaan antara &quot;secara teknis berfungsi&quot; dan &quot;saya ingin tetap berada di sini&quot; ternyata sangat kecil.</p>
<h2>Pahat tebing dan saksikan permukaannya berubah menjadi batu</h2>
<p>Spike 28 mengajukan pertanyaan yang spesifik: bisakah material empat lapis dengan pemetaan triplanar berjalan pada medan hasil komputasi tanpa menghabiskan anggaran frame? Jawabannya ya, tetapi bagian yang menarik adalah apa yang terjadi setelahnya.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/28-multi-material/" title="Spike 28 Tekstur Multi-Material" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/28-multi-material/" target="_blank">Buka Spike 28 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=28-multi-material">Lihat kode sumber</a></p>
<p>Empat tekstur prosedural (rumput, batu, pasir, salju) dihasilkan dari noise FBM saat startup. Tanpa file eksternal, tanpa pipeline aset, hanya matematika dan sebuah <code>DataTexture</code>. Bobot material berasal dari permukaannya sendiri: kemiringan dan ketinggian. Area datar di bawah garis pepohonan mendapatkan rumput. Permukaan curam mendapatkan batu. Dataran rendah mendapatkan pasir. Puncak tinggi mendapatkan salju. Setiap bobot mentah berasal dari <code>smoothstep</code> pada kemiringan dan ketinggian, lalu dinormalisasi per fragmen sehingga $\sum_i w_i = 1$ dan warna akhirnya hanyalah campuran berbobot $\sum_i w_i, c_i$. Normalisasi inilah yang mencegah permukaan menjadi gelap atau terlalu terang di area pertemuan bioma. Pemetaan triplanar menangani proyeksi UV untuk chunk MC yang segitiganya tidak memiliki koordinat UV bermakna.</p>
<p>Momen yang benar-benar meyakinkan kami: tinggikan medan dengan kuas untuk membuat tebing curam, lalu tekstur batu muncul pada permukaan baru di frame yang sama. Ratakan kembali dan rumput mengambil alih permukaan itu. Materialnya tidak mengetahui apa pun tentang kuas. Material hanya membaca posisi dunia dan normal permukaan, data yang sama dengan yang digunakan untuk membangun geometri. Siklus umpan balik dari pemahatan ke visual berlangsung seketika dan tanpa skrip khusus.</p>
<p>Spike 8 menguji biaya material medan satu setengah bulan lalu dengan mesh statis di WebGL. Spike 28 membuktikan bahwa material tersebut berfungsi pada medan dinamis hasil komputasi dengan seluruh pipeline pemahatan berjalan di bawahnya. Kami sudah mengalokasikan anggaran untuk ini, tetapi melihat semuanya tetap berjalan pada 60 fps masih terasa melegakan.</p>
<h2>80.000 rumpun rumput dan langit-langit gua</h2>
<p>Spike 29 adalah saat naluri pengembangan game mengambil alih.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/29-vegetation/" title="Spike 29 Vegetasi / Rumput Shader" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/29-vegetation/" target="_blank">Buka Spike 29 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=29-vegetation">Lihat kode sumber</a></p>
<p>Kami menginginkan rumput seperti di Breath of the Wild. Bukan jumlah poligonnya, melainkan rasanya. Rumput yang menutupi tempat-tempat yang tepat, bergerak tertiup angin, dan membuat Anda ingin berlari menerobosnya.</p>
<p>Setiap rumpun rumput terdiri dari tiga quad yang saling berpotongan pada sudut 60 derajat, dengan empat segmen vertikal agar dapat menekuk. Bentuk silang ini tampak bervolume dari sudut mana pun tanpa trik billboard. Satu <code>InstancedMesh</code> per chunk, 80.000 rumpun di seluruh dunia, dengan total sekitar 2,4 juta verteks rumput.</p>
<p>Penempatan adalah bagian yang penting. CPU menyusuri grid yang diberi jitter di setiap chunk dan mengevaluasi logika kemiringan/ketinggian yang sama dengan yang digunakan shader material GPU. Di tempat sistem material mengatakan &quot;rumput&quot;, rumput tumbuh. Di tempat batu atau pasir mendominasi, kepadatannya turun menjadi nol. Transisinya mulus karena bobot <code>smoothstep</code> yang mendasarinya menghasilkan gradien kontinu di tepi bioma. Anda tidak melihat batas karena memang tidak ada batas.</p>
<p>Lalu kami melakukan sesuatu yang belum tentu saya yakini akan berhasil. Rumput pada permukaan SDF. Fungsi penyebaran menyusuri setiap kolom volume SDF dan mencari zero-crossing di antara voxel yang bersebelahan. Ketika SDF beralih dari negatif ke positif, di sanalah terdapat permukaan. Normal permukaannya hanyalah gradien medan yang dinormalisasi, $\hat{n} = \frac{\nabla\phi}{\lVert\nabla\phi\rVert}$, yang dihitung dari perbedaan voxel, dan kemiringannya adalah $\arccos(\hat{n} \cdot \hat{y})$, yaitu sudut dari arah vertikal. Jika cukup landai, tempatkan rumput.</p>
<p>Ukir gua dengan kuas SDF di Spike 27. Kembali ke Spike 29 dan Anda akan melihat rumput tumbuh di atas langit-langit gua. Kode penyebaran tidak tahu apa itu gua. Kode itu hanya melihat permukaan dengan kemiringan dan ketinggian yang tepat. Perilaku emergen semacam inilah yang membuat sistem dunia terbuka memuaskan untuk dibangun.</p>
<p>Angin berupa gelombang sinus di shader verteks TSL, yang dimodulasi oleh koordinat V bilah rumput sehingga ujungnya bergoyang sementara akarnya tetap tertanam. Tekan V untuk beralih antara lembut, kuat, dan mati. Angin bekerja pada seluruh 80 ribu rumpun secara bersamaan tanpa biaya CPU karena semuanya dijalankan di shader verteks.</p>
<p>Spike 7 menguji 50 ribu instans rumput dan kami khawatir akan mencapai batasnya. Spike 29 menjalankan 80 ribu instans di atas medan komputasi, penyambungan seam, tekstur multi-material, dan kuas. Mengelompokkan semuanya ke dalam lebih sedikit draw call <code>InstancedMesh</code> tetap lebih penting daripada mengurangi jumlah verteks per bilah. Pelajaran dari Spike 7 tetap terbukti.</p>
<p>Satu hal yang kami tunda: rumput tidak diperbarui ketika Anda memahat medan di bawahnya. Matriks instans ditetapkan saat penyebaran dilakukan. Pahat bukit menjadi lembah dan rumput akan melayang di udara sampai Anda menekan G untuk menyebarkannya kembali. Cukup baik untuk sebuah spike. Versi produksi akan memerlukan penyebaran ulang untuk chunk yang ditandai kotor.</p>
<h2>Langkah kaki pertama</h2>
<p>Spike 30 adalah spike yang terus ingin saya buka kembali.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/30-physics/" title="Spike 30 Fisika Medan" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/30-physics/" target="_blank">Buka Spike 30 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=30-physics">Lihat kode sumber</a></p>
<p>Tanpa pustaka fisika. Kapsul khusus dengan timestep tetap 120 Hz. Basis kode produksi menggunakan Rapier di web worker (Spike 2 membuktikan latensinya tidak bermasalah), tetapi spike ini perlu membuktikan kueri tabrakannya sendiri. Bisakah karakter berjalan melintasi medan heightmap, melangkah ke medan SDF hasil pemahatan, dan tidak terjatuh menembusnya?</p>
<p>Intinya adalah fungsi bernama <code>terrainQuery(x, y, z)</code>. Fungsi ini memeriksa apakah posisi berada di dalam chunk yang dikunci ke MC. Jika ya, fungsi tersebut melakukan interpolasi trilinear pada salinan SDF di CPU dan mengembalikan gradien sebagai normal permukaan. Jika tidak, fungsi melakukan pencarian heightmap dengan normal beda-tengah. Karakter tidak tahu sistem medan mana yang sedang dipijaknya. Karakter hanya meminta posisi tanah dan mendapatkan jawaban.</p>
<p>Tabrakan SDF adalah bagian yang saya perkirakan akan sulit. Tujuh titik probe di sekitar kapsul (bawah, tengah, atas, dan empat offset arah mata angin). Probe pada posisi $\mathbf{x}$ mengalami penetrasi setiap kali $\phi(\mathbf{x}) &lt; r$, dengan kedalaman penetrasi $p = r - \phi(\mathbf{x})$, dan arah pendorong keluarnya adalah gradien medan $\hat{n} = \frac{\nabla\phi}{\lVert\nabla\phi\rVert}$. Untuk mencegah kapsul kembali memasuki permukaan, kecepatan diproyeksikan untuk menghilangkan komponen yang mengarah ke dalam:</p>
<p>$$
\mathbf{v}' = \mathbf{v} - (\mathbf{v} \cdot \hat{n}),\hat{n}
$$</p>
<p>sehingga hanya tersisa komponen yang meluncur di sepanjang permukaan. Ini bukan mesin fisika. Hanya kueri geometri dan respons sederhana. Namun, sistem ini menangani gua, overhang, dan terowongan hasil pemahatan tanpa kode kasus khusus untuk tiap bentuk. Anda berjalan memasuki gua yang diukir sepuluh detik lalu dan kapsul mengikuti kontur langit-langitnya dengan tepat.</p>
<p>Model pergerakannya bermula dari sesuatu yang praktis, lalu menjadi menyenangkan. Berjalan, berlari, sprint, melompat, dan meluncur di lereng dengan kemiringan di atas 45 derajat. Kemudian saya menambahkan paraglider ala BotW dan spike ini berubah menjadi sesuatu yang tidak ingin saya tutup.</p>
<p>Tekan Space saat berada di udara. Gravitasi turun dari -30 menjadi -4. Kecepatan jatuh dibatasi pada -3. Mesh sayap delta terbuka dari kapsul dengan interpolasi skala. Berbelok ke kiri dan sayapnya ikut miring. Arah hadap kapsul secara otomatis sejajar dengan vektor kecepatan sehingga Anda selalu melihat ke arah gerak. Lepaskan Space untuk jatuh. Sentuh tanah dan Anda langsung kembali berlari.</p>
<p>Kamera mundur ke sudut pandang orang ketiga (tekan P untuk beralih). Kamera mengikuti pemain dari belakang dengan penghalusan yaw. Ray-march dari pemain ke kamera menguji medan dalam 20 langkah. Terbang memasuki gua dan lengan kamera memendek secara halus, bukan menembus batu. Keluar dari sisi lain dan lengan kamera kembali memanjang.</p>
<p>Inilah momen yang membuat spike ini sepadan: pahat tebing tinggi dengan kuas heightmap. Beralih ke kamera orang ketiga. Berlari ke tepinya. Lompat. Buka glider. Berbelok ke kiri di atas medan yang baru saja Anda pahat, dengan rumput yang Anda tumbuhkan di Spike 29 bergoyang di bawah, tekstur batu dari Spike 28 di permukaan tebing, serta seam Transvoxel yang tetap tersambung di setiap batas chunk. Mendarat di sisi lain. Semuanya bekerja bersama dalam satu tab browser.</p>
<h2>Memahat medan di bawah kaki sendiri</h2>
<p>Satu hal yang sempat saya ragukan: apa yang terjadi ketika Anda memahat medan yang sedang dipijak karakter? Perubahan heightmap langsung diteruskan melalui <code>terrainQuery()</code> karena fungsi tersebut membaca buffer CPU secara langsung. Perubahan SDF diteruskan melalui salinan SDF di CPU. Kapsul menyelesaikan penetrasi pada tick fisika berikutnya, yang pada 120 Hz terjadi dalam $\frac{1}{120} \approx 8.3$ ms.</p>
<p>Semuanya langsung berfungsi. Tinggikan tanah di bawah pemain dan pemain ikut terangkat. Ukir tanah di bawahnya dan pemain akan jatuh. Tanpa penanganan khusus. Fisika berjalan cukup cepat sehingga perubahan medan dalam satu frame tidak pernah menghasilkan penetrasi besar. Ini adalah keuntungan tak terduga dari pemilihan timestep 120 Hz. Kami memilihnya untuk pergerakan yang mulus, dan ternyata pilihan itu juga membuat pengeditan medan aman tanpa biaya tambahan.</p>
<h2>Setelah 30 spike</h2>
<p>Kami memulai seri ini dengan heightmap datar dan 500 kubus. Kini kami memiliki medan hasil pemahatan dengan gua volumetrik, penyambungan seam Transvoxel, tekstur multi-material yang merespons bentuk permukaan, 80.000 rumpun rumput yang bergoyang tertiup angin, serta karakter yang dapat berjalan, sprint, melompat, dan melayang melintasi semuanya.</p>
<p>Belum ada satu pun dari semua ini dalam versi produksi. Basis kode <code>world/client/</code> masih menjalankan WebGL dengan chunk heightmap sederhana. Semua hasil dari 30 spike ini berada di halaman HTML mandiri. Berikutnya adalah pekerjaan integrasi: bermigrasi ke <code>WebGPURenderer</code>, menghubungkan kebijakan hibrida HM/MC ke pengelola chunk, serta menghubungkan sistem kuas dan material ke mode multipemain.</p>
<p>Namun, sistem rendering bukan lagi risikonya. Pertanyaan yang masih terbuka kini berkaitan dengan aliran data: persistensi edit, sinkronisasi jaringan untuk sapuan kuas, dan pemahatan kolaboratif. Hal-hal yang terjadi di antara pemain, bukan di antara segitiga.</p>
<p>Jika Anda mengikuti seri ini sejak Bagian 1, terima kasih sudah bertahan melewati bagian-bagian yang berantakan. Jika Anda baru menemukannya, kembalilah ke <a href="/id/blog/2026-02-25-open-world-browser-part-01-risk-first">Bagian 1</a>. Pelajaran justru berada di jalan-jalan yang keliru.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>TSL (Three Shading Language).</strong> Sistem shader berbasis node milik Three.js untuk renderer WebGPU. Material disusun dari node (<code>positionWorld</code>, <code>normalWorld</code>, <code>smoothstep</code>, <code>triplanarTexture</code>) menggunakan komposisi fungsi dalam JavaScript. Graf shader dikompilasi menjadi WGSL saat runtime. TSL menggantikan <code>ShaderMaterial</code> GLSL mentah untuk target WebGPU dan menyediakan interoperabilitas antara fitur material standar Three.js (cahaya, bayangan, kabut) dan logika kustom per fragmen.</p>
<p><strong>Pemetaan triplanar.</strong> Teknik proyeksi tekstur yang mengambil sampel tekstur tiga kali (bidang XY, XZ, YZ) lalu mencampurkannya berdasarkan arah normal permukaan. Teknik ini menghilangkan peregangan UV pada geometri mesh arbitrer, yang sangat penting untuk keluaran marching cubes karena segitiganya tidak memiliki koordinat UV bermakna. TSL menyediakan <code>triplanarTexture()</code> sebagai node bawaan.</p>
<p><strong>Vegetasi terinstans dengan bilah cross-quad.</strong> Setiap rumpun rumput terdiri dari tiga quad yang saling berpotongan pada sudut 60 derajat, sehingga menciptakan tampilan bervolume dari arah pandang mana pun. Empat segmen vertikal per quad memungkinkan tekukan halus untuk animasi angin. Seluruh hamparan dirender sebagai satu <code>InstancedMesh</code> per chunk. Kapasitas dialokasikan 25% lebih besar agar instans baru dapat mengisi slot yang telah dicadangkan ketika medan diedit tanpa mengalokasikan ulang buffer GPU. Lihat <a href="/id/guides/landscape-generation-browser#vegetation-and-foliage">panduan pembuatan lanskap kami tentang vegetasi</a>.
<strong>Tabrakan kapsul vs SDF.</strong> Tabrakan karakter dengan medan volumetrik tanpa mesin fisika. Kapsul diuji pada beberapa titik terhadap SDF. Saat nilai medan lebih kecil daripada radius kapsul, gradien memberikan normal ke arah luar dan selisihnya menghasilkan kedalaman penetrasi. Pendekatan ini menangani gua, bagian menjorok, dan terowongan tanpa kode khusus untuk setiap bentuk. Lihat <a href="/id/guides/landscape-generation-browser#physics-on-sdf-terrain">tabrakan medan SDF</a>.</p>
<p><strong>Pengontrol karakter dengan timestep tetap.</strong> Fisika melangkah pada 120 Hz terlepas dari frame rate, dengan mengakumulasi waktu nyata dan memprosesnya dalam langkah berukuran tetap. Jumlah substep maksimum mencegah spiral kematian pada frame yang lambat. Penempelan ke tanah menjaga kapsul tetap menyentuh permukaan saat melintasi lereng. Timestep tetap memastikan perilaku deterministik untuk replay multipemain di masa mendatang.</p>
<hr>
<p>Bagian 14 dari 29.
Sebelumnya: <a href="/id/blog/2026-04-13-open-world-browser-part-13-terrain-sculpting">Bagian 13 - Memahat medan dan matinya fungsi matematika</a>
Berikutnya: <a href="/id/blog/2026-04-13-open-world-browser-part-15-multiplayer-and-water">Bagian 15 - Ganti baseline, lalu sinkronkan</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 15: Ganti fondasinya, lalu sinkronkan]]></title>
            <link>https://app.cinevva.com/id/blog/2026-04-13-open-world-browser-part-15-multiplayer-and-water</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-04-13-open-world-browser-part-15-multiplayer-and-water</guid>
            <pubDate>Mon, 13 Apr 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 31-32 menghasilkan keputusan untuk mengganti dunia lama dengan spike terbaik, lalu membuktikan multiplayer berbasis replay parameter kuas dan menambahkan lautan beserta mekanisme berenang.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 15: Ganti fondasinya, lalu sinkronkan</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru mengikuti seri ini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menyediakan tautan ke semua bagian.</p>
<p>Empat belas bagian pertama membahas spike 1 hingga 30. Rangkaian itu berakhir dengan sistem medan yang dapat dibentuk secara real time, ditambah karakter yang dapat berjalan, meluncur, dan jatuh di atasnya. Bagian ini melanjutkan seri dari spike 31, dan hal pertama yang harus kami putuskan bukanlah persoalan teknis. Persoalannya adalah apa yang harus dilakukan dengan seluruh kode spike tersebut.</p>
<h2>Keputusan &quot;ganti, jangan backport&quot;</h2>
<p>Kami memiliki 30 file HTML mandiri, masing-masing membuktikan satu konsep terpisah, tanpa integrasi sama sekali. <code>world/client/</code> produksi masih menggunakan stack lama: WebGL, heightmap sederhana, controller karakter sepanjang 75 baris, serta protokol MessagePack dengan sembilan jenis pesan. Tidak ada pengeditan, WebGPU, material, maupun vegetasi.</p>
<p>Rencana yang tampak jelas adalah melakukan backport hasil spike ke codebase produksi tersebut satu per satu. Kami membatalkan rencana itu. Spike 30 sudah memiliki medan, fisika, material, vegetasi, dan kamera yang lebih baik daripada apa pun yang pernah ada di <code>world/client/</code>. Melakukan backport ke kode WebGL lama berarti harus terus melawannya sepanjang proses. Jadi, kami memutuskan untuk mengganti implementasi dunia dengan spike yang paling berhasil dan melanjutkan pengembangan dari sana. Spike 30 menjadi fondasi baru, sedangkan <code>world/client/</code> menjadi kode mati.</p>
<p>Keputusan itu mengubah kerangka kerja yang tersisa. Untuk beralih dari &quot;demo teknologi single-player yang hebat&quot; menjadi &quot;produk&quot;, kami membutuhkan multiplayer, persistensi, streaming dunia tanpa batas, dan penempatan objek. Sinkronisasi medan multiplayer dikerjakan lebih dahulu karena aspek inilah yang memaksa terbentuknya arsitektur. Pertanyaan yang dijawabnya mudah diajukan, tetapi sangat mahal jika dijawab dengan keliru: ketika Pemain A membentuk medan, apa yang sebenarnya dikirim melalui jaringan?</p>
<h2>Replay parameter kuas, bukan sinkronisasi piksel</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/31-multiplayer-sync/" title="Spike 31 Sinkronisasi Medan Multiplayer" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/31-multiplayer-sync/" target="_blank">Buka Spike 31 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=31-multiplayer-sync">Lihat kode sumber</a></p>
<p>Sebelum menulis satu baris pun kode jaringan, kami menelusuri secara persis apa yang dilakukan satu sapuan kuas. Kuas heightmap menelusuri radius di sekitar kursor dalam <code>Float32Array</code> CPU, menerapkan falloff smoothstep, lalu menambah, mengurangi, menghaluskan, atau meratakan nilainya. Kuas SDF melakukan hal yang sama dalam 3D pada sebuah bola voxel. Kedua jalur tersebut sepenuhnya berupa operasi matematika array di CPU. Tidak ada komputasi GPU dalam loop, keacakan, ataupun floating point nondeterministik. Array input yang sama ditambah parameter yang sama menghasilkan output yang sama di setiap mesin.</p>
<p>Itulah keseluruhan triknya. Kami tidak mengirim medan yang telah diedit. Kami mengirim parameter kuas, 56 byte per tick sapuan, lalu setiap klien menjalankan ulang fungsi deterministik yang sama. Protokol sinkronisasi terdiri atas empat jenis pesan: penemuan peer, pesan kuas <code>{op, wx, wy, wz, radius, strength, flattenTarget}</code>, dan pesan posisi pemain pada 20Hz.</p>
<p>Untuk spike ini, kami sepenuhnya melewati server dan menggunakan <code>BroadcastChannel</code>, API browser untuk pengiriman pesan lintas tab dengan origin yang sama. Buka dua tab, keduanya langsung berkomunikasi tanpa infrastruktur apa pun. Dengan demikian, persoalan sinkronisasi dapat dipisahkan dari latensi, autentikasi, dan pengkabelan Durable Object. Jika replay parameter mencapai hasil yang sama di berbagai tab, pendekatan itu juga akan mencapai hasil yang sama melalui WebSocket.</p>
<p>Satu-satunya tempat replay dapat menyimpang adalah operasi yang bergantung pada urutan. Menaikkan dan menurunkan bersifat komutatif, sehingga <code>val + strength * falloff</code> menghasilkan nilai yang sama terlepas dari siapa yang menerapkannya lebih dahulu. Operasi penghalusan dan perataan membaca nilai tetangga, sehingga dua klien yang menghaluskan titik yang benar-benar sama pada saat yang sama dapat menyimpang beberapa fraksi milimeter per tick. Dalam praktiknya, kondisi itu hampir tidak pernah terjadi, dan solusi produksinya sudah jelas: rutekan pengeditan melalui DO, biarkan DO menetapkan nomor urut monotonik, terapkan secara optimistis pada klien, lalu koreksi urutannya jika urutan otoritatif tidak sesuai. Ini adalah optimistic concurrency klasik, dan DO memang merupakan titik serialisasi yang alami.</p>
<h2>Kapsul peer yang terus menghilang</h2>
<p>Pengeditan tersinkronisasi pada percobaan pertama. Kapsul pemain jarak jauh tidak. Kapsul itu berkedip, muncul dan menghilang di tab lain, dan diperlukan perbaikan terhadap tiga bug terpisah agar kapsul tersebut tetap terlihat solid.</p>
<p>Kapsul dibuat di titik asal dunia, yang terkubur di bawah medan, karena pesan <code>join</code> tiba sebelum data posisi apa pun. Solusinya: mulai dalam keadaan tersembunyi dan tampilkan pada pembaruan posisi pertama. Siaran posisi berada di dalam render loop, sedangkan Chrome membatasi <code>requestAnimationFrame</code> pada tab yang tidak aktif. Akibatnya, pemeriksaan kedaluwarsa pada tab lain akan menghapus peer, lalu pesan berikutnya akan membuatnya kembali. Solusinya: pindahkan siaran ke <code>setInterval</code>, yang tidak dibatasi untuk tab yang terlihat. Selain itu, batas waktu kedaluwarsa 5 detik terlalu agresif dan dapat terpicu oleh jeda GC apa pun. Solusinya: naikkan menjadi 30 detik dan andalkan pesan <code>leave</code> yang bersih untuk penutupan normal.</p>
<h2>Persistensi dan late-join, format yang sama</h2>
<p>Kami menyatukan persistensi ke dalam spike yang sama alih-alih membuat spike baru, karena format serialisasinya identik, baik tujuannya IndexedDB maupun tab lain. Snapshot berisi heightmap lengkap (<code>Float32Array</code> 129×129, sekitar 66 KB), hanya chunk SDF yang telah diedit (masing-masing $65^3$, sekitar 1,1 MB), serta daftar ID chunk yang dikunci dalam mode marching-cubes. Penyimpanan dengan debounce menulis ke IndexedDB dua detik setelah pengeditan terakhir. Saat dimuat, medan prosedural dibuat secara sinkron, lalu state tersimpan menimpanya sebelum frame bermakna pertama. Late-join menggunakan kembali byte yang persis sama: saat tab baru bergabung, tab yang sudah memiliki pengeditan menyerialisasi state-nya dan mengirimkannya secara khusus kepada pendatang baru, lalu gunung yang Anda bentuk lima menit lalu muncul di layar mereka.</p>
<p>Pengujian persistensi pertama menemukan bug urutan yang menarik. Rumput disebarkan secara sinkron saat inisialisasi menggunakan ketinggian prosedural, tetapi pemulihan IndexedDB berlangsung secara asinkron dan menimpa heightmap setelahnya, sehingga setiap helai rumput mengambang atau tenggelam. Solusinya adalah pass <code>refreshAllGrass()</code> yang mengambil ulang sampel ketinggian di bawah setiap instance dan menyembunyikan helai rumput yang kini berada pada kemiringan atau ketinggian yang tidak sesuai. Fungsi yang sama digunakan untuk pemuatan maupun late-join.</p>
<h2>Drama lereng</h2>
<p>Medan yang dibentuk lebih kasar daripada fondasi prosedural yang mulus, dan hal itu mengungkap tiga bug fisika yang tidak mungkin ditemukan pada medan lama. Berjalan lurus menanjak membuat kapsul meluncur ke samping. Penyebabnya adalah proyeksi kecepatan yang dimaksudkan agar pergerakan tetap menyinggung permukaan tanah, tetapi ditulis hanya menggunakan komponen horizontal dari normal. Pada lereng diagonal dengan normal $(-0.3, 0.9, -0.3)$, berjalan ke utara tiba-tiba menghasilkan kecepatan menyamping tanpa sebab. Ground snap sudah menjaga pemain tetap berada di permukaan, jadi kami cukup menghapus proyeksi tersebut.</p>
<p>Drift tetap terjadi akibat sumber kedua. Probe tabrakan SDF mendorong body keluar mengikuti gradien sebesar kedalaman penetrasi. Pada lereng apa pun, gradien memiliki komponen horizontal, sehingga penetrasi 0,1 m pada lereng 15° mendorong sekitar 0,026 m ke samping per langkah. Pada 120Hz, itu setara dengan drift tak terlihat sekitar 3 m/s. Solusinya: pisahkan respons berdasarkan kemiringan. Pada permukaan yang dapat dilalui ($\text{grad}_y$ di atas ambang berjalan), dorongan hanya diberikan secara vertikal. Pada dinding dan tebing, dorongan 3D penuh tetap dipertahankan karena di sanalah defleksi memang diperlukan. Kami juga menaikkan batas kemiringan yang dapat dilalui dari $\cos 45°$ menjadi $\cos 60°$ agar perbukitan buatan kuas terasa dapat didaki seperti dalam Breath of the Wild.</p>
<p>Bug ketiga membuat kapsul membeku di batas chunk karena probe tabrakan mengambil sampel SDF dari satu chunk saja dan menerima sentinel &quot;jauh di udara&quot; ketika probe menyeberang ke chunk tetangga. Solusinya adalah <code>sdfSampleWorld(wx, wy, wz)</code> dan <code>sdfGradientWorld(...)</code>, yang menemukan chunk yang tepat untuk posisi dunia mana pun dan menggunakan estimasi jarak heightmap sebagai fallback ketika SDF tidak tersedia. Transisi tabrakan dari SDF ke heightmap kini berlangsung mulus.</p>
<h2>Air menyempurnakan dunia</h2>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/32-water-swimming/" title="Spike 32 Air dan Berenang" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/32-water-swimming/" target="_blank">Buka Spike 32 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=32-water-swimming">Lihat kode sumber</a></p>
<p>Setiap spike hingga titik ini berfokus pada &quot;daratan di atas air&quot;. Spike 32 menambahkan lautan dan, bersamanya, aksi pergerakan baru. Kami menetapkan permukaan air pada ketinggian 22 di medan yang berkisar antara 8 hingga 58. Pengaturan ini membanjiri lembah rendah, menyisakan pantai di garis pesisir, dan mempertahankan banyak daratan kering untuk bermain.</p>
<p>Permukaannya menggunakan <code>MeshStandardNodeMaterial</code> yang dibuat dengan TSL, pendekatan node yang sama seperti pada medan. Tiga gelombang sinus yang saling bertumpuk pada frekuensi berbeda menggeser vertex, sedangkan normal permukaan berasal dari turunan kosinus analitik gelombang tersebut, bukan dari normal mesh. Warna bertransisi dari biru kehijauan di perairan dangkal menjadi teal gelap di perairan dalam menggunakan estimasi kedalaman $(\text{level} - y + \text{wave}) \times 0.12$ yang dibatasi ke $[0,1]$. Buih muncul ketika estimasi itu mendekati nol di garis pantai, sedangkan alpha mengikuti kedalaman sehingga air dangkal tampak transparan dan air dalam hampir opak.</p>
<p>Mekanisme berenang menggunakan pegas daya apung. Pemain memasuki mode berenang ketika kaki turun melewati permukaan air dan pusat tubuh berada dalam jarak setengah tinggi kapsul dari permukaan. Sebuah pegas menarik tubuh menuju target tepat di bawah permukaan. Dengan konstanta daya apung 12 dan redaman air 4, pemain mengapung stabil dengan kepala di atas air tanpa osilasi. Kecepatan berenang lebih lambat daripada berjalan, dengan akselerasi dan drag yang terasa mengambang. Melompat di dekat permukaan akan melontarkan pemain keluar dengan 60% kecepatan lompatan normal, sedangkan saat masuk ke air, kecepatan turun dibatasi pada -5 m/s agar pemain tidak langsung terjun terlalu dalam. Tabrakan medan tetap berjalan di bawah air, sehingga Anda dapat berjalan di dasar danau ketika dasarnya naik melebihi target berenang. Flag berenang ikut dikirim dalam siaran posisi agar peer dapat melihat Anda berenang, dan overlay gradien HTML memberi rona pada tampilan ketika kamera turun ke bawah permukaan.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Replay parameter kuas deterministik.</strong> Alih-alih melakukan streaming medan yang telah diedit, setiap klien hanya mengirim parameter kuas dan menjalankan ulang fungsi CPU yang sama. Hal ini dimungkinkan karena kuas heightmap dan SDF sama-sama berupa operasi matematika murni <code>Float32Array</code> tanpa keacakan atau nondeterminisme GPU, sehingga input identik menghasilkan output yang identik hingga tingkat bit di mana pun. Payload-nya sebesar 56 byte per tick sapuan. Operasi komutatif (menaikkan, menurunkan) mencapai hasil yang sama terlepas dari urutan, sedangkan operasi yang membaca nilai tetangga (menghaluskan, meratakan) memerlukan titik serialisasi untuk menjamin konvergensi. Durable Object produksi menyediakannya melalui nomor urut monotonik.</p>
<p><strong>BroadcastChannel sebagai pengganti sementara WebSocket.</strong> API browser untuk pengiriman pesan lintas tab dengan origin yang sama tanpa server. Di sini, API tersebut digunakan untuk menguji protokol sinkronisasi secara terpisah dari latensi jaringan dan autentikasi. Format serialisasinya (<code>Float32Array</code> heightmap mentah, chunk SDF yang diedit, serta ID chunk yang dikunci ke MC) menggunakan byte yang sama untuk persistensi IndexedDB dan transfer state late-join, sehingga satu format dapat menangani tiga tugas.</p>
<p><strong>Respons tabrakan SDF yang dipisahkan berdasarkan kemiringan.</strong> Ketika probe kapsul menembus medan volumetrik, solusi naifnya adalah mendorong body keluar mengikuti gradien SDF sebesar kedalaman penetrasi. Pada lereng, gradien tersebut memiliki komponen horizontal yang menghasilkan drift lateral. Memisahkan respons agar permukaan yang dapat dilalui ($\text{grad}_y$ di atas ambang) hanya menerima dorongan vertikal, sementara permukaan curam mempertahankan dorongan 3D penuh beserta proyeksi kecepatan, menghilangkan drift tanpa mengorbankan tabrakan dinding. Lihat <a href="/id/guides/landscape-generation-browser#physics-on-sdf-terrain">tabrakan medan SDF</a>.</p>
<p><strong>Air TSL dengan normal gelombang analitik.</strong> Lautan menggunakan material node dengan vertex yang digeser oleh penjumlahan tiga gelombang sinus. Alih-alih menghitung ulang normal mesh setelah pergeseran, normal permukaan diturunkan secara analitik dari turunan kosinus fungsi gelombang. Pendekatan ini lebih murah dan menghindari artefak normal beda hingga pada grid kasar. Warna berbasis kedalaman, buih garis pantai, dan transparansi berbasis kedalaman semuanya menggunakan satu estimasi kedalaman yang sama.</p>
<p><strong>Berenang dengan pegas daya apung.</strong> Fisika berenang memodelkan tubuh sebagai pegas teredam yang ditarik menuju target tepat di bawah permukaan. Dengan konstanta daya apung 12 dan redaman 4, pemain menetap di permukaan tanpa berosilasi. Konstanta pergerakan yang berbeda—kecepatan lebih lambat, akselerasi mengambang, dan drag besar—membuat berenang terasa berbeda dari berjalan, sementara sistem tabrakan kapsul dengan medan yang sudah ada tetap berfungsi di bawah air.</p>
<hr>
<p>Bagian 15 dari 29.
Sebelumnya: <a href="/id/blog/2026-04-13-open-world-browser-part-14-world-comes-alive">Bagian 14 - Dunia menjadi hidup</a>
Berikutnya: <a href="/id/blog/2026-04-28-open-world-browser-part-16-structure-and-authoring">Bagian 16 - Struktur untuk dunia yang terus berkembang</a>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Cubcoats × Cinevva: Lembar Ringkas Konsep Game]]></title>
            <link>https://app.cinevva.com/id/blog/2026-03-19-cubcoats-game-concepts-one-pager</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-03-19-cubcoats-game-concepts-one-pager</guid>
            <pubDate>Thu, 19 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Tiga konsep game edukatif (Pohon Emas, Pulau Kata Kali, Kisah Pulau) berdasarkan alur kerja sketsa-ke-video-ke-3D dan Kali si Kucing. Untuk lisensi atau presentasi kepada mitra.]]></description>
            <content:encoded><![CDATA[<h1>Cubcoats × Cinevva: Lembar Ringkas Konsep Game</h1>
<p><em>Berdasarkan alur kerja sketsa-ke-video-ke-3D dan Kali si Kucing (Cubcoats). Untuk lisensi, blog, atau presentasi kepada mitra.</em></p>
<p><strong>Untuk dibagikan sebagai PDF:</strong> Buka halaman ini, lalu gunakan menu browser Anda: <strong>File → Print → Save as PDF</strong>.</p>
<hr>
<h2>Pohon Emas — Lembar ringkas lengkap</h2>
<p><strong>Slogan:</strong> <em>Dunia yang tumbuh bersamamu. Kunjungi, siram, amati. Tanpa level. Tanpa tekanan.</em></p>
<table>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Usia</strong></td>
<td>3–13 tahun (cakupan luas)</td>
</tr>
<tr>
<td><strong>Format</strong></td>
<td>Dunia 3D bersama yang episodik + &quot;momen&quot; singkat mingguan</td>
</tr>
<tr>
<td><strong>Platform</strong></td>
<td>Web (dan perangkat seluler nantinya); mudah diakses, tidak perlu instalasi</td>
</tr>
<tr>
<td><strong>Pemicu viral</strong></td>
<td>&quot;Kirim benih kepada temanmu.&quot; Pertumbuhan bersama, klip menenangkan yang dapat dibagikan.</td>
</tr>
</tbody>
</table>
<h3>Apa ini</h3>
<p>Dunia koleksi yang menenangkan dan berkembang mengikuti <strong>waktu di dunia nyata</strong>. Satu &quot;musim&quot; bersama (misalnya Pulau Musim Semi): sebuah pulau 3D tempat anak-anak dapat berjalan-jalan (seperti demo Kali yang dapat dimainkan). Tidak ada level atau skor konvensional. Progresnya berupa <strong>pohonmu menumbuhkan cabang baru</strong>, <strong>kamu telah melihat 12 momen</strong>, <strong>seseorang menyiram benihmu</strong>.</p>
<p>Dalam setiap kunjungan, seorang anak dapat: <strong>menyiram satu tanaman</strong>, <strong>meninggalkan satu harapan</strong> (teks atau emoji), <strong>menemukan satu karakter Cubcoats yang tersembunyi</strong>, atau <strong>menonton satu &quot;momen&quot; berdurasi 30 detik</strong> (misalnya Kali di bawah pohon emas). Momen baru dan bagian cerita singkat dirilis <strong>setiap minggu</strong> (episodik). Bahasa ambien opsional: &quot;Hari ini Kali berkata: [satu kalimat dalam bahasa Inggris dan Mandarin].&quot;</p>
<p>Pembelajaran dan perkembangan berlangsung secara <strong>tersirat</strong>: tema-tema (kebaikan, kesabaran, mencoba lagi) hadir dalam penulisan dan karya visual, bukan sebagai pelajaran. Pengalaman ini terasa seperti mainan atau ruang bersama, bukan sekolah.</p>
<h3>Alur permainan inti</h3>
<ol>
<li><strong>Kunjungi</strong> pulau (melalui browser atau aplikasi).</li>
<li><strong>Lakukan satu aktivitas ringan</strong> per kunjungan: menyiram, menyampaikan harapan, menemukan karakter, atau menonton sebuah momen.</li>
<li><strong>Lihat dunia berubah</strong> dalam hitungan hari/minggu (bunga baru, pose karakter baru, klip pendek baru).</li>
<li><strong>Bagikan</strong> benih kepada teman atau &quot;kunjungi pulau teman&quot; agar pertumbuhannya terasa sosial.</li>
</ol>
<h3>Cara konsep ini menggunakan alur kerja dan karakter dari artikel</h3>
<ul>
<li><strong>Dunia 3D yang dapat dimainkan:</strong> Alur kerja yang sama seperti demo Kali: T-pose → 3D Model Generator → rigging → Cinevva Engine. Pulau dan karakternya dapat dijelajahi dari sudut pandang orang ketiga, tanpa tekanan besar.</li>
<li><strong>Pohon emas:</strong> Diambil langsung dari artikel (bagian perubahan emosi Kali dari &quot;takut menjadi penuh harapan&quot; dan pohon emas ajaib). Pohon tersebut menjadi pusat emosional dan visual musim ini.</li>
<li><strong>&quot;Momen&quot; singkat:</strong> Diproduksi seperti video vertikal pendek dalam artikel: frame awal + frame akhir + prompt gerakan → Video Generator (Kling 3.0 Pro), 9:16, ~15 detik. Setiap rilis mingguan menghadirkan satu bagian cerita singkat.</li>
<li><strong>IP Cubcoats:</strong> Kali dan tujuh karakter lainnya, dunia pulau, serta gaya visual yang hangat dan membulat. Cocok untuk peluncuran ulang yang mengutamakan lisensi (2026) dengan produk digital episodik.</li>
</ul>
<h3>Mengapa konsep ini bisa menjadi viral</h3>
<ul>
<li><strong>Mudah diakses:</strong> Satu tautan, tanpa proses orientasi yang rumit. &quot;Kirim benih kepada temanmu&quot; mudah untuk dibagikan.</li>
<li><strong>Klip yang indah dan menenangkan:</strong> Momen-momen pendek dapat dibagikan secara mandiri (media sosial, &quot;tonton 15 detik ini&quot;). Mudah dijadikan meme secara positif.</li>
<li><strong>Episodik:</strong> &quot;Apa yang baru minggu ini?&quot; mendorong kunjungan kembali dan percakapan.</li>
<li><strong>Tersirat:</strong> Orang tua melihat pengalaman yang &quot;tenang, kreatif, tanpa iklan, tanpa stres&quot;; anak-anak mendapatkan rutinitas, kesabaran, dan kejutan menyenangkan tanpa merasa diajari secara eksplisit.</li>
</ul>
<h3>Kemungkinan sudut pandang untuk blog Cinevva</h3>
<p><em>&quot;Kami membawa Kali dari sketsa menjadi video, lalu menjadi karakter yang dapat Anda ajak menjelajah. Pohon Emas adalah langkah berikutnya: dunia yang tumbuh secara waktu nyata, tempat anak-anak berkunjung, menyiram, dan menonton momen-momen singkat—tanpa level, tanpa tekanan. Alur kerja yang sama. Format baru.&quot;</em></p>
<hr>
<h2>Pulau Kata Kali — Sekilas</h2>
<table>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Slogan</strong></td>
<td>Bantu Kali dan teman-temannya mengembangkan pulau. Pelajari bahasa Inggris dan Mandarin sambil bermain.</td>
</tr>
<tr>
<td><strong>Usia</strong></td>
<td>5–11 tahun</td>
</tr>
<tr>
<td><strong>Fokus</strong></td>
<td>Bahasa Inggris ↔ Mandarin untuk anak-anak; gamifikasi dan progres yang kuat.</td>
</tr>
</tbody>
</table>
<p><strong>Ide inti:</strong> Pulau Cubcoats dibagi menjadi beberapa zona karakter (hutan Kali, pantai milik karakter lain). Anak-anak membantu karakter dengan menyelesaikan tugas singkat yang mengharuskan mereka memahami dan menggunakan bahasa Inggris/Mandarin. Progres = &quot;Benih → Bibit → Pohon → Pohon Emas&quot; (buka zona berikutnya setelah pohon di zona tersebut tumbuh sepenuhnya). Misi &quot;lentera&quot; harian, kartu frasa sebagai barang koleksi, indikator &quot;suasana hati&quot; karakter, serta dasbor orang tua opsional. Momen cerita singkat (dengan gaya frame awal/akhir) terbuka setelah suatu zona selesai. <strong>Alur kerja:</strong> Alur kerja 3D + video yang sama untuk karakter dan bagian-bagian emosional.</p>
<hr>
<h2>Cubcoats: Kisah Pulau — Sekilas</h2>
<table>
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Slogan</strong></td>
<td>Buat episode Cubcoats versimu sendiri. Remix ceritanya. Bagikan versimu.</td>
</tr>
<tr>
<td><strong>Usia</strong></td>
<td>3–13 tahun (kelompok: 3–6, 7–10, 11–13)</td>
</tr>
<tr>
<td><strong>Fokus</strong></td>
<td>Pembuatan dan remix cerita; unsur edukatif terintegrasi, tetapi bukan daya tarik utama.</td>
</tr>
</tbody>
</table>
<p><strong>Ide inti:</strong> Narasi episodik tempat anak-anak memilih percabangan cerita (apa yang Kali katakan? ke mana dia pergi?). Aktivitas utamanya adalah <strong>membuat remix</strong>: pilih karakter, tempat, dan 2–3 bagian cerita → hasilkan &quot;episode&quot; singkat (naskah + visual sederhana, atau kelak video pendek yang dibuat dengan AI). Pembelajaran berlangsung secara tersirat (kosakata dan pola bahasa dalam dialog dan pilihan). Aspek sosial: bagikan episodemu, mainkan versi orang lain, beri penilaian &quot;baik hati / lucu / mengejutkan.&quot; <strong>Alur kerja:</strong> Tampilan karakter yang sama + alur kerja video dua frame untuk &quot;momen&quot; buatan pengguna; 3D untuk menjaga konsistensi karakter/dunia.</p>
<hr>
<p><em>Peralatan Cinevva yang disebutkan: Image Generator, Video Generator (Kling 3.0 Pro), 3D Model Generator, auto-rigging, Cinevva Engine. Mencerminkan alur kerja yang dijelaskan dalam &quot;Dari sketsa menjadi video dan 3D yang dapat dimainkan&quot; (2026-03-04).</em></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Apa yang sebenarnya diperlukan untuk membangun dunia terbuka di browser]]></title>
            <link>https://app.cinevva.com/id/blog/2026-03-14-open-world-browser-medium-article</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-03-14-open-world-browser-medium-article</guid>
            <pubDate>Sat, 14 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Uraian jurnalistik tentang seri rekayasa Cinevva dalam 12 bagian: 24 eksperimen spike, dari baseline medan sederhana hingga marching cubes berbasis GPU, streaming LOD, dan debugging sambungan Transvoxel.]]></description>
            <content:encoded><![CDATA[<h1>Apa yang sebenarnya diperlukan untuk membangun dunia terbuka di browser</h1>
<p><em>Oleh <a href="/id/about">Mariana Muntean</a>, CEO Cinevva</em></p>
<img src="/img/blog/open-world-browser-120fps.png" alt="Dunia terbuka yang berjalan di browser pada 120 FPS — medan, pepohonan, fisika, dan kapsul pemain, semuanya dirender dalam satu tab" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Tim Cinevva baru saja menerbitkan salah satu jurnal rekayasa paling transparan dalam sejarah terkini pengembangan gim: sebuah <a href="/id/blog/2026-02-25-open-world-browser-series-guide">seri 12 bagian</a> yang mendokumentasikan upaya kami membangun dunia terbuka multipemain yang berjalan sepenuhnya di browser. Tanpa unduhan. Tanpa toko aplikasi. Hanya sebuah URL.</p>
<p>Proyek ini mencakup 24 eksperimen teknis yang kami sebut &quot;spike&quot; -- prototipe singkat dan terfokus yang masing-masing dirancang untuk menjawab satu pertanyaan berisiko. Setiap spike dirilis dengan kode sumber aktif yang dapat Anda buka dan jalankan di browser saat ini juga. Seri ini ditulis oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan salah satu pendiri Cinevva, dan lebih terasa seperti jurnal lapangan dari garis depan kemampuan browser yang sebenarnya pada 2026 daripada materi pemasaran.</p>
<p>Hal yang membuat seri ini layak dibaca -- bahkan jika Anda tidak pernah berencana membangun sistem medan -- adalah metode yang mendasarinya. Ini merupakan studi kasus tentang cara mengurangi risiko proyek ambisius sebelum Anda berkomitmen pada sesuatu yang mahal.</p>
<h2>Memulai dari pertanyaan tersulit</h2>
<p>Sebagian besar proyek dunia terbuka gagal dalam urutan yang dapat diprediksi. Pertama, Anda mendapatkan konsep yang indah. Lalu, adegan yang menarik. Kemudian, Anda menyadari bahwa seluruh anggaran frame sudah habis bahkan sebelum gameplay tersedia.</p>
<p>Tim kami membalik urutannya. <a href="/id/blog/2026-02-25-open-world-browser-part-01-risk-first">Spike pertama</a> sengaja dibuat sederhana dan tidak menarik: mesh medan sepanjang 512 meter, 500 objek instans, noise ketinggian prosedural, bidang air, dan kabut. Tanpa bayangan, tanpa tahap pemolesan visual. Satu-satunya pertanyaan adalah apakah browser dapat mempertahankan frame rate yang stabil saat kamera bergerak melintasinya.</p>
<p>Ternyata bisa. Dan jawaban &quot;ya&quot; itu menetapkan sesuatu yang disebut Oleg sebagai &quot;kontrak baseline&quot; -- biaya referensi terukur untuk adegan minimal, yang menjadi pembanding bagi setiap fitur berikutnya untuk membuktikan kelayakannya. Jika efek baru tampak hebat tetapi melampaui anggaran frame, efek itu tidak dirilis. Setidaknya, belum.</p>
<p>Disiplin semacam itu terdengar jelas dan masuk akal. Dalam praktiknya, hal tersebut jarang ditemui di lingkungan pembuatan prototipe yang bergerak cepat, tempat semua orang bersemangat mengejar pencapaian visual berikutnya.</p>
<h2>Pertaruhan fisika</h2>
<p><a href="/id/blog/2026-02-25-open-world-browser-part-02-worker-physics">Eksperimen kedua</a> menangani perdebatan arsitektur yang memecah para pengembang gim browser: apakah fisika sebaiknya dijalankan di thread utama, yang lebih sederhana, atau di Web Worker, yang tidak dapat memblokir rendering?</p>
<p>Fisika berbasis worker lebih bersih di atas kertas. Dalam praktiknya, kekhawatiran utamanya adalah latensi. Setiap peristiwa input harus dua kali melintasi batas pesan: sekali untuk mencapai worker, dan sekali lagi untuk membawa hasilnya kembali. Jika perjalanan bolak-balik itu terlalu lambat, jeda antara menekan tombol dan melihat karakter bergerak akan terasa lamban.</p>
<p>Tim mengintegrasikan mesin fisika Rapier (dikompilasi dari Rust ke WebAssembly) dalam worker khusus, merangkai pipeline pesan, lalu melakukan pengukuran. Overhead-nya dapat diabaikan. Kontrol tetap terasa instan. Namun, kami berhati-hati untuk mencatat bahwa yang divalidasi adalah satu skenario tertentu, bukan aturan universal. Ketika tekanan GPU dan kompleksitas streaming berubah di kemudian hari, asumsi tersebut perlu diperiksa kembali.</p>
<h2>Spike membosankan yang menyelamatkan proyek</h2>
<p><a href="/id/blog/2026-02-25-open-world-browser-part-03-the-unflashy-spikes">Bagian ketiga</a> dari seri ini tidak memiliki tangkapan layar. Bagian tersebut membahas tiga eksperimen yang tampak tidak menarik, tetapi memiliki konsekuensi di tingkat produk.</p>
<p>Eksperimen pertama menguji apakah Cloudflare Durable Objects dapat menangani siaran posisi secara real-time pada tick rate setara gim -- tulang punggung sistem multipemain. Jika gagal, seluruh arsitektur jaringan akan memerlukan sharding sejak awal, alih-alih kepemilikan satu pulau oleh satu instance.</p>
<p>Eksperimen kedua memvalidasi profil kualitas seluler: bukan preset desktop yang sekadar diganti namanya, melainkan jalur rendering berbiaya rendah yang dirancang secara eksplisit dari baseline medan yang sama. Pertanyaannya adalah apakah dunia tersebut dapat tetap mudah dibaca dan responsif di bawah keterbatasan GPU seluler tanpa menulis ulang renderer.</p>
<p>Eksperimen ketiga mengevaluasi apakah skrip perilaku yang dihasilkan AI untuk alur kerja kreator cukup andal untuk digunakan dalam produksi.</p>
<p>Tak satu pun menghasilkan demo yang memukau. Namun, ketiganya menetapkan batasan tegas yang membentuk setiap keputusan arsitektur setelahnya. Oleg menulis bahwa &quot;spike yang tidak mencolok ini mengubah arsitektur lebih cepat daripada spike visual.&quot;</p>
<h2>Streaming: titik runtuhnya proyek-proyek yang indah</h2>
<img src="/img/blog/open-world-chunk-streaming.png" alt="Spike 6: Streaming chunk sedang berjalan — setiap area berwarna adalah chunk medan yang dimuat dan dikeluarkan secara dinamis saat kamera bergerak" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Anda dapat menyembunyikan banyak hal dalam satu frame diam. Namun, Anda tidak dapat menyembunyikan tersendat selama 40 milidetik ketika pemain berlari melintasi batas chunk.</p>
<p>Tim menguji <a href="/id/blog/2026-02-25-open-world-browser-part-04-streaming-before-fancy">streaming sebelum membangun medan tingkat lanjut</a>, dengan sengaja memisahkan berbagai aspek pengembangan. Spike 6 memvalidasi pemuatan chunk di sekitar pemain menggunakan konten sederhana. Baru setelah mendapatkan sinyal yang jelas itu, Spike 11 memperkenalkan streaming heightmap terkompresi dengan penyempurnaan progresif -- memuat medan terlebih dahulu pada resolusi 17 sampel, kemudian 33, lalu grid penuh 65 sampel.</p>
<p>Urutan tersebut ternyata lebih penting daripada yang kami duga. Seandainya kami langsung memulai dengan chunk ketinggian terkompresi, penyebab setiap gangguan akan menjadi ambigu. Apakah masalahnya terletak pada decoding, kemacetan saat mengunggah tekstur, atau pembaruan geometri? Menguji streaming sederhana terlebih dahulu menghilangkan satu kategori ketidakpastian secara keseluruhan.</p>
<p>Sebuah pelajaran praktis pun muncul: ukur kemacetan saat pengunggahan secara langsung, bukan melalui FPS rata-rata. Nilai rata-rata menyembunyikan lonjakan waktu frame, padahal lonjakan itulah yang benar-benar dirasakan pemain.</p>
<h2>Perebutan anggaran visual</h2>
<p>Tiga eksperimen terpisah membedah biaya rendering secara terisolasi, alih-alih menggabungkannya. Kepadatan dan animasi angin pada <a href="/id/blog/2026-02-25-open-world-browser-part-05-budgeting-the-pretty">vegetasi</a>. Material medan berlapis dengan pemetaan triplanar untuk permukaan tebing. Cascaded shadow maps di bawah beban medan yang realistis.</p>
<p>Spike vegetasi mengungkap bahwa mengelompokkan berbagai instance ke dalam lebih sedikit mesh jauh lebih penting daripada mengurangi jumlah poligon per helai. Spike material menemukan bahwa proyeksi triplanar pada permukaan vertikal sepadan dengan biaya GPU-nya, tetapi penambahan lapisan texture splat kelima tidak. Spike bayangan menentukan bahwa tiga cascade pada resolusi 1024 menghasilkan contact shadow yang memadai tanpa melampaui 2 milidetik waktu GPU.</p>
<p>Tim menerapkan aturan tegas: sebuah fitur hanya boleh dilanjutkan jika biayanya dapat dijelaskan dengan data waktu frame yang terukur. Batasan yang ditetapkan sejak awal itu membuat keputusan arsitektur selanjutnya seputar medan volumetrik dan clipmap menjadi jauh lebih jelas.</p>
<h2>Perubahan arah yang mengubah lintasan proyek</h2>
<p>Sebelum Spike 10, model mental kami adalah &quot;dunia yang lebih besar berarti lebih banyak geometri.&quot; Setelah <a href="/id/blog/2026-02-25-open-world-browser-part-06-clipmaps">Spike 10</a>, model itu berubah menjadi &quot;anggaran geometri konstan, dengan pembaruan cincin yang berpusat pada kamera.&quot;</p>
<p>Geometry clipmap -- cincin-cincin medan konsentris yang berpusat pada kamera, dengan setiap cincin semakin kasar -- membuat jumlah segitiga tetap relatif konstan, berapa pun jarak gambarnya. Trik praktisnya adalah geomorphing pada batas cincin: memadukan ketinggian vertex secara halus di shader sehingga perpindahan antara tingkat resolusi tidak terlihat saat bergerak.</p>
<p>Ada pelajaran halus dari metodologi pengujian. Clipmap tampak baik-baik saja dalam tangkapan layar. Artefaknya baru terlihat saat kamera terus bergerak melintasi batas cincin. Tim menghabiskan waktu melakukan lintasan berkecepatan konstan dan mengamati noise temporal. &quot;Tangkapan layar berbohong,&quot; tulis Oleg. &quot;Gerakan menunjukkan kenyataan.&quot;</p>
<h2>Menjelajah ke bawah tanah</h2>
<p>Heightmap tidak dapat merepresentasikan gua. Heightmap hanya menyimpan satu nilai elevasi untuk setiap titik pada grid. Begitu Anda membutuhkan terowongan, bagian batu yang menggantung, atau permukaan batu yang dipahat, Anda memerlukan medan volumetrik.</p>
<p><a href="/id/blog/2026-02-25-open-world-browser-part-07-marching-cubes">Spike 12</a> mengimplementasikan marching cubes di GPU menggunakan compute shader WebGPU, dengan mengekstraksi mesh segitiga dari signed distance field 3D. Empat chunk berukuran 64 kubik berjalan secara bersamaan, dengan pembaruan mesh per frame dari pengeditan SDF yang dianimasikan. Compute shader menangani semuanya -- mengevaluasi field, mengklasifikasikan sel, menghasilkan vertex -- tanpa readback CPU sama sekali.</p>
<p>Tantangannya bukan sekadar membuatnya bekerja. Tantangannya adalah membuatnya bekerja berdampingan dengan semua sistem lain. Integrasi dengan scene graph Three.js, pengelolaan siklus hidup buffer (buffer WebGPU tidak dapat diubah ukurannya), penanganan fence agar resource GPU yang masih diproses tidak dihancurkan -- seri ini mencurahkan <a href="/id/blog/2026-02-25-open-world-browser-part-08-webgpu-integration">dua</a> bagian penuh untuk hal yang kami sebut &quot;pengerasan bertahap&quot;, yaitu proses tidak glamor untuk menambahkan satu kemampuan pada satu waktu dan memastikan lapisan sebelumnya tetap berfungsi setelah setiap penambahan.</p>
<h2>Mimpi buruk sambungan</h2>
<p>Bagian paling menguras tenaga secara teknis dalam seri ini mencakup <a href="/id/blog/2026-02-25-open-world-browser-part-09-transvoxel-first-cut">Bagian 9 hingga 11</a>, yang membahas apa yang terjadi saat chunk medan dengan resolusi berbeda saling bertemu.</p>
<p>Ketika chunk beresolusi tinggi berdampingan dengan chunk beresolusi rendah, mesh yang dibuat secara independen tidak sejajar pada batasnya. Hasilnya adalah retakan yang terlihat, tepian yang berkedip, dan T-junction yang membuat cahaya bocor. Algoritma Transvoxel menyelesaikannya dengan sel transisi khusus yang menjembatani perbedaan resolusi -- tetapi mengimplementasikannya dengan benar untuk semua konfigurasi chunk, dengan urutan winding yang konsisten, pengelolaan buffer yang tepat, dan draw range yang akurat, menghabiskan enam eksperimen terpisah.</p>
<p>Kisah debugging tim yang paling berkesan: dua hari dihabiskan untuk memburu artefak sambungan yang kami kira berasal dari logika transisi. Penyebab sebenarnya adalah data usang. Compute shader GPU menulis N vertex ke dalam buffer, tetapi draw call masih dikonfigurasi untuk merender N+M vertex dari frame sebelumnya. Vertex tambahan tersebut berisi data sampah yang menghasilkan segitiga setipis silet dan berkedip-kedip. Perbaikannya hanya satu baris: batasi draw range ke jumlah vertex aktif dari atomic counter.</p>
<p>&quot;Bug rendering sering menyamar sebagai bug meshing,&quot; kata Oleg. &quot;Geometrinya ternyata sudah benar sejak awal.&quot;</p>
<h2>Dari kekacauan menuju tata kelola</h2>
<p>Setelah pergulatan dengan sambungan, tim mengganti perilaku chunk ad hoc dengan <a href="/id/blog/2026-02-25-open-world-browser-part-11-policy-modes">sistem kebijakan yang eksplisit</a>. Kini, sebuah fungsi pusat menentukan tingkat LOD setiap chunk, mode rendering-nya (heightmap atau marching cubes), serta sisi mana yang membutuhkan sel transisi. Cincin jarak menentukan LOD dasar. Batasan ketetanggaan memastikan tidak ada dua chunk bersebelahan yang berbeda lebih dari satu tingkat resolusi. Bitmap pengeditan mempertahankan chunk volumetrik dalam mode marching-cubes berapa pun jaraknya jika chunk tersebut berisi modifikasi dari kreator.</p>
<p>Overlay debug berkode warna -- hijau untuk chunk heightmap, biru untuk marching cubes, oranye untuk sisi transisi -- mengubah laporan seperti &quot;Saya melihat bug di suatu tempat dekat punggung bukit itu&quot; menjadi &quot;bug muncul di posisi (142, 12, -67) menghadap barat laut.&quot;</p>
<p>&quot;Kebijakan tidak mengurangi kompleksitas,&quot; tulis Oleg. &quot;Kebijakan menata kompleksitas.&quot;</p>
<h2>Hasil akhirnya</h2>
<p>Spike terakhir menggabungkan cincin clipmap, kabut langit per fragmen (mengambil sampel warna skybox sebenarnya ke arah setiap fragmen medan), dan perangkaian modul Three.js menjadi satu demonstrasi terpadu. Hasilnya adalah sistem medan yang menggabungkan pengeditan volumetrik jarak dekat, chunk heightmap jarak menengah, dan cincin clipmap jarak jauh di bawah lapisan kebijakan yang mengatur mode, LOD, dan transisi.</p>
<p>Seri ini ditutup dengan <a href="/id/blog/2026-02-25-open-world-browser-part-12-lessons">pelajaran</a> yang menurut Oleg akan ia terapkan kembali pada proyek apa pun di masa depan:</p>
<ul>
<li><strong>Mulailah dengan spike risiko sebelum mengerjakan fitur.</strong> Tuntaskan pertanyaan &quot;apakah ini bahkan bisa dilakukan?&quot; sebelum berinvestasi dalam pipeline konten.</li>
<li><strong>Bekukan baseline yang sudah terbukti baik sebelum melakukan lompatan integrasi.</strong> Satu hari yang dihabiskan untuk menetapkan checkpoint bersih akan menghemat beberapa hari untuk melacak sumber regresi di kemudian hari.</li>
<li><strong>Terapkan kebijakan dan observabilitas sebelum menjalani maraton optimasi.</strong> Kondisi yang diberi nama dan disertai aturan pemicu selalu lebih baik daripada bug misterius.</li>
<li><strong>Uji dalam gerakan, bukan melalui tangkapan layar.</strong> Perubahan mendadak, kedipan, dan gangguan streaming semuanya tersembunyi dalam frame diam.</li>
<li><strong>Ukur waktu frame per fitur, bukan FPS rata-rata.</strong> Nilai rata-rata menyembunyikan lonjakan yang benar-benar dirasakan pengguna.</li>
<li><strong>Publikasikan bagian-bagian yang berantakan.</strong> Jalan buntu, perburuan bug semu, dua hari menyalahkan sistem yang keliru. Bagian-bagian itulah yang benar-benar dapat dipelajari orang lain.</li>
</ul>
<h2>Mengapa ini penting di luar Cinevva</h2>
<p>Seri ini penting karena tiga alasan yang melampaui pipeline medan milik satu perusahaan.</p>
<p>Pertama, seri ini menunjukkan bahwa compute shader WebGPU, fisika WebAssembly, dan Durable Objects yang diterapkan di edge telah melewati sebuah ambang batas. Dunia terbuka multipemain dengan medan volumetrik, pengeditan real-time, dan streaming LOD kini layak secara arsitektural untuk dijalankan dalam satu tab browser pada 2026. Hal itu belum berlaku dua tahun lalu.</p>
<p>Kedua, metodologi spike -- eksperimen kecil dan terfokus yang masing-masing menjawab satu pertanyaan berisiko dengan hasil langsung serta terukur -- menawarkan pola bagi tim mana pun yang mencoba sesuatu yang mungkin tidak berhasil. Disiplin untuk mengukur sebelum berkomitmen, menetapkan baseline sebelum melakukan integrasi, dan mengidentifikasi kasus tepi sebelum mengoptimalkan dapat diterapkan jauh melampaui sistem medan.</p>
<p>Ketiga, transparansi radikal adalah inti utamanya. Menerbitkan kode sumber untuk seluruh 24 eksperimen, termasuk jalan buntu dan penyimpangan debugging selama dua hari, menjadikan ini lebih dari sekadar blog teknis. Ini adalah buku catatan rekayasa publik yang memperlakukan pembaca sebagai rekan kerja, bukan pelanggan.
Seri lengkapnya tersedia di <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>, dengan setiap eksperimen teknis yang dapat dijalankan langsung di browser.</p>
<hr>
<p><em>Artikel ini awalnya diterbitkan di <a href="https://vio-202020.medium.com/de-risking-an-ambitious-project-before-committing-to-anything-big-like-an-online-open-world-c94a7c05ee06">Medium</a>.</em></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[2026-03-04-sketch-to-animated-3d-character-factcheck-note]]></title>
            <link>https://app.cinevva.com/id/blog/2026-03-04-sketch-to-animated-3d-character-factcheck-note</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-03-04-sketch-to-animated-3d-character-factcheck-note</guid>
            <pubDate>Wed, 04 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[]]></description>
            <content:encoded><![CDATA[<h1>Catatan pemeriksaan fakta: &quot;Dari sketsa menjadi video dan 3D yang dapat dimainkan&quot;</h1>
<p><strong>Untuk:</strong> Oleg Sidorkin<br>
<strong>Perihal:</strong> <a href="https://app.cinevva.com/blog/2026-03-04-sketch-to-animated-3d-character">app.cinevva.com/blog/2026-03-04-sketch-to-animated-3d-character</a><br>
<strong>Diperiksa berdasarkan:</strong> repo cinevva-site (situs pemasaran + worker)</p>
<hr>
<h2>Terverifikasi ✓</h2>
<ul>
<li><strong>Nama alat</strong> (Image Generator, Video Generator, 3D Model Generator) dan <strong>tautan</strong> <code>/id/tools/hunyuan3d</code> sesuai dengan basis kode.</li>
<li><strong>Penulis</strong> (Oleg Sidorkin, CTO) sudah benar.</li>
<li><strong>Alur kerja video:</strong> Interpolasi frame awal + akhir, rasio 9:16, durasi 3–15 detik, dan mode storyboard semuanya didukung.</li>
<li><strong>Pipeline 3D:</strong> Hunyuan3D dan &quot;3D Model Generator&quot; sudah benar; auto-rigging (Tripo) dan &quot;unggah GLB → model ber-rig + pustaka animasi&quot; sesuai dengan implementasinya.</li>
<li><strong>Cinevva Engine</strong> dan &quot;Mencerminkan kondisi awal 2026&quot; sudah akurat.</li>
</ul>
<hr>
<h2>Perlu dikoreksi</h2>
<p><strong>&quot;Seedance 1.5 Pro&quot;</strong> — Di repo ini, video diimplementasikan dengan <strong>Kling 3.0 Pro</strong> (<a href="http://fal.ai">fal.ai</a>), bukan Seedance 1.5 Pro:</p>
<ul>
<li><code>worker/src/genai/fal-video.ts</code> menggunakan <code>fal-ai/kling-video/v3/pro/...</code></li>
<li><code>worker/src/index.ts</code> mencatat biaya sebagai <code>model: 'kling-3.0-pro'</code></li>
<li><code>tools/video.md</code> menyatakan: &quot;Buat video AI pendek dari teks atau gambar menggunakan <strong>Kling 3.0 Pro</strong>&quot;</li>
</ul>
<p>Nama API/produknya adalah &quot;seedance&quot; (misalnya <code>/genai/seedance/generate</code>), tetapi model yang mendasarinya adalah Kling 3.0 Pro. Seedance 1.5 Pro merupakan model yang berbeda (ByteDance). Sumber publik sering membatasi Seedance 1.5 Pro hingga sekitar 10 detik; durasi 15 detik didukung untuk Kling di sini.</p>
<p><strong>Rekomendasi:</strong> Dalam artikel, sebutkan model videonya sebagai <strong>&quot;Kling 3.0 Pro&quot;</strong> (atau misalnya &quot;Video Generator (Kling 3.0 Pro)&quot;) agar sesuai dengan situs pemasaran dan dokumentasi. Jika backend aplikasi benar-benar menggunakan Seedance 1.5 Pro, selaraskan teks aplikasi dan <code>tools/video.md</code> agar keduanya menjelaskan model yang sama.</p>
<hr>
<h2>Tidak dapat diverifikasi di repo</h2>
<p>Cubcoats, Kali the Kitty, Mimi Chao, dan klaim bisnis terkait berasal dari sumber eksternal; tidak diperiksa.</p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Dari sketsa ke video dan 3D yang dapat dimainkan: karakter, bingkai cerita, dan rig]]></title>
            <link>https://app.cinevva.com/id/blog/2026-03-04-sketch-to-animated-3d-character</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-03-04-sketch-to-animated-3d-character</guid>
            <pubDate>Wed, 04 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Cara kami menggunakan Generator Gambar, Generator Video, dan Generator Model 3D Cinevva untuk mengubah sketsa kasar karakter menjadi video pendek vertikal buatan AI dan model 3D ber-rig yang dapat Anda gerakkan di browser.]]></description>
            <content:encoded><![CDATA[<h1>Dari sketsa ke video dan 3D yang dapat dimainkan</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO Cinevva</em></p>
<p>Dahulu, mengubah karakter dari sketsa datar menjadi game 3D yang dapat dimainkan memerlukan seniman konsep, pemodel 3D, pembuat rig, animator, dan seseorang untuk merangkai semuanya dalam sebuah engine. Kami ingin melihat seberapa banyak tahapan produksi tersebut yang dapat ditangani sendiri oleh <a href="/id/tools/">alat kreatif Cinevva</a>. Inilah yang kami temukan.</p>
<p>Karakternya adalah <strong>Kali the Kitty</strong> dari <a href="https://thecubcoats.com">Cubcoats</a>, merek anak-anak yang menjual lebih dari satu juta hoodie berbentuk boneka melalui Nordstrom, Amazon, dan Disney Store. Cubcoats memiliki delapan karakter orisinal dengan kepribadian yang jelas, dunia pulau fiktif, dan 14 paten. Mereka akan diluncurkan kembali pada 2026 sebagai platform yang mengutamakan lisensi, dan kami ingin menunjukkan seperti apa kekayaan intelektual tersebut saat berkembang melampaui produk fisik: sebuah video pendek vertikal dan karakter 3D ber-rig yang dapat Anda gerakkan di browser. Semua yang ditampilkan di bawah ini adalah hasil nyata dari eksplorasi tersebut.</p>
<p>Seret penampil 3D untuk memutar sudut pandang. Gulir strip film untuk melihat bagaimana video pendek vertikal bergerak dari bingkai pertama hingga terakhir.</p>
<h2>Dari ilustrasi buku datar menjadi karakter yang dapat Anda putar</h2>
<p>Cubcoats sudah memiliki ilustrasi 2D yang indah. Arahan seni Mimi Chao memberi setiap karakter tampilan gambar tangan yang hangat dan membulat, sangat cocok untuk hoodie dan buku cerita. Namun, ilustrasi datar tidak dapat langsung digunakan dalam alur produksi 3D. Kami membutuhkan karakter beresolusi tinggi yang dapat menjadi referensi andal untuk pembuatan video, mesh, dan rigging, semuanya dengan wajah yang sama.</p>
<p>Kami memulai dengan memasukkan ilustrasi buku asli ke <a href="/id/tools/flux">Generator Gambar</a> kami dan memintanya menghasilkan versi render 3D dari karakter yang sama.</p>
<figure class="pipeline-media pipeline-media--single">
<img src="/blog/sketch-to-3d-pipeline/kali-flat-book-art.png" alt="Ilustrasi datar asli Kali the Kitty dari Cubcoats" loading="lazy">
<figcaption><strong>Titik awal.</strong> Ilustrasi buku 2D asli Kali. Hangat, ekspresif, dan sepenuhnya datar.</figcaption>
</figure>
<p>Proporsinya tetap terjaga, kepribadiannya terasa, dan tampilan kartun 3D yang lembut memberi semua alat pada tahap berikutnya acuan konsisten yang dapat digunakan bersama. Dari sana, kami mengiterasi pose dan pembingkaian hingga memperoleh referensi utama yang terkunci.</p>
<div class="pipeline-media pipeline-media--two">
<figure>
<img src="/blog/sketch-to-3d-pipeline/kali-3d-chatgpt.png" alt="Referensi karakter bergaya 3D yang telah dikunci untuk Kali" loading="lazy">
<figcaption><strong>Referensi utama yang dikunci.</strong> Tampilan kartun 3D seluruh tubuh yang digunakan untuk video dan sebagai acuan visual mesh.</figcaption>
</figure>
<figure>
<img src="/blog/sketch-to-3d-pipeline/kali-3d-tpose.png" alt="Referensi pose-T untuk pembuatan dan rigging 3D" loading="lazy">
<figcaption><strong>Lembar pose-T.</strong> Karakter yang sama dengan kedua lengan direntangkan. Ini digunakan sebagai masukan untuk [Generator Model 3D](/id/tools/hunyuan3d) dan [pembuat rig otomatis](/id/tools/rigger).</figcaption>
</figure>
</div>
<p>Pose-T penting karena proses rigging mengharuskan lengan berada jauh dari torso. Jika dilewati, pembuat rig otomatis akan menyatukan lengan dengan tubuh lalu gagal melanjutkan. Kami membuat pose-T berdasarkan tampilan karakter terkunci yang sama agar siluet dan proporsinya tetap konsisten di setiap tahap.</p>
<h2>Tulis ceritanya sebelum membuat apa pun</h2>
<p>Sebelum menggunakan alat video, kami menulis rangkaian adegan dalam bahasa sederhana. Sifat kepribadian Kali di dunia Cubcoats adalah &quot;Positif.&quot; Dialah yang membuat semua orang merasa diterima dan tetap optimistis ketika keadaan menjadi sulit. Jadi, kami membangun alur berdurasi sepuluh detik berdasarkan sifat tersebut:</p>
<blockquote>
<p>Kali berjalan memasuki hutan gelap berkabut pada malam hari sambil membawa lentera kecil yang bercahaya. Dia ketakutan, duduk sendirian, dan hampir menyerah. Kemudian dia menemukan pohon emas ajaib yang menyala di belakangnya. Rasa takjub, kegembiraan, dan partikel keemasan berjatuhan. Dari rasa takut menjadi harapan dalam satu tarikan napas.</p>
</blockquote>
<p>Itulah seluruh alurnya. Ceritanya tidak perlu rumit. Cerita tersebut harus memuat satu perubahan emosi dalam satu adegan kontinu agar bingkai awal dan bingkai akhir benar-benar dapat terhubung.</p>
<h2>Dua bingkai yang mengawali dan mengakhiri semuanya</h2>
<p>Kami membuat dua gambar diam utama berdasarkan alur tersebut menggunakan <a href="/id/tools/flux">Generator Gambar</a> kami. Rasio aspek potret digunakan agar sesuai dengan video pendek vertikal. Prompt-nya menggambarkan karakter yang sama persis pada dua momen berbeda.</p>
<p><strong>Prompt bingkai awal:</strong></p>
<blockquote>
<p>Render animasi 3D bergaya Pixar dari Kali, karakter kucing kecil berwarna merah muda dengan mata gelap besar dan bulat, telinga merah muda yang runcing, perut merah muda muda, dan wajah bulat yang ceria. Dia berdiri di tepi hutan gelap berkabut pada malam hari sambil memegang lentera kecil yang bercahaya dengan kedua telapak kakinya. Telinganya sedikit merunduk dan ekspresinya gugup tetapi penuh tekad. Pencahayaan sinematik dengan sinar bulan biru sejuk dari atas dan cahaya jingga hangat dari lentera. Kabut tebal di antara batang-batang pohon gelap pada latar belakang. Sudut kamera: medium shot, sedikit rendah dan mengarah ke atas kepadanya. Tanpa teks, tanpa watermark.</p>
</blockquote>
<p><strong>Prompt bingkai akhir:</strong></p>
<blockquote>
<p>Render animasi 3D bergaya Pixar dari Kali, karakter kucing kecil berwarna merah muda dengan mata gelap besar dan bulat, telinga merah muda yang runcing, serta perut merah muda muda. Dia berdiri di depan pohon ajaib raksasa yang dipenuhi bunga emas bercahaya, merentangkan kedua lengan lebar-lebar, dan tersenyum lebar dengan penuh kegembiraan. Kelopak-kelopak emas melayang di udara di sekelilingnya. Pohon tersebut memancarkan cahaya keemasan hangat yang menerangi seluruh area terbuka di hutan. Langit malam berbintang terlihat di atas. Sudut kamera: wide shot dari posisi sedikit rendah, komposisi pengungkapan yang epik. Tanpa teks, tanpa watermark.</p>
</blockquote>
<div class="pipeline-media pipeline-media--two">
<figure>
<img src="/blog/sketch-to-3d-pipeline/kali-start-frame.png" alt="Bingkai awal untuk video AI vertikal" loading="lazy">
<figcaption><strong>Bingkai awal.</strong> Kali yang gugup di tepi hutan bersama lenteranya.</figcaption>
</figure>
<figure>
<img src="/blog/sketch-to-3d-pipeline/kali-end-frame.png" alt="Bingkai akhir untuk video AI vertikal" loading="lazy">
<figcaption><strong>Bingkai akhir.</strong> Kali yang gembira di depan pohon emas.</figcaption>
</figure>
</div>
<p>Seedance melakukan interpolasi di antara kedua bingkai pembatas ini. Deskripsi karakter tetap identik di kedua prompt agar model memahami bahwa itu adalah karakter yang sama. Hanya adegan, emosi, dan kameranya yang berubah.</p>
<h2>Hasil videonya lebih baik dari yang diperkirakan</h2>
<p>Kami memuat kedua bingkai ke <a href="/id/tools/video">Generator Video</a> Cinevva, memilih Seedance 1.5 Pro, menetapkan rasio aspek 9:16 dan durasi 15 detik, mengetik alurnya ke dalam prompt gerakan, lalu menekan Buat.</p>
<figure class="pipeline-media pipeline-media--single">
<img src="/blog/sketch-to-3d-pipeline/video-generator-setup.png" alt="Generator Video Cinevva dengan bingkai awal dan akhir yang telah dimuat" loading="lazy">
<figcaption><strong>Pengaturan sebenarnya.</strong> Bingkai awal, bingkai akhir, prompt gerakan, format vertikal 9:16, durasi 15 detik, dan audio aktif.</figcaption>
</figure>
<p>Klip tersebut melakukan interpolasi di antara kedua bingkai pembatas. Audio asli dibuat dalam proses yang sama. Berikut adalah bingkai-bingkai yang diambil dari sepanjang linimasa.</p>
<div class="pipeline-filmstrip" aria-label="Bingkai dari video vertikal yang dibuat">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_01.jpg" alt="Bingkai video 1" loading="lazy">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_02.jpg" alt="Bingkai video 2" loading="lazy">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_03.jpg" alt="Bingkai video 3" loading="lazy">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_04.jpg" alt="Bingkai video 4" loading="lazy">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_05.jpg" alt="Bingkai video 5" loading="lazy">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_06.jpg" alt="Bingkai video 6" loading="lazy">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_07.jpg" alt="Bingkai video 7" loading="lazy">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_08.jpg" alt="Bingkai video 8" loading="lazy">
<img src="/blog/sketch-to-3d-pipeline/seedance-frames/frame_09.jpg" alt="Bingkai video 9" loading="lazy">
</div>
<p class="pipeline-caption">Dari kiri ke kanan: perkembangan sepanjang video pendek vertikal yang dibuat.</p>
<p>Mode bingkai awal plus bingkai akhir merupakan pilihan tepat ketika kami ingin mendapatkan pose penutup yang persis. Untuk alur emosi yang lebih panjang, satu referensi plus prompt bekerja dengan baik menggunakan mode storyboard Kling 3.0 Pro dari <a href="/id/tools/video">Generator Video</a>. Pengaturan berbeda untuk kebutuhan berbeda.</p>
<h2>Karakter yang sama, kini dalam 3D</h2>
<p>Di sinilah prosesnya menjadi menarik. Gambar diam pose-T yang berasal dari keluarga visual yang sama dengan referensi video dimasukkan ke <a href="/id/tools/hunyuan3d">Generator Model 3D</a> kami untuk pembuatan 3D dari gambar. Anda tidak perlu mencocokkan mesh game dengan video piksel demi piksel. Yang perlu dicocokkan adalah ingatan pemain. Karakter dalam game harus terasa memiliki kepribadian yang sama seperti dalam video. Dan karena sejak awal kami mengunci satu identitas visual, hasilnya memang terasa sama.</p>
<figure class="pipeline-media pipeline-media--single">
<img src="/blog/sketch-to-3d-pipeline/kali-preview.png" alt="Pratinjau hasil render mesh Hunyuan3D" loading="lazy">
<figcaption>Pratinjau hasil render mesh yang dibuat. Tekstur dan proporsi sebelum rigging.</figcaption>
</figure>
<p><a href="/id/tools/hunyuan3d">Generator Model 3D</a> menghasilkan GLB bertekstur. Belum siap digunakan dalam game, tetapi jelas terlihat sebagai Kali. Siluetnya cocok. Materialnya mendekati referensi. Cukup baik untuk melanjutkan proses.</p>
<h2>Seret model-model ini untuk melihatnya dari berbagai sudut</h2>
<p>Hasil mentah dari <a href="/id/tools/hunyuan3d">Generator Model 3D</a>. Belum memiliki rig, hanya mesh bertekstur. Di sebelahnya terdapat karakter yang sama setelah proses rigging otomatis, lengkap dengan animasi berjalan yang telah dipanggang.</p>
<ClientOnly>
  <SketchPipelineModels />
</ClientOnly>
<h2>Rigging dan animasi</h2>
<p><a href="/id/tools/hunyuan3d">Generator Model 3D</a> memberi Anda sebuah mesh. Agar mesh tersebut dapat bergerak, diperlukan kerangka dan animasi. Platform kami menangani rigging secara otomatis: unggah GLB, lalu dapatkan kembali model ber-rig dengan pustaka animasi lengkap. Siklus berjalan, animasi bernapas saat diam, lompatan, dan semua yang dibutuhkan karakter game.</p>
<p>Animasi berjalan bawaan terlihat hampir tepat, tetapi masih belum sempurna. Lengan Kali berada terlalu dekat dengan tubuhnya dan kepalanya miring pada sudut yang sedikit keliru. Keduanya masuk akal untuk humanoid generik, tetapi terasa tidak cocok untuk kucing kartun yang bulat. Jadi, kami menambahkan koreksi tulang saat runtime dalam kode game: offset bahu yang mendorong lengan ke luar dan koreksi rotasi kepala yang meluruskan kemiringannya. Penyesuaian kecil dengan dampak besar. Tanpa koreksi tersebut, dia terlihat kaku dan robotik. Setelah dikoreksi, dia kembali terlihat seperti Kali.</p>
<h2>Memainkan karakter di browser</h2>
<p>Kami memasukkan model ber-rig tersebut ke <a href="/id/engine">Cinevva Engine</a>. Kamera orang ketiga, gerakan WASD, objek koleksi yang tersebar, serta kamera orbit saat diam. Menyempurnakan blending animasi membutuhkan beberapa iterasi: crossfade antara diam dan berjalan, menormalisasi tinggi, memperbaiki sumbu arah depan, dan menyesuaikan offset tulang. Kamera orang ketiga di belakang karakter menyempurnakan perjalanan dari sketsa menjadi sesuatu yang benar-benar dapat Anda gerakkan.</p>
<p>Cobalah sendiri. Gunakan WASD untuk bergerak.</p>
<div class="pipeline-game-embed">
<iframe src="https://api.cinevva.com/games/game-mmbijtzp-d63d/" allow="fullscreen" loading="lazy"></iframe>
</div>
<h2>Saran saya bagi siapa pun yang ingin melakukan ini besok</h2>
<p>Kunci satu tampilan karakter sebelum menggunakan alat generatif apa pun. Setiap menit yang Anda habiskan untuk menyempurnakan referensi tersebut akan menghemat satu jam dalam mengejar konsistensi pada tahap berikutnya.</p>
<p>Tulis alur singkat terlebih dahulu. Kemudian buat bingkai awal dan akhir menggunakan <a href="/id/tools/flux">Generator Gambar</a>. Pastikan ukuran gambar referensi tetap berada dalam batas API. Gunakan pose-T dari sistem desain yang sama saat memasukkannya ke <a href="/id/tools/hunyuan3d">Generator Model 3D</a>.</p>
<p>Masukkan kedua bingkai ke <a href="/id/tools/video">Generator Video</a> dan biarkan alat tersebut melakukan interpolasi. Untuk mesh game, buat rig model melalui platform dan sesuaikan offset tulang saat runtime jika animasi bawaan tidak benar-benar cocok dengan proporsi karakter Anda.</p>
<p>Dua tahun lalu, alur produksi ini belum ada. Anda akan membutuhkan tim dan anggaran. Sekarang Anda hanya membutuhkan sebuah sketsa dan <a href="/id/tools/">alat kreatif</a> Cinevva. Menurut saya, ini merupakan perubahan penting dalam memperluas siapa saja yang dapat menghidupkan sebuah karakter.</p>
<hr>
<p><em>Alat Cinevva yang digunakan: <a href="/id/tools/flux">Generator Gambar</a>, <a href="/id/tools/video">Generator Video</a>, <a href="/id/tools/hunyuan3d">Generator Model 3D</a>, rigging otomatis, dan <a href="/id/engine">Cinevva Engine</a>. Berdasarkan kondisi awal 2026.</em></p>
<style>
.pipeline-media { margin: 1.25rem 0; }
.pipeline-media figure { margin: 0; }
.pipeline-media img {
  width: 100%;
  height: auto;
  border-radius: 10px;
  border: 1px solid rgba(255,255,255,0.08);
  display: block;
}
.pipeline-media figcaption {
  margin-top: 0.5rem;
  font-size: 0.9rem;
  color: var(--vp-c-text-2);
  line-height: 1.45;
}
.pipeline-media--two {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
}
@media (min-width: 768px) {
  .pipeline-media--two {
    grid-template-columns: 1fr 1fr;
    gap: 1rem;
  }
}
.pipeline-media--single { margin: 1.25rem 0; }
.pipeline-filmstrip {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  padding: 12px 4px;
  margin: 1rem 0;
  border-radius: 10px;
  background: var(--vp-c-bg-soft);
  border: 1px solid rgba(255,255,255,0.06);
  -webkit-overflow-scrolling: touch;
}
.pipeline-filmstrip img {
  flex: 0 0 auto;
  height: 180px;
  width: auto;
  border-radius: 6px;
  object-fit: cover;
}
@media (min-width: 900px) {
  .pipeline-filmstrip img { height: 220px; }
}
.pipeline-caption {
  font-size: 0.85rem;
  color: var(--vp-c-text-2);
  margin: 0.35rem 0 1rem;
}
.pipeline-game-embed {
  position: relative;
  width: 100%;
  aspect-ratio: 16/9;
  margin: 1.25rem 0;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid rgba(255,255,255,0.08);
}
.pipeline-game-embed iframe {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  border: none;
}
</style>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 1: Kami memulainya dengan mencoba merusaknya]]></title>
            <link>https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-01-risk-first</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-01-risk-first</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Sebelum membangun gua atau shader canggih, kami perlu menjawab satu pertanyaan pelik: bisakah ini berjalan di browser?]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 1: Kami memulainya dengan mencoba merusaknya</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Salah Satu Pendiri Cinevva</em></p>
<p>Baru di sini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan memuat tautan ke semua bagian.</p>
<p>Kami sedang membangun dunia terbuka multipemain yang sepenuhnya berjalan di browser. Tanpa instalasi, tanpa toko aplikasi, cukup sebuah URL. Risiko terbesar sejak awal sudah jelas: mampukah browser merender dunia 3D persisten pada frame rate yang nyaman dimainkan sekaligus menyisakan ruang untuk gameplay, fisika, dan jaringan?</p>
<p>Sebagian besar proyek dunia terbuka gagal dalam urutan yang mudah diprediksi. Pertama, Anda mendapatkan konsep yang bagus. Lalu, Anda mendapatkan adegan yang indah. Kemudian, Anda menyadari bahwa anggaran frame sudah habis bahkan sebelum gameplay tersedia.</p>
<p>Kami ingin menjawab persoalan anggaran rendering sebelum berinvestasi pada hal lain. Jadi, Spike 1 melewatkan trailer yang memukau dan langsung berfokus pada pengukuran.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/01-terrain/" title="Spike 1: Medan dan Instancing" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/01-terrain/" target="_blank">Buka Spike 1 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=01-terrain">Lihat kode sumber</a></p>
<p>Rancangannya sengaja dibuat sederhana. Mesh medan berukuran 512 meter, ketinggian prosedural dari noise sinus berlapis dengan penurunan ketinggian menuju tepian pulau, bidang air, kabut atmosferis, dan 500 objek yang dirender menggunakan instancing. Kami menggunakan WebGL biasa dengan Three.js, tone mapping ACES, dan tanpa bayangan.</p>
<p>Kami tidak peduli seperti apa tampilannya. Yang kami pedulikan adalah apakah adegan tersebut tetap stabil saat kamera digerakkan melaluinya.</p>
<p>Ada dua temuan dari spike ini yang membentuk keseluruhan proyek.</p>
<p>Pertama, kami memastikan bahwa desktop memberikan ruang performa yang nyata jika tahap pertama tetap dibangun secara disiplin. Hal ini memberi kami keyakinan untuk mencoba arsitektur medan yang lebih sulit di kemudian hari.</p>
<p>Kedua, kami membuat kontrak tolok ukur dasar. Setiap spike berikutnya harus menjelaskan biayanya relatif terhadap adegan ini. Jika sebuah fitur baru terlihat bagus tetapi terlalu mahal, fitur tersebut tidak akan dilanjutkan.</p>
<p>Disiplin terhadap tolok ukur dasar ini menjadi sangat penting ketika kami kemudian menghadapi artefak sambungan, transisi LOD campuran, dan pembuatan mesh berbasis compute. Tanpa acuan yang stabil, setiap bug tampak lebih besar daripada kenyataannya.</p>
<p>Pada bagian 2, kami beralih dari rendering ke responsivitas input. Fisika di worker terdengar hebat dalam dokumen arsitektur. Namun, itu hanya berguna jika karakter masih terasa langsung merespons saat Anda menekan tombol.</p>
<h2>Teknologi yang dibahas dalam bab ini</h2>
<p><strong>Medan heightmap.</strong> Grid 2D dengan setiap sel menyimpan satu nilai elevasi. GPU menggeser mesh datar di vertex shader untuk membentuk permukaan medan. Heightmap berukuran ringkas (chunk 65x65 berukuran ~8 KB pada 16-bit), ramah GPU, dan cepat dirender. Keterbatasannya adalah heightmap tidak dapat merepresentasikan gua, ceruk menggantung, atau permukaan apa pun yang melipat kembali ke atas dirinya sendiri. Untuk memahami batasan heightmap dan teknologi penggantinya, lihat <a href="/id/guides/landscape-generation-browser#why-heightmaps-arent-enough">panduan pembuatan lanskap</a> kami.</p>
<p><strong>Three.js.</strong> Library rendering yang kami gunakan di seluruh proyek ini. Three.js mengabstraksikan WebGL 2 (dan kemudian WebGPU) menjadi scene graph dengan kamera, cahaya, material, dan objek geometri. Library ini menyediakan <code>InstancedMesh</code> untuk merender banyak salinan geometri yang sama dalam satu draw call, frustum culling, material PBR, dan pascapemrosesan. Lihat <a href="https://github.com/mrdoob/three.js">Three.js di GitHub</a>. Untuk memahami peran Three.js dalam stack dunia terbuka berbasis browser, lihat <a href="/id/guides/browser-3d-open-world-tech#three-js">panduan teknologi 3D browser</a> kami.</p>
<p><strong>InstancedMesh.</strong> Fitur Three.js yang merender N salinan geometri yang sama dengan satu draw call, masing-masing pada posisi/rotasi/skala yang berbeda. Transformasi per instance disimpan dalam buffer atribut matriks. Dengan cara inilah kami merender 500 objek dalam Spike 1 tanpa 500 draw call terpisah. Untuk vegetasi dalam skala besar, instanced culling berbasis GPU membawa pendekatan ini lebih jauh. Lihat <a href="/id/guides/landscape-generation-browser#gpu-driven-vegetation-culling">panduan lanskap kami tentang culling vegetasi berbasis GPU</a>.</p>
<p><strong>Anggaran frame.</strong> Pada 60 fps, setiap frame memiliki waktu $\frac{1000\ \text{ms}}{60} \approx 16.7$ ms untuk semuanya: logika JavaScript, fisika, rendering, dan compositing. Spike untuk &quot;pemeriksaan anggaran&quot; mengukur seberapa banyak waktu yang digunakan oleh adegan dasar, sehingga ruang yang tersisa untuk semua hal yang ditambahkan kemudian adalah $t_\text{features} = 16.7 - t_\text{baseline}$. Jika adegan dasar sudah menghabiskan 12 ms, hanya tersisa ~4.7 ms untuk gabungan gameplay, fisika, dan jaringan. Pendekatan ini berasal dari pengembangan dunia terbuka AAA, tempat <a href="/id/guides/browser-3d-open-world-tech#what-we-can-learn-from-skyrim-and-the-witcher">GTA V, Skyrim, dan Elden Ring</a> sama-sama menggunakan LOD dan streaming secara agresif agar tetap berada dalam anggaran frame yang tetap.</p>
<hr>
<p>Bagian 1 dari 12.<br>
Selanjutnya: <a href="/id/blog/2026-02-25-open-world-browser-part-02-worker-physics">Bagian 2 - Fisika worker dan kekhawatiran akan lag input</a><br>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 2: Fisika di Worker dan kekhawatiran akan latensi input]]></title>
            <link>https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-02-worker-physics</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-02-worker-physics</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Kami memindahkan Rapier ke Web Worker dan mengukur hal yang pertama kali dikhawatirkan semua orang: apakah gerakan terasa terlambat?]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 2: Fisika di Worker dan kekhawatiran akan latensi input</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru di sini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menautkan semua bagiannya.</p>
<p>Jika Anda cukup lama mengembangkan game multipemain di browser, pada akhirnya Anda akan menemui perdebatan ini.</p>
<p>&quot;Fisika di worker menghasilkan arsitektur yang rapi. Fisika di thread utama terasa lebih aman.&quot;</p>
<p>Keduanya bisa benar. Yang penting adalah respons kontrol dan latensi saat menerima input nyata.</p>
<p>Spike 2 dibuat untuk menjawabnya dengan pengukuran, bukan opini.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/02-rapier-worker/" title="Spike 2 Rapier Worker" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/02-rapier-worker/" target="_blank">Buka Spike 2 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=02-rapier-worker">Lihat kode sumber</a></p>
<p>Kami menggunakan kembali medan dari Spike 1 dan mengintegrasikan Rapier ke dalam module worker khusus. Status input dikirim ke worker di setiap frame, simulasi dijalankan di sana, dan posisi otoritatif dikirim kembali ke renderer.</p>
<p>Metrik utamanya adalah latensi dari input hingga gerakan terlihat serta waktu langkah fisika. Kami juga mengamati jitter selama gerakan normal, lonjakan saat berlari cepat, dan ritme lompatan.</p>
<p>Hasilnya lebih baik dari perkiraan. Dengan bentuk dan frekuensi pesan yang kami gunakan, batas worker tidak menjadi faktor dominan dalam latensi. Kontrol tetap terasa langsung, dan hanya itulah yang akan dipedulikan pemain.</p>
<p>Salah satu tantangan pada fase ini adalah risiko salah menafsirkan hasil. Setelah mendapatkan hasil yang sukses, tim sering kali menggeneralisasi secara berlebihan dan menganggap pertanyaan tentang arsitektur telah tuntas selamanya. Padahal tidak. Kami hanya memvalidasi satu skenario konkret dan satu profil perangkat keras. Spike berikutnya tetap harus menguji ulang asumsi ketika beban GPU dan streaming berubah.</p>
<p>Spike ini juga meningkatkan proses kerja kami. Kami mulai menampilkan telemetri waktu di HUD secara default untuk spike interaktif. Hal itu mengubah percakapan tim dari &quot;rasanya ada yang tidak beres&quot; menjadi &quot;alur ini menambah 1,2 ms.&quot;</p>
<p>Di bagian 3, kami membahas eksperimen yang kurang menarik tetapi mencegah kejutan mahal di kemudian hari: beban broadcast, keterbatasan perangkat seluler, dan keandalan pembuatan perilaku.</p>
<h2>Teknologi yang dibahas dalam bab ini</h2>
<p><strong>Rapier.</strong> Mesin fisika yang ditulis dalam Rust dan dikompilasi menjadi WebAssembly untuk digunakan di browser. Rapier menangani rigid body, collider, joint, character controller, dan raycasting dengan performa 2–3 kali lipat dibandingkan implementasi native. Untuk dunia terbuka, Rapier menyediakan character controller pemain (berjalan di medan, menaiki anak tangga, meluncur di lereng), tabrakan objek, raycasting untuk interaksi, dan trigger volume. Lihat <a href="https://rapier.rs/">dokumentasi Rapier</a> dan <a href="/id/guides/browser-3d-open-world-tech#rapier-rust-wasm">panduan teknologi 3D browser kami tentang fisika</a>.</p>
<p><strong>Web Workers.</strong> Thread browser yang menjalankan JavaScript (atau Wasm) di luar thread utama. Menjalankan simulasi fisika di worker berarti pemanggilan <code>world.step()</code> yang berat tidak memblokir rendering. Thread utama mengirimkan status input ke worker di setiap frame melalui <code>postMessage</code> dan menerima kembali posisi otoritatif. Penalti latensinya berasal dari dua perjalanan pesan tersebut (~0,1–0,5 ms per perjalanan di desktop). Manfaatnya adalah thread render tidak pernah terhenti akibat deteksi tabrakan. Transferable object (transfer <code>ArrayBuffer</code>) menghilangkan overhead penyalinan untuk array posisi berukuran besar.</p>
<p><strong>WebAssembly (Wasm).</strong> Format instruksi biner yang berjalan di browser dengan kecepatan mendekati native. Rapier, Havok, dan Recast semuanya dapat dikompilasi menjadi Wasm. Langkah fisika di Rapier-Wasm biasanya memerlukan 0,5–2 ms untuk beberapa ratus body, dibandingkan 5–15 ms untuk implementasi JavaScript yang setara. Modul Wasm dimuat sebagai berkas <code>.wasm</code> yang diambil bersama kode perekat JavaScript. Lihat <a href="https://webassembly.org/">spesifikasi WebAssembly</a>.</p>
<p><strong>Latensi input-ke-visual.</strong> Waktu antara penekanan tombol dan perubahan visual yang dihasilkannya di layar. Agar gerakan terasa &quot;langsung&quot;, latensi ini harus tetap di bawah ~80 ms. Dalam konfigurasi fisika berbasis worker, rantainya bersifat aditif:</p>
<p>$$
L = t_\text{input} + 2,t_\text{msg} + t_\text{step} + t_\text{render} + t_\text{vsync}
$$</p>
<p>event keydown (thread utama), <code>postMessage</code> ke worker dan kembali lagi ($2,t_\text{msg}$), langkah fisika, renderer menerapkan posisi baru, lalu vsync berikutnya. Setiap komponen relatif kecil jika berdiri sendiri (~0,1–0,5 ms per perjalanan pesan di desktop), tetapi semuanya terakumulasi. Itulah sebabnya kami mengukur $L$ secara langsung alih-alih hanya memercayai diagram arsitektur.</p>
<hr>
<p>Bagian 2 dari 12.<br>
Sebelumnya: <a href="/id/blog/2026-02-25-open-world-browser-part-01-risk-first">Bagian 1 - Kami memulai dengan mencoba merusaknya</a><br>
Berikutnya: <a href="/id/blog/2026-02-25-open-world-browser-part-03-the-unflashy-spikes">Bagian 3 - Spike yang tidak mencolok tetapi menyelamatkan kami</a><br>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 3: Eksperimen sederhana yang menyelamatkan kami]]></title>
            <link>https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-03-the-unflashy-spikes</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-03-the-unflashy-spikes</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Beban broadcast Durable Object, batasan kualitas seluler, dan keandalan pembuatan perilaku memang tidak glamor, tetapi semuanya mencegah kejutan yang mahal.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 3: Eksperimen sederhana yang menyelamatkan kami</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru di sini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menyediakan tautan ke semua bagian.</p>
<p>Bagian ini memiliki lebih sedikit tangkapan layar yang memukau dan lebih banyak pengaman arsitektur.</p>
<p>Setelah Spike 1 dan 2, kami menjalankan tiga pemeriksaan risiko yang tampak kecil, tetapi berdampak besar pada produk.</p>
<p>Yang pertama adalah fan-out broadcast dengan Durable Objects. Kami menguji distribusi posisi multi-klien pada tick rate seperti dalam game dan melacak distribusi latensi, penggunaan CPU per tick, serta integritas pengiriman. Jika pengujian ini gagal, kami akan beralih ke sharding sejak awal alih-alih menggunakan kepemilikan satu pulau.</p>
<p>Yang kedua adalah validasi batasan perangkat seluler. Bukan preset desktop yang sekadar diganti namanya menjadi seluler, melainkan profil berbiaya rendah yang eksplisit dari baseline medan yang sama.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/01-terrain/?quality=mobile" title="Profil kualitas seluler berdasarkan Spike 1" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/01-terrain/?quality=mobile" target="_blank">Buka profil seluler di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=01-terrain">Lihat kode sumber</a></p>
<p>Kami mengurangi kepadatan segmen, jumlah objek, beban resolusi rendering, dan jangkauan kabut. Pertanyaannya sederhana. Bisakah dunia ini tetap mudah dibaca dan responsif dalam batasan perangkat kelas seluler tanpa menulis ulang seluruh renderer?</p>
<p>Yang ketiga adalah keandalan pembuatan perilaku untuk alur kerja kreator. Kami mengevaluasi tingkat JSON yang valid, ketepatan semantik terhadap primitif yang diharapkan, dan latensi respons. Jika pengujian ini gagal, kami akan beralih ke pembuatan perilaku berbasis formulir yang ketat.</p>
<p>Wawasan utama dari bab ini adalah bahwa eksperimen sederhana ini mengubah arsitektur lebih cepat daripada eksperimen visual. Eksperimen tersebut menetapkan batas tegas untuk topologi jaringan, janji performa seluler, dan UX alat kreator.</p>
<p>Di bagian 4, kami kembali ke pekerjaan medan yang terlihat dan menguji perilaku streaming saat bergerak, bukan sekadar tangkapan layar pemuatan statis.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Cloudflare Durable Objects.</strong> Instans serverless berstatus yang diterapkan di edge, dengan persistensi bawaan dan dukungan WebSocket. Setiap Durable Object menyimpan state otoritatif untuk satu shard (atau chunk) dunia. Pemain terhubung melalui WebSocket dan menerima broadcast posisi dari pemain lain dalam shard yang sama. Saat pemain berpindah ke chunk yang bersebelahan, mereka terhubung ke Durable Object milik chunk tersebut. Durable Objects secara otomatis menyimpan state secara persisten ke disk dan dapat diskalakan hingga ribuan instans bersamaan. Lihat <a href="https://developers.cloudflare.com/durable-objects/">dokumentasi Cloudflare Durable Objects</a> dan <a href="/id/guides/browser-3d-open-world-tech#multiplayer-networking">panduan teknologi 3D browser kami tentang jaringan multipemain</a>.</p>
<p><strong>Sharding spasial.</strong> Membagi dunia ke beberapa instans server berdasarkan wilayah geografis. Setiap shard memiliki satu area persegi panjang pada grid dunia. Saat kepadatan pemain berubah, shard dapat dipecah atau digabungkan. Pemain di dekat batas shard dapat melihat konten dari kedua shard melalui kueri visibilitas lintas-shard. Inilah cara <a href="/id/guides/browser-3d-open-world-tech#server-architecture">EVE Online menangani ribuan pemain</a> dalam satu semesta.</p>
<p><strong>Fan-out broadcast WebSocket.</strong> Mendistribusikan pembaruan posisi secara real-time dari satu server ke banyak klien yang terhubung. Bandwidth downstream per klien meningkat secara linear mengikuti jumlah pemain yang dapat terlihat:</p>
<p>$$
B_\text{client} = N_\text{visible} \times b_\text{player}
$$</p>
<p>Pada tick rate seperti dalam game (20–30 Hz), setiap pemain menghasilkan data posisi sebesar $b_\text{player} \approx 800$ byte/detik, sehingga 200 pemain yang terlihat membutuhkan $200 \times 800 = 160$ KB/detik per klien. Biaya server untuk pendekatan all-to-all yang naif bahkan lebih buruk karena meningkat seperti $N^2$. Inilah alasan relevance filtering (pengelolaan area kepentingan spasial) membatasi $N_\text{visible}$ sebelum pembaruan dikirim ke setiap koneksi dalam anggaran waktu tick. Lihat <a href="/id/guides/browser-3d-open-world-tech#client-server-communication">panduan jaringan kami</a> untuk memahami kompromi antara kompresi delta dan frekuensi pembaruan.</p>
<p><strong>Batasan rendering seluler.</strong> GPU seluler memiliki throughput sebesar 1/5 hingga 1/10 dari GPU desktop, batas memori sekitar 1 GB (dibandingkan 2–4 GB pada desktop), serta mengalami thermal throttling saat menerima beban berkelanjutan. Profil kualitas seluler mengurangi kepadatan segmen, jumlah objek, resolusi rendering, jarak pandang, dan kualitas bayangan. Tujuannya bukan menyamai kualitas desktop, melainkan mempertahankan keterbacaan dan responsivitas. Lihat <a href="/id/guides/browser-3d-open-world-tech#browser-3d-performance-real-numbers">angka performa 3D browser</a> untuk benchmark GPU nyata.</p>
<hr>
<p>Bagian 3 dari 12.<br>
Sebelumnya: <a href="/id/blog/2026-02-25-open-world-browser-part-02-worker-physics">Bagian 2 - Fisika Worker dan kekhawatiran akan input lag</a><br>
Berikutnya: <a href="/id/blog/2026-02-25-open-world-browser-part-04-streaming-before-fancy">Bagian 4 - Streaming sebelum medan yang canggih</a><br>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 4: Streaming sebelum membuat medan yang canggih]]></title>
            <link>https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-04-streaming-before-fancy</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-04-streaming-before-fancy</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Kami menguji pemuatan dan pergantian chunk terlebih dahulu dengan konten sederhana, lalu beralih ke penyempurnaan heightmap secara progresif. Urutan itu terbukti menguntungkan.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 4: Streaming sebelum membuat medan yang canggih</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru mengikuti seri ini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menautkan semua bagiannya.</p>
<p>Streaming adalah tahap ketika proyek yang &quot;terlihat bagus&quot; biasanya mulai berantakan.</p>
<p>Anda bisa menyembunyikan banyak hal dalam satu frame diam. Anda tidak bisa menyembunyikan sendatan selama 40 ms saat melintasi batas chunk.</p>
<p>Kami sengaja menguji streaming sebelum membangun representasi medan tingkat lanjut. Dengan begitu, kami mendapatkan sinyal yang jelas tentang perilaku pemuatan dan penghapusan.</p>
<p>Spike 6 memvalidasi pergantian lingkungan sekitar dengan konten chunk sederhana.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/06-chunk-streaming/" title="Spike 6: Pergantian Pemuatan Chunk" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/06-chunk-streaming/" target="_blank">Buka Spike 6 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=06-chunk-streaming">Lihat kode sumber</a></p>
<p>Kemudian kami beralih ke jalur medan yang sebenarnya dalam Spike 11: streaming chunk ketinggian dengan decoding di sisi worker dan penyempurnaan progresif dari grid sampel 17 menjadi 33, lalu 65.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/11-chunk-streaming/" title="Spike 11: Streaming Chunk Heightmap" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/11-chunk-streaming/" target="_blank">Buka Spike 11 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=11-chunk-streaming">Lihat kode sumber</a></p>
<p>Urutan pengerjaan ternyata lebih penting daripada yang kami perkirakan. Jika kami langsung memulai dengan chunk ketinggian terkompresi, penyebab setiap sendatan akan sulit dipastikan. Apakah masalah decoding, pengunggahan tekstur, atau pembaruan geometri? Spike 6 menghilangkan satu lapisan ketidakpastian sebelum Spike 11 menambahkan kompleksitas.</p>
<p>Pelajaran praktis dari bagian ini kami terapkan pada spike-spike berikutnya. Kemacetan saat pengunggahan harus diukur secara langsung, bukan disimpulkan dari FPS rata-rata. FPS rata-rata menyembunyikan lonjakan waktu frame, padahal lonjakan itulah yang benar-benar dirasakan pengguna.</p>
<p>Pada bagian 5, kita memasuki pembahasan biaya visual, ketika vegetasi, shader medan, dan bayangan berjenjang bersaing memperebutkan anggaran frame yang sama.</p>
<h2>Teknologi yang dibahas dalam bagian ini</h2>
<p><strong>Streaming berbasis chunk.</strong> Dunia dibagi menjadi grid yang terdiri dari chunk independen (biasanya berukuran 64x64 meter). Saat pemain bergerak, chunk di sisi belakang dihapus sementara chunk di sisi depan dimuat melalui streaming. Beginilah cara kerja <a href="/id/guides/browser-3d-open-world-tech#skyrim-s-cell-system">sistem sel Skyrim</a>: grid sel 5x5 dimuat di sekitar pemain dan diganti seiring pergerakan mereka. Versi browser menambahkan latensi jaringan ke dalam perhitungan, sehingga pre-fetching prediktif berdasarkan kecepatan pemain menjadi sangat penting. Lihat <a href="/id/guides/landscape-generation-browser#streaming-architecture-for-terrain">panduan arsitektur streaming</a> kami.</p>
<p><strong>Penyempurnaan heightmap secara progresif.</strong> Kirim medan dalam resolusi rendah terlebih dahulu, lalu sempurnakan. Ukuran grid ini tidak dipilih secara sembarangan: setiap tingkat merupakan grid $(2^k + 1) \times (2^k + 1)$, sehingga $17 = 2^4 + 1$, $33 = 2^5 + 1$, dan $65 = 2^6 + 1$. Nilai $+1$ mempertahankan satu sampel bersama pada setiap batas agar chunk yang bersebelahan tetap sejajar, dan setiap tahap kurang lebih melipatgandakan jumlah sampel sebanyak empat kali ($n^2$ bertambah saat panjang sisi digandakan). Grid 17x17 (ukuran minimum untuk chunk 64 m dengan jarak 4 m) berukuran sekitar 200 byte setelah dikompresi dan dapat langsung merender permukaan yang terlihat. Setelah itu, stream penyempurnaan 33x33, kemudian resolusi penuh 65x65. Setiap tingkat menambahkan sampel tanpa mengganti data sebelumnya. Pendekatan ini dapat dipetakan langsung ke cincin LOD geometry clipmap, tempat medan jauh menggunakan data beresolusi rendah dan medan jarak dekat menggunakan resolusi penuh. Lihat <a href="/id/guides/landscape-generation-browser#progressive-chunk-loading">pemuatan chunk progresif</a>.</p>
<p><strong>Pengodean delta dan kompresi.</strong> Data heightmap dapat dikompresi dengan baik karena sel-sel yang bersebelahan memiliki nilai serupa. Pengodean delta menyimpan selisih antara setiap sel dan nilai prediksinya (rata-rata sel tetangga), sehingga nilai-nilai terkumpul di sekitar nol. Jika digabungkan dengan zlib atau brotli, chunk 65x65 menyusut dari ukuran mentah 8,4 KB menjadi 1–2 KB setelah dikompresi. Dengan presisi yang dikurangi untuk chunk jauh (8-bit alih-alih 16-bit), ukurannya menjadi 0,5–1 KB. Lihat <a href="/id/guides/landscape-generation-browser#terrain-data-compression-for-streaming">kompresi data medan</a>.</p>
<p><strong>Pre-fetching prediktif.</strong> Memuat chunk sebelum pemain tiba. Jarak antisipasi harus mencakup jarak yang ditempuh pemain selama pemuatan chunk, $d_\text{prefetch} = v \cdot t_\text{load}$, sehingga jarak tersebut meningkat sesuai kecepatan: pada kecepatan berjalan (5 km/jam), lakukan pre-fetch 2 chunk ke depan (128 m); pada kecepatan berlari (15 km/jam), lakukan pre-fetch 4 chunk. Cincin pemuatan bergeser mengikuti arah kecepatan. Antrean prioritas mengurutkan permintaan tertunda berdasarkan urgensi dan membatalkan permintaan chunk yang telah dijauhi pemain. Lihat <a href="/id/guides/landscape-generation-browser#predictive-pre-fetching">pre-fetching prediktif</a>.</p>
<hr>
<p>Bagian 4 dari 12.<br>
Sebelumnya: <a href="/id/blog/2026-02-25-open-world-browser-part-03-the-unflashy-spikes">Bagian 3 - Spike sederhana yang menyelamatkan kami</a><br>
Berikutnya: <a href="/id/blog/2026-02-25-open-world-browser-part-05-budgeting-the-pretty">Bagian 5 - Menganggarkan hal-hal yang mempercantik tampilan</a><br>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 5: Mengatur anggaran untuk elemen visual]]></title>
            <link>https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-05-budgeting-the-pretty</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-05-budgeting-the-pretty</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Vegetasi, material medan, dan bayangan berjenjang terlihat memukau. Tantangan sebenarnya adalah membuktikan bahwa semuanya dapat masuk dalam anggaran waktu frame.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 5: Mengatur anggaran untuk elemen visual</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru mengikuti seri ini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menyediakan tautan ke semua bagian.</p>
<p>Di bab inilah ambisi visual bertemu dengan perhitungan.</p>
<p>Kami membagi biaya rendering ke dalam beberapa spike terpisah karena hasil yang digabungkan sulit didiagnosis. Jika Anda mengaktifkan semuanya sekaligus, Anda hanya akan mengetahui bahwa frame berjalan lambat. Anda tidak akan mengetahui fitur mana yang menghabiskan anggaran.</p>
<p>Spike 7 menargetkan kepadatan vegetasi dan biaya animasi. Pendekatannya menggunakan penyebaran saat runtime dari density map 32x32 untuk setiap chunk medan, yang mengisi kumpulan <code>InstancedMesh</code> berukuran besar. Setiap helai rumput dan kelompok semak mendapatkan efek angin di vertex shader yang digerakkan oleh tekstur noise bergulir. Angka utama yang kami pantau bukan jumlah segitiga, melainkan overhead draw call dan throughput vertex pada GPU kelas menengah. Kami menemukan bahwa mengelompokkan instance ke dalam lebih sedikit mesh lebih penting daripada mengurangi jumlah poligon per helai.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/07-gpu-vegetation/" title="Spike 7 Vegetasi GPU" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/07-gpu-vegetation/" target="_blank">Buka Spike 7 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=07-gpu-vegetation">Lihat kode sumber</a></p>
<p>Spike 8 mendorong kompleksitas material medan. Perpaduan multilapis yang dibobot berdasarkan sudut kemiringan dan ketinggian, proyeksi triplanar opsional untuk permukaan tebing, serta normal map per lapisan. Shader melakukan splatting berbasis kemiringan dengan empat lapisan tekstur, masing-masing membutuhkan satu sampel diffuse dan normal. Itu berarti $4 \times 2 = 8$ pengambilan tekstur per fragmen sebelum pencahayaan ditambahkan, dan jumlahnya meningkat secara linear seiring penambahan lapisan, sehingga lapisan kelima berarti 10 pengambilan pada setiap piksel. Kami secara khusus melakukan profiling pada GPU Intel terintegrasi untuk menemukan batas minimumnya. Kesimpulannya, proyeksi triplanar pada permukaan vertikal sepadan dengan biayanya, tetapi penambahan lapisan splat kelima tidak.</p>
<p><a href="/id/spikes/08-terrain-material/" target="_blank">Buka Spike 8 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=08-terrain-material">Lihat kode sumber</a></p>
<p>Spike 9 berfokus pada biaya cascaded shadow map dengan beban medan dan objek yang realistis. CSM dengan tiga cascade menjadi patokan dasar. Kami secara khusus mengujinya dengan posisi matahari bersudut rendah karena pada kondisi itulah tekanan terhadap cascade menjadi paling berat. Cascade terjauh mencakup potongan frustum yang sangat besar, sementara detail bayangan ditentukan oleh kepadatan texel, $\rho \approx \frac{R^2}{A}$ (shadow map beresolusi $R$ yang direntangkan di atas area permukaan $A$). Satu map untuk seluruh jarak pandang membuat $A$ menjadi sangat besar dan $\rho$ merosot. Cascade mengatasi masalah ini dengan membagi frustum agar setiap potongan mendapatkan map $R \times R$ sendiri di atas $A$ yang kecil, sehingga $\rho$ tetap kurang lebih konstan dari jarak dekat hingga jauh. Kami mengukur perbedaan waktu GPU antara dua dan empat cascade, lalu antara resolusi shadow map 1024 dan 2048. Hasilnya, tiga cascade pada resolusi 1024 memberikan contact shadow yang memadai di dekat kamera tanpa melampaui 2 md waktu GPU pada perangkat keras target kami.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/09-csm-shadows/" title="Spike 9 Bayangan CSM" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/09-csm-shadows/" target="_blank">Buka Spike 9 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=09-csm-shadows">Lihat kode sumber</a></p>
<p>Bagian tersulit dalam fase ini adalah disiplin produk. Beberapa efek terlihat sangat memukau, tetapi tetap harus dibatasi karena menghabiskan terlalu banyak anggaran frame dibandingkan dengan dampak visualnya.</p>
<p>Aturan kami menjadi sederhana. Sebuah fitur hanya dilanjutkan jika biayanya dapat dijelaskan menggunakan data waktu frame yang terukur.</p>
<p>Kedengarannya jelas. Namun, praktik ini tidak umum dalam siklus pembuatan prototipe cepat ketika semua orang antusias terhadap peningkatan visual berikutnya. Menerapkan aturan ini sejak awal membuat keputusan arsitektur seputar clipmap dan zona volumetrik menjadi jauh lebih jelas di kemudian hari karena kami sudah mengetahui biaya per fitur dari semua hal yang bersaing memperebutkan 16 md yang sama.</p>
<p>Di bagian 6, kami melakukan perubahan arah besar pertama pada arsitektur medan dengan geometry clipmap.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>InstancedMesh dan vegetasi GPU.</strong> <code>InstancedMesh</code> milik Three.js merender N salinan geometri yang sama dengan satu draw call. Untuk vegetasi, density map (32x32 per chunk) mengendalikan penyebaran helai rumput dan kelompok semak saat runtime ke dalam buffer instance. Animasi angin berjalan di vertex shader menggunakan tekstur noise bergulir. Dalam skala besar, <code>ComputeInstanceCulling</code> milik WebGPU menghilangkan instance di luar layar dan di kejauhan sebelum rasterisasi, sedangkan <code>IndirectBatchedMesh</code> mengemas beberapa jenis vegetasi ke dalam satu buffer yang dirender dengan multi-draw indirect. Lihat <a href="/id/guides/landscape-generation-browser#gpu-driven-vegetation-culling">panduan lanskap kami tentang culling vegetasi GPU</a>.</p>
<p><strong>Pemetaan triplanar.</strong> Tekstur standar dengan pemetaan UV akan meregang pada lereng curam karena koordinat UV terkompresi. Pemetaan triplanar memproyeksikan tekstur di sepanjang ketiga sumbu (X, Y, Z) dan memadukannya berdasarkan normal permukaan. Permukaan tebing mendapatkan proyeksi X atau Z (tanpa peregangan), sedangkan tanah datar mendapatkan proyeksi Y. Perpaduannya halus dan otomatis tanpa memerlukan UV unwrapping. Untuk medan PBR, bobot perpaduan yang sama diterapkan pada channel albedo, normal, roughness, dan ambient occlusion. Lihat <a href="/id/guides/landscape-generation-browser#triplanar-mapping">detail pemetaan triplanar</a>.</p>
<p><strong>Splatting material berbasis kemiringan dan ketinggian.</strong> Alih-alih menggunakan splat map yang dilukis manual, material ditetapkan secara prosedural di fragment shader berdasarkan karakteristik medan. Tanah datar pada ketinggian rendah mendapatkan rumput, lereng curam mendapatkan batu, area berketinggian tinggi mendapatkan salju (hanya pada permukaan yang cukup datar agar salju dapat menumpuk), dan area dekat permukaan laut mendapatkan pasir. Transisinya menggunakan <code>smoothstep</code> agar perpaduan tetap halus. Dalam implementasi kami, setiap chunk medan mengevaluasi empat lapisan tekstur dengan sampel diffuse dan normal per lapisan, sehingga menghasilkan delapan pengambilan tekstur per fragmen sebelum pencahayaan. Lihat <a href="/id/guides/landscape-generation-browser#slope-and-altitude-based-material-assignment">penetapan material berdasarkan kemiringan dan ketinggian</a>.</p>
<p><strong>Cascaded Shadow Maps (CSM).</strong> CSM membagi frustum pandangan kamera menjadi 3–4 rentang jarak (cascade). Setiap cascade merender shadow map dari perspektif matahari dengan resolusi yang disesuaikan dengan jaraknya. Cascade dekat mendapatkan bayangan beresolusi tinggi (contact shadow yang mendetail di bawah pohon dan bangunan), sedangkan cascade jauh mendapatkan resolusi lebih rendah (bayangan pegunungan yang luas). Shader medan mengambil sampel dari semua cascade dan memilih cascade yang sesuai untuk setiap fragmen. Biaya performa: 3–4 cascade pada resolusi 1024x1024 menambahkan sekitar 0,5–1 md untuk rendering shadow map, ditambah sekitar 0,2–0,3 md untuk pengambilan sampel. Lihat <a href="/id/guides/landscape-generation-browser#shadows-for-terrain">bayangan untuk medan</a>.</p>
<hr>
<p>Bagian 5 dari 12.<br>
Sebelumnya: <a href="/id/blog/2026-02-25-open-world-browser-part-04-streaming-before-fancy">Bagian 4 - Streaming sebelum medan yang canggih</a><br>
Berikutnya: <a href="/id/blog/2026-02-25-open-world-browser-part-06-clipmaps">Bagian 6 - Clipmap mengubah jalan cerita</a><br>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 6: Clipmap mengubah alur cerita]]></title>
            <link>https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-06-clipmaps</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-06-clipmaps</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Geometry clipmap memberi kami cara untuk menjaga biaya terrain tetap dapat diprediksi saat menjelajahi dunia yang jauh lebih luas.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 6: Clipmap mengubah alur cerita</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru mengikuti seri ini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menautkan semua bagiannya.</p>
<p>Sebelum Spike 10, model mental kami masih berupa &quot;dunia yang lebih besar berarti lebih banyak geometri.&quot; Setelah Spike 10, modelnya berubah menjadi &quot;anggaran geometri konstan, pembaruan cincin yang berpusat pada kamera.&quot; Perubahan ini mengubah arah proyek.</p>
<p>Gagasan di balik geometry clipmap cukup sederhana. Terrain dirender sebagai sekumpulan cincin konsentris yang berpusat pada kamera. Cincin terdalam memiliki kerapatan vertex tertinggi. Setiap cincin $k$ ke arah luar menggandakan jarak antar-vertex, $s_k = s_0 \cdot 2^k$, sehingga mencakup area permukaan tanah $4\times$ lebih luas daripada cincin di dalamnya.</p>
<p>Penggandaan itulah inti triknya. Jarak pandang bertambah secara geometris seiring jumlah cincin, $d_\text{view} \approx s_0 \cdot 2^{L}$, sedangkan biaya vertex hanya bertambah secara linear:</p>
<p>$$
V_\text{total} \approx N^2 \cdot L
$$</p>
<p>untuk $L$ cincin yang masing-masing memiliki $N \times N$ vertex. Menggandakan jarak pandang hanya membutuhkan satu cincin tambahan, bukan geometri empat kali lebih banyak. Jumlah segitiga tetap kurang lebih konstan terlepas dari ukuran dunia karena Anda selalu merender $L$ cincin yang sama pada resolusi yang sama.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/10-clipmap-geomorph/" title="Geomorphing Geometry Clipmap Spike 10" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/10-clipmap-geomorph/" target="_blank">Buka Spike 10 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=10-clipmap-geomorph">Lihat kode sumber</a></p>
<p>Trik praktisnya adalah geomorphing pada batas cincin. Ketika sebuah vertex bertransisi dari satu cincin LOD ke cincin berikutnya, tingginya harus berbaur secara mulus antara sampel beresolusi tinggi dan rendah. Tanpa itu, akan muncul lompatan visual setiap kali kamera bergerak dan cincin bergeser. Kami menanganinya dengan faktor pembauran berdasarkan jarak vertex ke tepi cincin, lalu menginterpolasi tinggi di vertex shader:</p>
<p>$$
h = \operatorname{lerp}(h_\text{fine},, h_\text{coarse},, \alpha), \qquad \alpha = \operatorname{smoothstep}(d_\text{near},, d_\text{far},, d)
$$</p>
<p>dengan $d$ sebagai jarak vertex dari kamera. Di dalam cincin ($d \le d_\text{near}$), vertex menggunakan tinggi pada resolusi penuh; ketika mencapai cincin berikutnya ($d \ge d_\text{far}$), vertex tersebut sudah beralih ke tinggi kasar yang akan digunakan oleh cincin itu, sehingga tidak ada lagi yang dapat menimbulkan lompatan visual.</p>
<p>Satu pelajaran yang tidak terlalu kentara muncul dari pengujian pergerakan kamera. Clipmap mudah dinilai dari tangkapan layar statis, tetapi artefak transisi bisa terlewat. Kami menghabiskan waktu menjalankan penelusuran berkecepatan konstan melintasi batas-batas cincin sambil mengamati noise temporal. Tangkapan layar menipu. Gerakan menunjukkan kenyataan.</p>
<p>Spike ini juga memberi kami batas arsitektur yang jelas. Seiring waktu, terrain jarak dekat dapat menjadi dinamis dan mahal, dengan pengeditan volumetrik, kompleksitas material yang lebih tinggi, dan interaksi fisika. Terrain jarak jauh dapat tetap stabil, dapat diprediksi, dan murah. Pemisahan ini menjadi tulang punggung setiap keputusan arsitektur sejak saat itu.</p>
<p>Jika Anda sedang mengevaluasi clipmap untuk proyek sendiri, ujilah dengan rangkaian uji stres, bukan gambar cantik. Jalur penelusuran yang panjang, perubahan ketinggian kamera, dan perlintasan batas secara berulang adalah hal-hal yang mengungkap masalah sebenarnya.</p>
<p>Pada bagian 7, kami menambahkan meshing volumetrik dan beralih dari &quot;terrain sebagai permukaan&quot; menjadi &quot;terrain sebagai volume yang dapat diedit.&quot; Pada titik itulah proyek ini berhenti sekadar menjadi renderer dan mulai berkembang menjadi editor dunia.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Geometry clipmap.</strong> Diperkenalkan oleh Losasso dan Hoppe pada SIGGRAPH 2004 (<a href="https://hhoppe.com/geomclipmap.pdf">makalah</a>), geometry clipmap merender terrain sebagai cincin-cincin persegi konsentris yang berpusat pada kamera. Setiap cincin mencakup area dua kali lebih luas daripada cincin sebelumnya dengan separuh resolusi vertex. Jumlah total vertex bersifat konstan: sekitar $N^2 \cdot L$. Dengan $N = 256$ dan $L = 8$ level, hasilnya adalah $256^2 \times 8 \approx 524{,}000$ vertex, terlepas dari ukuran dunia. CPU memperbarui data heightmap untuk setiap cincin saat kamera bergerak. Vertex shader membaca tinggi dari sebuah tekstur dan menggeser grid datar. Lihat <a href="/id/guides/landscape-generation-browser#geometry-clipmaps">panduan landscape kami tentang geometry clipmap</a> dan <a href="https://developer.nvidia.com/gpugems/gpugems2/part-i-geometric-complexity/chapter-2-terrain-rendering-using-gpu-based-geometry">GPU Gems 2, Bab 2</a>.</p>
<p><strong>Geomorphing.</strong> Artefak visual terbesar dalam LOD terrain adalah popping: vertex tiba-tiba melompat ketika sebuah patch berganti level LOD. Geomorphing menghilangkan hal ini dengan membaurkan posisi vertex di antara level-level LOD dalam sebuah zona transisi. Setiap vertex menyimpan tinggi LOD saat ini sekaligus tinggi LOD yang lebih kasar. Faktor morph berdasarkan jarak kamera menginterpolasi keduanya secara mulus: <code>morphedHeight = mix(fineLodHeight, coarseLodHeight, smoothstep(lodNear, lodFar, distance))</code>. Zona transisi biasanya mencakup 20% bagian terluar dari setiap cincin. Pada kecepatan kamera normal, transisinya tidak terlihat. Lihat <a href="/id/guides/landscape-generation-browser#geomorphing-pop-free-lod-transitions">detail geomorphing</a>.</p>
<p><strong>CDLOD (Clipmap Adaptif Quadtree).</strong> Penyempurnaan clipmap bercincin tetap oleh Strugar (2014, <a href="https://www.vertexasylum.com/CDLOD/cdlod_latest.pdf">makalah</a>). Alih-alih menggunakan cincin konsentris dengan resolusi seragam, CDLOD menggunakan quadtree yang beradaptasi dengan kompleksitas terrain. Area datar menggunakan node kasar, sedangkan area dengan detail tinggi (tebing, punggung bukit) mendapatkan subdivisi yang lebih halus. Hal ini penting bagi dunia buatan kreator karena setiap chunk dapat memiliki tingkat kompleksitas yang sangat berbeda. Lihat <a href="/id/guides/landscape-generation-browser#cdlod-quadtree-adaptive-clipmaps">CDLOD dalam panduan landscape kami</a>.</p>
<hr>
<p>Bagian 6 dari 12.<br>
Sebelumnya: <a href="/id/blog/2026-02-25-open-world-browser-part-05-budgeting-the-pretty">Bagian 5 - Menganggarkan hal-hal yang mempercantik tampilan</a><br>
Berikutnya: <a href="/id/blog/2026-02-25-open-world-browser-part-07-marching-cubes">Bagian 7 - Marching cubes dan gua nyata pertama</a><br>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 7: Marching cubes dan gua nyata pertama]]></title>
            <link>https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-07-marching-cubes</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-07-marching-cubes</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 12 menghadirkan marching cubes WebGPU waktu nyata ke dalam proyek dan mengubah kemungkinan yang dapat diwujudkan oleh medan.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 7: Marching cubes dan gua nyata pertama</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru mengikuti seri ini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menyediakan tautan ke semua bagian.</p>
<p>Heightmap sangat bagus sampai Anda membutuhkan struktur yang menjorok.</p>
<p>Begitu ingin membuat terowongan yang dipahat, tepian batu yang menggantung, atau langit-langit gua, pipeline heightfield murni mulai membatasi Anda. Heightmap menyimpan satu nilai Y untuk setiap koordinat XZ. Secara fisik, heightmap tidak mampu merepresentasikan permukaan yang melipat kembali di atas dirinya sendiri. Kami membutuhkan representasi volumetrik.</p>
<p>Spike 12 mengimplementasikan marching cubes di GPU menggunakan compute shader WebGPU. Algoritma ini mengevaluasi signed distance field (SDF) pada grid 3D dan mengekstrak mesh segitiga di permukaan persilangan nol. Setiap sel memiliki 8 sudut, yang masing-masing berada di dalam atau di luar permukaan, sehingga menghasilkan $2^8 = 256$ kemungkinan pola tanda. Tabel pencarian memetakan setiap pola ke sekumpulan segitiga. Verteks ditempatkan pada rusuk sel, tepat di titik tempat field melintasi nol. Untuk rusuk di antara sudut $a$ dan $b$ dengan nilai field $f_a$ dan $f_b$, interpolasi linear menempatkan verteks pada</p>
<p>$$
\mathbf{v} = \mathbf{p}_a + t,(\mathbf{p}_b - \mathbf{p}_a), \qquad t = \frac{-f_a}{f_b - f_a}
$$</p>
<p>yang merupakan fraksi sepanjang rusuk tempat nilai field mencapai nol. Karena $f_a$ dan $f_b$ memiliki tanda yang berlawanan pada rusuk yang bersilangan, $t$ selalu berada dalam $[0, 1]$. Kami menjalankannya pada empat chunk aktif berukuran 64 kubik secara bersamaan dan menguji pengeditan SDF beranimasi dengan pembuatan ulang mesh pada setiap frame.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/12-webgpu-marching-cubes/" title="Spike 12 Marching Cubes WebGPU" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/12-webgpu-marching-cubes/" target="_blank">Buka Spike 12 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=12-webgpu-marching-cubes">Lihat kode sumber</a></p>
<p>Keberhasilan pertama memberi kami keyakinan terhadap pipeline komputasi itu sendiri. Satu dispatch dapat mengevaluasi SDF, mengklasifikasikan sel, dan mengeluarkan verteks ke buffer GPU tanpa readback CPU sama sekali. Keberhasilan kedua adalah menyadari betapa cepatnya tahap &quot;sudah berfungsi&quot; berubah menjadi perburuan artefak. Segitiga yang hilang jarang disebabkan oleh masalah dalam teori marching cubes. Penyebabnya adalah ketidakcocokan indeks tabel, rentang draw yang keliru sehingga membaca melewati jumlah verteks aktif, atau interaksi kasus khusus di dekat batas chunk ketika sampel SDF tetangga tidak tersedia.</p>
<p>Spike ini memaksa kami berpikir dalam bentuk zona. Di dekat kamera, Anda menginginkan kebebasan volumetrik agar pemain dapat memahat, menggali, dan melihat gua. Jauh dari kamera, Anda menginginkan efisiensi clipmap karena heightmap datar lebih murah dan sudah sangat memadai. Dualitas tersebut menjadi tulang punggung arsitektur yang terus kami sempurnakan sejak Spike 13 dan seterusnya.</p>
<p>Salah satu momen debugging favorit saya adalah saat menggunakan tombol wireframe ketika pengeditan sedang berjalan. Melihat topologi terbentuk dan melebur secara waktu nyata membuat kompromi kualitas langsung terlihat. Anda dapat melihat bagian yang kepadatan verteksnya sudah cukup tinggi, bagian yang terlalu kasar, dan lokasi persis transisi LOD yang pada akhirnya akan membutuhkan dukungan Transvoxel untuk mencegah retakan.</p>
<p>Di bagian 8, kami membahas tantangan integrasi. Menyatukan mesh mentah yang digerakkan oleh komputasi dan logika scene graph Three.js dalam satu pipeline rendering yang stabil ternyata lebih sulit daripada yang ditunjukkan demo terpisah tersebut.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Marching cubes.</strong> Algoritma untuk mengekstrak mesh segitiga dari scalar field 3D (Lorensen dan Cline, 1987). Setiap sel dalam grid 3D beraturan diklasifikasikan dengan mengambil sampel field pada 8 sudutnya. Pola tanda menghasilkan indeks kasus (0-255), lalu tabel pencarian memetakan setiap kasus ke sekumpulan segitiga. Verteks ditempatkan pada rusuk grid dengan menginterpolasi antara kedua sudutnya. Algoritma ini sangat mudah diparalelkan karena setiap sel diproses secara independen, sehingga ideal untuk komputasi GPU. Lihat <a href="/id/guides/landscape-generation-browser#signed-distance-fields-sdfs">panduan lanskap kami tentang SDF dan marching cubes</a>.</p>
<p><strong>Signed Distance Field (SDF).</strong> Representasi volumetrik yang menyimpan jarak bertanda ke permukaan terdekat pada setiap titik dalam ruang 3D. Nilai positif berada di luar, nilai negatif berada di dalam, dan persilangan nol merupakan permukaannya. SDF dapat merepresentasikan bentuk 3D apa pun: gua, lengkungan, struktur yang menjorok, dan geometri mengambang yang tidak dapat diekspresikan oleh heightmap. Pengeditan dilakukan secara alami melalui aljabar himpunan pada field. Penambahan material (gabungan dua bentuk) adalah $d = \min(d_1, d_2)$, penghapusan (penggalian) adalah $d = \max(d_1, -d_2)$ dengan bentuk pahatan dinegasikan, sedangkan perpaduan halus menggunakan minimum lunak seperti</p>
<p>$$
\operatorname{smin}(d_1, d_2, k) = \min(d_1, d_2) - \frac{h^2}{4k}, \qquad h = \max\bigl(k - |d_1 - d_2|,, 0\bigr)
$$</p>
<p>dengan $k$ mengendalikan radius perpaduan. Ketika $k \to 0$, fungsi ini kembali menjadi $\min$ yang tegas. Lihat <a href="/id/guides/landscape-generation-browser#signed-distance-fields-sdfs">representasi medan SDF</a>.</p>
<p><strong>Compute shader WebGPU.</strong> Program GPU yang menjalankan komputasi serbaguna dan tidak terikat pada pipeline rasterisasi. Compute shader menjalankan workgroup berisi thread yang dieksekusi secara paralel. Untuk marching cubes, setiap thread memproses satu sel grid: mengambil sampel SDF, mengklasifikasikan sel, mencari triangulasi, menginterpolasi verteks rusuk, dan menambahkannya ke buffer mesh menggunakan penghitung atomik. Readback CPU tidak diperlukan karena buffer keluaran digunakan langsung sebagai data verteks untuk rendering. <a href="https://www.willusher.io/webgpu-marching-cubes/">webgpu-marching-cubes</a> karya Will Usher mendemonstrasikan pemrosesan grid 256^3 secara waktu nyata di browser. Lihat <a href="/id/guides/landscape-generation-browser#gpu-driven-lod-with-webgpu">panduan lanskap kami tentang LOD berbasis WebGPU</a>.</p>
<p><strong>Arsitektur gabungan heightmap + SDF.</strong> Pendekatan praktis untuk medan di browser: heightmap mencakup seluruh dunia (murah dan ringkas), sedangkan volume SDF hanya tersedia dalam chunk yang membutuhkan gua, struktur menjorok, atau fitur yang dipahat kreator (5-10% dari seluruh chunk). Di dekat kamera, kebebasan volumetrik memungkinkan pemahatan dan pembuatan gua. Di kejauhan, heightmap menyediakan medan datar yang efisien. Lihat <a href="/id/guides/landscape-generation-browser#hybrid-heightmap-base--volumetric-overlays">representasi medan gabungan</a>.</p>
<hr>
<p>Bagian 7 dari 12.<br>
Sebelumnya: <a href="/id/blog/2026-02-25-open-world-browser-part-06-clipmaps">Bagian 6 - Clipmap mengubah alur pengembangan</a><br>
Berikutnya: <a href="/id/blog/2026-02-25-open-world-browser-part-08-webgpu-integration">Bagian 8 - Integrasi tanpa kehilangan tolok ukur dasar kami</a><br>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 8: Integrasi tanpa kehilangan baseline]]></title>
            <link>https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-08-webgpu-integration</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-08-webgpu-integration</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 13 dan 14 lebih berfokus pada disiplin proses daripada fitur. Kami membekukan baseline yang bersih, lalu memperkuat satu lapisan demi satu.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 8: Integrasi tanpa kehilangan baseline</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru mengikuti seri ini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menyediakan tautan ke semua bagian.</p>
<p>Integrasi adalah tahap ketika proyek mulai menjadi berantakan. Anda memiliki komponen-komponen yang berfungsi secara terpisah. Begitu semuanya dihubungkan, tiba-tiba setiap bug terasa seolah bisa berasal dari mana saja.</p>
<p>Spike 13 dan 14 adalah jawaban kami terhadap jebakan tersebut. Spike 13 menetapkan baseline Three.js WebGPU yang bersih. Hanya sebuah renderer, scene, kamera, dan mesh sederhana. Tanpa terrain, compute, atau efek. Kami memastikan bahwa backend WebGPU milik Three.js dapat diinisialisasi dengan benar, render loop berjalan stabil, dan material node TSL (Three.js Shading Language) berfungsi sesuai harapan. Baru setelah checkpoint tersebut berhasil, kami mulai menambahkan lapisan.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/13-threejs-webgpu/" title="Spike 13: Baseline Three.js WebGPU" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/13-threejs-webgpu/" target="_blank">Buka Spike 13 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=13-threejs-webgpu">Lihat kode sumber</a></p>
<p>Spike 14 berfokus pada penguatan secara bertahap. Kami menambahkan satu kemampuan pada satu waktu: pertama kontrol kamera, lalu pencahayaan, kemudian mesh hasil komputasi dari pipeline marching cubes, dan setelah itu penyaluran buffer untuk memasukkan output GPU langsung ke atribut geometri Three.js. Setelah setiap penambahan, kami memastikan bahwa lapisan sebelumnya masih berfungsi dengan benar.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/14-threejs-webgpu-incremental/" title="Spike 14: Penguatan Bertahap" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/14-threejs-webgpu-incremental/" target="_blank">Buka Spike 14 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=14-threejs-webgpu-incremental">Lihat kode sumber</a></p>
<p>Proses tersebut terdengar lambat. Memang lambat selama tepat satu hari, tetapi segera setelah itu pendekatan ini menghemat beberapa hari kerja saat logika sambungan dan peralihan kebijakan menjadi rumit.</p>
<p>Kategori bug tertentu yang membenarkan disiplin ini adalah artefak setipis rambut. Serpihan tipis yang tampak seperti kerusakan geometri, tetapi sebenarnya disebabkan oleh data lama. Compute shader menulis N vertex ke dalam buffer, tetapi draw call masih dikonfigurasi untuk merender N+M vertex dari frame sebelumnya. Vertex tambahan tersebut berisi data sampah dari dispatch lama. Hasil visualnya adalah segitiga sangat tipis yang berkedip, muncul dan menghilang secara tidak terduga.</p>
<p>Bug dalam kategori tersebut tidak bisa dikalahkan hanya dengan intuisi. Anda mengatasinya melalui perubahan terkendali, sehingga Anda tahu persis apa yang berubah antara kondisi terakhir yang berfungsi dan kondisi saat ini yang rusak.</p>
<p>Integrasi WebGPU juga mengajari kami tentang siklus hidup buffer. Buffer GPU di WebGPU tidak dapat diubah setelah dipetakan untuk penggunaan tertentu. Jika Anda perlu mengubah ukuran vertex buffer karena output marching cubes bertambah, Anda harus membuat buffer baru dan memperbarui binding-nya. Tidak ada <code>realloc</code>. Menangani siklus hidup tersebut dengan benar—menghancurkan buffer lama tanpa berbenturan dengan pekerjaan GPU yang masih berjalan—memerlukan pengelolaan fence eksplisit yang tidak ada di WebGL.</p>
<p>Pada bagian 9, kami beralih ke pengerjaan sambungan Transvoxel. Bab tersebut sengaja dimulai dengan sebuah kerangka dasar. Pada tahap ini, kami sudah sepenuhnya memahami bahwa integrasi yang terburu-buru menghasilkan misteri, sedangkan persiapan yang terkendali menghasilkan masalah yang dapat di-debug.</p>
<h2>Teknologi yang dibahas dalam bab ini</h2>
<p><strong>WebGPU.</strong> Penerus WebGL yang menyediakan akses GPU tingkat rendah di browser, lengkap dengan compute shader dan indirect rendering. Dua fitur penting WebGPU untuk dunia terbuka: compute shader memungkinkan pembuatan terrain, penempatan vegetasi, dan culling di sisi GPU; indirect rendering memungkinkan GPU menentukan apa yang perlu digambar berdasarkan output komputasi, sehingga menghilangkan bottleneck CPU dalam scene yang padat. Tersedia di Chrome, Edge, dan Firefox pada desktop. Lihat <a href="/id/guides/browser-3d-open-world-tech#webgpu-the-performance-unlock">WebGPU sebagai pembuka potensi performa</a>.</p>
<p><strong>Three.js Shading Language (TSL).</strong> Sistem shader berbasis node milik Three.js yang menggantikan GLSL/WGSL mentah dengan ekspresi JavaScript yang dapat dikomposisikan. Node TSL seperti <code>texture()</code>, <code>positionWorld</code>, <code>smoothstep()</code>, dan <code>fog()</code> membangun shader graph saat runtime, yang kemudian dikompilasi ke backend yang sesuai (GLSL untuk WebGL atau WGSL untuk WebGPU). TSL memungkinkan logika material ditulis satu kali dan digunakan pada kedua renderer. Node graph dievaluasi pada setiap frame, sehingga uniform dinamis dan percabangan kondisional dapat berfungsi secara alami.</p>
<p><strong>Siklus hidup buffer GPU di WebGPU.</strong> Buffer WebGPU dibuat dengan flag penggunaan tertentu (<code>VERTEX</code>, <code>STORAGE</code>, <code>COPY_DST</code>, dan sebagainya) dan tidak dapat diubah ukurannya setelah dibuat. Jika dispatch marching cubes menghasilkan lebih banyak vertex daripada yang dapat ditampung buffer, Anda harus membuat buffer baru, memperbarui binding, dan menghancurkan buffer lama. Menghancurkan buffer yang masih dirujuk oleh perintah GPU yang sedang berjalan akan menyebabkan error. Pengelolaan fence eksplisit (melalui <code>device.queue.onSubmittedWorkDone()</code>) memastikan bahwa buffer lama tidak dihancurkan sebelum GPU selesai menggunakannya. Disiplin siklus hidup ini tidak ada di WebGL, karena driver mengelola memori secara implisit.</p>
<p><strong>Penguatan bertahap.</strong> Disiplin proses untuk integrasi: tetapkan baseline yang sudah dipastikan berfungsi, tambahkan satu kemampuan pada satu waktu, lalu pastikan lapisan sebelumnya tetap berfungsi setelah setiap penambahan. Pendekatan ini lebih lambat selama satu hari, tetapi menghemat berhari-hari dalam proses debugging berikutnya karena setiap regresi dapat dilacak ke perubahan spesifik yang terkendali. Pola baseline-lalu-bertahap lazim digunakan dalam <a href="/id/guides/browser-3d-open-world-tech#what-we-d-build-first">pengembangan dunia terbuka AAA</a>, ketika sistem diintegrasikan dalam urutan tertentu untuk mengelola risiko.</p>
<hr>
<p>Bagian 8 dari 12.<br>
Sebelumnya: <a href="/id/blog/2026-02-25-open-world-browser-part-07-marching-cubes">Bagian 7 - Marching cubes dan gua nyata pertama</a><br>
Berikutnya: <a href="/id/blog/2026-02-25-open-world-browser-part-09-transvoxel-first-cut">Bagian 9 - Transvoxel dimulai dengan sebuah kerangka dasar</a><br>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 9: Transvoxel dimulai dengan kerangka pengujian]]></title>
            <link>https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-09-transvoxel-first-cut</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-09-transvoxel-first-cut</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Kami tidak langsung menerapkan sambungan secara menyeluruh. Kami terlebih dahulu membangun perangkat uji sambungan, lalu memvalidasi satu sisi menggunakan data referensi.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 9: Transvoxel dimulai dengan kerangka pengujian</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Salah Satu Pendiri Cinevva</em></p>
<p>Baru di sini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan memuat tautan ke semua bagian.</p>
<p>Sambungan adalah tempat kepercayaan diri runtuh.</p>
<p>Semuanya dapat terlihat stabil sampai dua resolusi bertemu. Sebuah chunk pada LOD 0 berada di sebelah chunk pada LOD 1. Mesh keduanya dihasilkan secara terpisah. Pada batas yang sama, posisi vertex tidak cocok karena chunk beresolusi lebih rendah memiliki kerapatan grid setengahnya. Hasilnya adalah retakan yang terlihat, T-junction, dan tepi yang berkedip-kedip.</p>
<p>Algoritma Transvoxel mengatasi masalah ini dengan menghasilkan transition cell khusus di sepanjang sisi batas antara dua chunk dengan resolusi berbeda. Cell ini mengambil sampel dari grid beresolusi tinggi dan rendah secara bersamaan, lalu menghasilkan triangle yang menyatukan kedua permukaan. Algoritma ini menggunakan lookup table tersendiri, terpisah dari tabel marching cubes biasa, dengan 512 kasus transition cell.</p>
<p>Pada tahap ini, kami sudah cukup banyak mendapat luka dari proses integrasi sehingga tahu bahwa implementasinya tidak boleh dilakukan secara terburu-buru.</p>
<p>Spike 15 hanya memiliki satu tugas: membangun perangkat uji sambungan yang dapat kami percaya sebelum menyentuh keseluruhan algoritma. Kami menyiapkan lingkungan terkendali berisi dua chunk dengan data SDF yang telah diketahui, ditempatkan berdampingan pada resolusi berbeda, beserta kontrol visualisasi untuk menampilkan atau menyembunyikan mesh utama, mesh sambungan, wireframe, dan normal secara terpisah.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/15-transvoxel-seam/" title="Kerangka Sambungan Transvoxel Spike 15" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/15-transvoxel-seam/" target="_blank">Buka Spike 15 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=15-transvoxel-seam">Lihat kode sumber</a></p>
<p>Setelah perangkat uji stabil, Spike 16 memvalidasi pembuatan transition cell berbasis tabel pada satu sisi. Kami memilih satu sisi yang sejajar dengan sumbu (batas +X), mengimplementasikan evaluasi transition cell hanya untuk sisi tersebut, lalu membandingkan hasilnya dengan data referensi dari makalah Transvoxel.</p>
<p><a href="/id/spikes/16-transvoxel-face/" target="_blank">Buka Spike 16 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=16-transvoxel-face">Lihat kode sumber</a></p>
<p>Kami sengaja menguji satu sisi pada satu waktu karena pengkabelan transition table memiliki banyak mode kegagalan yang independen. Perhitungan indeks kasus bergantung pada pengambilan sampel vertex yang tepat dari kedua grid. Pengindeksan vertex di dalam transition cell menggunakan skema penomoran yang berbeda dari cell marching cubes biasa. Urutan winding harus konsisten dengan mesh utama, atau backface culling akan menghilangkan triangle sambungan. Jika Anda menguji keenam sisi sekaligus, setiap gejala akan tampak acak. Jika Anda menguji satu sisi secara menyeluruh, kegagalan yang muncul akan lebih bermakna dan dapat di-debug.</p>
<p>Keuntungan halus lainnya dari fase ini adalah investasi pada alat bantu. Sejak awal, kami membuat kontrol visibilitas, rendering khusus sambungan, dan indikator LOD berkode warna. Saat itu, kontrol tersebut terasa seperti beban tambahan. Namun kemudian, ketika berbagai kasus sudut mulai rumit, investasi itu terbayar berkali-kali karena kami dapat mengisolasi secara tepat cell sambungan mana yang bermasalah.</p>
<p>Pada akhir bab ini, kami belum &quot;selesai dengan sambungan.&quot; Namun, kami sudah berada dalam posisi yang memungkinkan bug sambungan dianalisis alih-alih ditakuti.</p>
<p>Di bagian 10, roller coaster yang sesungguhnya dimulai. Sudut dengan LOD campuran, pembalikan winding, bayangan semu akibat overdraw parsial, dan momen-momen ketika Anda yakin algoritmanya salah, lalu menemukan bahwa bug sebenarnya adalah draw range yang membaca melampaui jumlah vertex aktif.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Algoritma Transvoxel.</strong> Dirancang oleh Eric Lengyel (<a href="https://transvoxel.org/">transvoxel.org</a>), Transvoxel memecahkan masalah tersulit dalam LOD terrain volumetrik: sambungan antara chunk dengan resolusi berbeda. Ketika chunk beresolusi tinggi berada di sebelah chunk beresolusi rendah, mesh marching cubes tidak sejajar pada batasnya sehingga menghasilkan retakan yang terlihat. Transvoxel menyisipkan transition cell khusus di sepanjang sisi batas untuk menjembatani perbedaan resolusi dengan triangle tambahan yang cocok dengan kedua sisi. Algoritma ini menggunakan lookup table tersendiri (terpisah dari marching cubes biasa) dengan 512 kasus transition cell, yang disederhanakan menjadi 73 kelas ekuivalensi. Algoritma ini bebas paten dan telah digunakan dalam game yang dirilis (Space Engineers, Astroneer). Lihat <a href="/id/guides/landscape-generation-browser#the-transvoxel-algorithm">panduan landscape kami tentang Transvoxel</a>.</p>
<p><strong>Transition cell.</strong> Cell khusus yang dihasilkan pada sisi di antara dua tingkat LOD. Tidak seperti cell marching cubes biasa yang mengambil sampel dari 8 sudut pada satu grid, transition cell mengambil sampel dari grid beresolusi tinggi dan rendah secara bersamaan. Sisi beresolusi tinggi memiliki $3 \times 3 = 9$ titik sampel, sedangkan sisi beresolusi rendah memiliki $2 \times 2 = 4$. Sembilan sampel tersebut menghasilkan $2^9 = 512$ kasus mentah dalam algoritma ini, yang menyusut menjadi 73 triangulasi berbeda setelah rotasi dan pencerminan diperhitungkan. Klasifikasi dan triangulasi cell menggunakan tabel khusus yang menghasilkan triangle penghubung vertex pada kedua resolusi. Skema penomoran vertex-nya berbeda dari cell MC biasa, yang sering menjadi sumber bug implementasi.</p>
<p><strong>Sambungan transisi LOD.</strong> Batas antara dua resolusi mesh tempat ketidakcocokan topologi menimbulkan artefak visual. Tanpa penyatuan, chunk LOD 0 (grid 1 m) di sebelah chunk LOD 1 (grid 2 m) menghasilkan T-junction: mesh halus memiliki vertex di sepanjang batas yang tidak dimiliki mesh kasar, sehingga menimbulkan retakan yang dapat ditembus cahaya. Transvoxel, geomorphing, dan geometri skirt adalah tiga pendekatan untuk memperbaiki sambungan tersebut. Untuk terrain volumetrik, Transvoxel merupakan solusi standar karena geomorphing hanya dapat digunakan pada heightmap. Lihat <a href="/id/guides/landscape-generation-browser#lod-for-volumetric-terrain">LOD untuk terrain volumetrik</a>.</p>
<hr>
<p>Bagian 9 dari 12.<br>
Sebelumnya: <a href="/id/blog/2026-02-25-open-world-browser-part-08-webgpu-integration">Bagian 8 - Integrasi tanpa kehilangan baseline kami</a><br>
Berikutnya: <a href="/id/blog/2026-02-25-open-world-browser-part-10-seam-chaos">Bagian 10 - Kekacauan sambungan dan pertarungan bos di sudut</a><br>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 10: Kekacauan sambungan dan pertarungan bos di sudut]]></title>
            <link>https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-10-seam-chaos</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-10-seam-chaos</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 17 hingga 22 menjadi titik ketika teori berhadapan dengan kasus-kasus ekstrem. Kami memburu bug urutan winding, segitiga yang hilang, hantu overdraw, dan logika fallback hibrida.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 10: Kekacauan sambungan dan pertarungan bos di sudut</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Salah Satu Pendiri Cinevva</em></p>
<p>Baru mengikuti seri ini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan memuat tautan ke semua bagian.</p>
<p>Jika bagian-bagian sebelumnya terasa sistematis, bab ini terasa seperti pertempuran.</p>
<p>Spike 17 hingga 22 adalah era kasus ekstrem kami. Marching cubes LOD ganda, sambungan batas antara heightmap dan MC, chunk sudut beresolusi campuran tempat tiga atau empat tingkat LOD bertemu, pembuatan sambungan di GPU, serta perilaku mode fallback. Setiap spike menangani skenario kegagalan tertentu yang telah kami temui atau perkirakan.</p>
<p>Spike 17 menguji marching cubes ganda dengan dua tingkat LOD yang aktif secara bersamaan. Tantangannya adalah tetangga sebuah chunk dapat memiliki resolusi berbeda pada sisi-sisi yang berbeda. Logika sel transisi dari Spike 16 berfungsi untuk satu sisi dalam satu waktu, tetapi ketika sebuah chunk memerlukan sel transisi pada beberapa sisi, pengelolaan buffer vertex menjadi rumit. Sel transisi setiap sisi harus dibuat dan ditambahkan tanpa menimpa sel dari sisi lainnya.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/19-transvoxel-corner-grid/" title="Spike 19: Grid Sudut Transvoxel" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/19-transvoxel-corner-grid/" target="_blank">Buka Spike 19 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=19-transvoxel-corner-grid">Lihat kode sumber</a></p>
<p>Musuh pertama yang terus muncul adalah urutan winding. Beberapa kali kami mengira ada masalah topologi, tetapi ternyata masalahnya ada pada orientasi. Backface culling menghilangkan segitiga sambungan yang valid karena winding-nya terbalik terhadap mesh utama. Akar masalahnya sama, tetapi gejala visualnya berbeda-beda tergantung sudut kamera. Perbaikannya adalah menerapkan konvensi winding yang konsisten dalam kode emisi sel transisi dan memverifikasinya dengan pengalih material dua sisi.</p>
<p>Musuh kedua adalah rasa percaya diri palsu akibat hasil yang hanya benar sebagian. Sebuah sambungan bisa terlihat sempurna dari satu sudut kamera, lalu rusak ketika peran LOD bertukar antara chunk beresolusi lebih tinggi dan lebih rendah. Sel transisi bersifat asimetris. Sel tersebut mengambil sampel dari sisi beresolusi tinggi dan sisi beresolusi rendah dengan cara yang berbeda. Jika logika “sisi mana yang beresolusi tinggi” terbalik untuk satu konfigurasi, bug hanya akan terlihat ketika kamera bergerak ke posisi tertentu.</p>
<p>Lalu terjadilah salah satu pemulihan favorit kami. Kami sedang memburu artefak sambungan yang terpotong pada tile heightmap dan menyalahkan logika transisi. Dua hari habis untuk itu. Penyebab sebenarnya adalah overdraw usang. Geometri beresolusi lebih tinggi dari frame sebelumnya masih tertinggal di bagian akhir buffer setelah chunk diturunkan ke LOD yang lebih rendah. Rentang gambar masih menggunakan jumlah vertex lama yang lebih besar. Begitu kami membatasi rentang gambar ke jumlah vertex aktif yang dilaporkan oleh penghitung atomik milik compute shader, “masalah sambungan misterius” itu menghilang.</p>
<p>Itu menjadi pengingat yang sangat baik bahwa bug rendering sering menyamar sebagai bug pembuatan mesh. Geometrinya sebenarnya sudah benar sejak awal. Draw call hanya membaca melewati akhir data yang valid.</p>
<p>Pada Spike 22, kami menguji fallback hibrida yang memungkinkan chunk beralih dari marching cubes ke mode heightmap dalam kondisi tertentu, misalnya ketika chunk tidak memiliki edit volumetrik dan berada cukup jauh dari kamera. Ini memberi kami pendekatan yang lebih praktis daripada kebijakan serba-atau-tidak-sama-sekali. Chunk dekat kamera yang telah diedit menggunakan MC demi kebebasan volumetrik. Chunk jauh yang belum diedit menggunakan heightmap demi efisiensi.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/22-gpu-mc-heightmap-fallback/" title="Spike 22: Fallback Heightmap MC" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/22-gpu-mc-heightmap-fallback/" target="_blank">Buka Spike 22 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=22-gpu-mc-heightmap-fallback">Lihat kode sumber</a></p>
<p>Bab ini adalah turunan curam dalam wahana roller coaster. Menjengkelkan sekaligus produktif. Banyak perbaikannya berukuran kecil, terkadang hanya satu baris yang mengubah operator perbandingan atau offset. Namun, pemahaman yang dihasilkannya tentang interaksi antara transisi LOD, pengelolaan buffer, dan rentang gambar sama sekali tidak kecil.</p>
<p>Di bagian 11, kami membahas lapisan stabilisasi yang muncul setelah kekacauan ini: mode chunk berbasis kebijakan dan peralihan dari perbaikan bug secara reaktif menuju aturan sistem yang eksplisit.</p>
<h2>Teknologi yang dibahas dalam bab ini</h2>
<p><strong>Marching cubes LOD ganda.</strong> Menjalankan marching cubes pada dua tingkat resolusi secara bersamaan, dengan sel transisi yang menyatukan batasnya. Tantangannya adalah tetangga sebuah chunk dapat memiliki resolusi berbeda pada sisi-sisi yang berbeda, sehingga setiap sisi memerlukan pembuatan sel transisi secara independen. Sel transisi dari setiap sisi ditambahkan ke buffer vertex tanpa menimpa sel dari sisi lainnya. Penghitung atomik melacak jumlah total vertex aktif di seluruh sisi.</p>
<p><strong>Urutan winding.</strong> Urutan vertex dalam setiap segitiga menentukan sisi mana yang menjadi permukaan “depan”. Winding yang konsisten—biasanya berlawanan arah jarum jam jika dilihat dari luar—diperlukan untuk backface culling. Ketika sel transisi menghasilkan segitiga, winding-nya harus mengikuti konvensi mesh utama. Jika terbalik, backface culling akan menghilangkan segitiga sambungan yang valid, sehingga dari sudut kamera tertentu terlihat seperti ada permukaan yang hilang. Teknik debugging yang umum adalah mengaktifkan <code>side: THREE.DoubleSide</code> pada material untuk memastikan apakah artefak tersebut disebabkan oleh masalah winding atau celah topologi yang sebenarnya.</p>
<p><strong>Fallback dari heightmap ke MC.</strong> Mode chunk hibrida tempat chunk yang jauh atau belum diedit menggunakan medan heightmap—murah dan berupa permukaan datar—sedangkan chunk yang dekat atau telah diedit menggunakan marching cubes—bersifat volumetrik dan mendukung gua. Keputusan fallback bergantung pada jarak dari kamera dan apakah chunk memuat edit SDF. Sambungan antara chunk heightmap dan chunk MC memerlukan geometri transisinya sendiri, mirip dengan Transvoxel, tetapi menjembatani dua representasi berbeda alih-alih dua tingkat LOD. Lihat <a href="/id/guides/landscape-generation-browser#hybrid-heightmap-base--volumetric-overlays">heightmap hibrida + overlay volumetrik</a>.</p>
<p><strong>Rentang gambar dan penghitung atomik.</strong> Dalam pembuatan mesh berbasis GPU, compute shader menulis vertex ke dalam buffer dan menaikkan penghitung atomik untuk melacak jumlah vertex yang dihasilkan. Draw call harus menggunakan penghitung ini sebagai jumlah vertex, bukan kapasitas buffer. Jika rentang gambar tidak dibatasi ke jumlah aktif, vertex usang dari frame sebelumnya—yang masih tertinggal di bagian akhir buffer—akan menghasilkan geometri hantu: serpihan tipis dan segitiga berkedip yang tampak seperti kesalahan topologi, tetapi sebenarnya merupakan artefak rendering akibat pembacaan yang melewati data valid.</p>
<hr>
<p>Bagian 10 dari 12.<br>
Sebelumnya: <a href="/id/blog/2026-02-25-open-world-browser-part-09-transvoxel-first-cut">Bagian 9 - Transvoxel dimulai dengan sebuah kerangka</a><br>
Berikutnya: <a href="/id/blog/2026-02-25-open-world-browser-part-11-policy-modes">Bagian 11 - Mode berbasis kebijakan, bukan mode yang di-hardcode</a><br>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 11: Mode kebijakan, bukan mode yang di-hardcode]]></title>
            <link>https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-11-policy-modes</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-11-policy-modes</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 23 mengalihkan kami dari perbaikan reaktif menuju kebijakan eksplisit. LOD berbasis jarak, peralihan HM/MC berbasis pengeditan, dan kontrol debugging sambungan yang lebih baik.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 11: Mode kebijakan, bukan mode yang di-hardcode</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru mengikuti seri ini? Baca <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan tersebut menjelaskan apa itu spike dan menautkan semua bagiannya.</p>
<p>Setelah bab tentang kekacauan sambungan, kami harus berhenti bereaksi dan mulai mengatur sistem.</p>
<p>Spike 23 mengganti perilaku ad hoc dengan aturan kebijakan yang eksplisit. Alih-alih setiap chunk bertindak berdasarkan apa pun yang disarankan oleh status lokalnya, kini sistem kebijakan terpusatlah yang mengambil keputusan. Level LOD mana yang didapat chunk ini? Apakah chunk dirender sebagai heightmap atau marching cubes? Apakah chunk memerlukan sel transisi, dan pada sisi mana? Jawabannya berasal dari fungsi kebijakan yang mengevaluasi jarak ke kamera, riwayat pengeditan, dan status resolusi chunk tetangga.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/23-policy-chunk-modes/" title="Spike 23: Mode Kebijakan Chunk" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/23-policy-chunk-modes/" target="_blank">Buka Spike 23 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=23-policy-chunk-modes">Lihat kode sumber</a></p>
<p>Penetapan LOD berbasis jarak menggunakan cincin konsentris di sekitar kamera, serupa dengan konsep clipmap tetapi diterapkan pada grid chunk. Chunk cincin 0 mendapatkan MC beresolusi penuh. Cincin 1 mendapatkan MC beresolusi setengah. Cincin 2 dan seterusnya menggunakan mode heightmap. Batasan ketetanggaan sangat penting: untuk setiap dua chunk yang bertetangga, kami mensyaratkan $|L_i - L_j| \le 1$. Rasio resolusi pada sebuah sisi adalah $2^{|L_i - L_j|}$, dan tabel transisi Transvoxel hanya didefinisikan untuk kasus 2:1 ($|L_i - L_j| = 1$). Lompatan 2 level akan membutuhkan transisi 4:1 yang tidak dapat direpresentasikan oleh tabel tersebut, sehingga kebijakan memaksa chunk dengan detail lebih rendah untuk ditingkatkan hingga batasan terpenuhi.</p>
<p>Logika peralihan HM/MC memeriksa bitmap pengeditan setiap chunk. Jika sebuah chunk memiliki pengeditan volumetrik apa pun (gua, terowongan, pahatan medan), chunk tersebut tetap berada dalam mode MC terlepas dari jaraknya. Chunk yang belum diedit dapat beralih ke mode heightmap ketika berada cukup jauh. Pendekatan hibrida ini memberi kami kebebasan volumetrik di tempat yang penting dan efisiensi di tempat yang tidak memerlukannya.</p>
<p>Dari luar, spike ini tampak lebih kecil dibandingkan beberapa spike sebelumnya. Dalam praktiknya, ini merupakan peningkatan besar terhadap kenyamanan pengembangan.</p>
<p>Ketika sistem dapat menjelaskan mengapa sebuah chunk beralih mode, Anda tidak perlu menghabiskan banyak waktu untuk menebak. Kami menambahkan overlay berkode warna: hijau untuk chunk heightmap, biru untuk chunk MC, dan oranye untuk sisi dengan transisi aktif. Ketika visibilitas sambungan memiliki kontrol render khusus, ambiguitas dalam debugging visual berkurang. Ketika rentang draw secara eksplisit dikaitkan dengan jumlah vertex aktif dari sistem kebijakan, bayangan geometri usang tidak lagi menghabiskan waktu Anda sepanjang sore.</p>
<p>Kami juga merombak perilaku kamera dalam spike ini. Spike sebelumnya memiliki kontrol orbit sederhana yang cukup untuk mengambil tangkapan layar, tetapi tidak berguna untuk mereproduksi bug. Spike 23 menambahkan kamera terbang WASD dengan kecepatan yang dapat dikonfigurasi, tombol pengunci ketinggian, dan tampilan posisi. Kedengarannya sepele. Namun, inilah perbedaan antara &quot;Saya melihat bug di suatu tempat dekat punggung bukit itu&quot; dan &quot;Bug muncul pada posisi (142, 12, -67) saat menghadap barat laut.&quot;</p>
<p>Wawasan utama dari bab ini adalah bahwa kebijakan tidak mengurangi kompleksitas. Kebijakan menata kompleksitas. Jumlah kasus ekstrem yang ada tetap sama. Namun, kini setiap kasus ekstrem memiliki nama, kondisi pemicu, dan lokasi dalam kode tempat Anda dapat memasang breakpoint. Itu adalah jenis keberhasilan yang berbeda, dan hal inilah yang menentukan apakah suatu sistem dapat terus berkembang atau runtuh akibat bebannya sendiri.</p>
<p>Pada akhir Spike 23, kami memiliki lapisan perilaku medan dekat yang cukup mudah diprediksi untuk dihubungkan ke strategi cincin clipmap medan jauh tanpa terus-menerus mengkhawatirkan bug interaksi.</p>
<p>Pada bagian 12, kami membahas Spike 24, ketika transisi cincin, kabut skybox, dan integrasi shader pada tingkat versi Three.js menutup bab proyek ini.</p>
<h2>Teknologi yang dibahas dalam bab ini</h2>
<p><strong>Kebijakan LOD berbasis jarak.</strong> Fungsi terpusat yang menetapkan level LOD dan mode rendering untuk setiap chunk berdasarkan jarak ke kamera, riwayat pengeditan, dan status chunk tetangga. Cincin jarak konsentris menentukan LOD dasar: cincin 0 = MC beresolusi penuh, cincin 1 = MC beresolusi setengah, cincin 2+ = mode heightmap. Fungsi kebijakan dijalankan setiap frame saat kamera bergerak dan memicu transisi chunk. Ini menggantikan keputusan ad hoc per chunk dengan sistem aturan yang mudah diprediksi dan di-debug. Lihat <a href="/id/guides/landscape-generation-browser#gpu-driven-lod-with-webgpu">pemilihan LOD berbasis GPU</a> untuk padanannya dalam compute shader.</p>
<p><strong>Batasan ketetanggaan.</strong> Algoritma Transvoxel hanya menangani rasio resolusi 2:1. Jika dua chunk yang bertetangga berbeda lebih dari satu level LOD (misalnya, LOD 0 di sebelah LOD 2), tabel transisi tidak dapat menghasilkan geometri sambungan yang valid. Sistem kebijakan menerapkan batasan ini dengan meningkatkan chunk yang memiliki detail lebih rendah ketika selisih LOD melebihi 1. Propagasi batasan ini dapat berantai: peningkatan satu chunk mungkin memaksa chunk tetangganya untuk ikut ditingkatkan. Implementasinya berupa pass iteratif sederhana yang konvergen dalam 2–3 iterasi untuk konfigurasi grid pada umumnya.</p>
<p><strong>Bitmap pengeditan untuk pemilihan mode.</strong> Setiap chunk menyimpan bitmap yang mencatat apakah chunk tersebut berisi pengeditan SDF volumetrik (gua, terowongan, pahatan). Chunk dengan pengeditan apa pun tetap berada dalam mode marching cubes terlepas dari jaraknya, sehingga modifikasi kreator tetap terjaga. Chunk yang belum diedit beralih ke mode heightmap ketika cukup jauh dari kamera, sehingga menghemat komputasi dan memori. Bitmap ini berupa satu flag per chunk, tetapi dapat diperluas untuk melacak kepadatan pengeditan agar keputusan mode menjadi lebih terperinci.</p>
<p><strong>Overlay visualisasi debugging.</strong> Rendering chunk berkode warna dengan hijau = mode heightmap, biru = mode MC, dan oranye = sisi dengan transisi aktif. Overlay per chunk dilengkapi angka level LOD, label mode, dan tombol wireframe. Ini adalah alat pengembangan, bukan fitur yang dirilis, tetapi manfaatnya terus terasa saat men-debug transisi LOD dan artefak sambungan. Jika dipadukan dengan kamera terbang WASD yang menampilkan posisi dunia secara tepat, alat ini mengubah &quot;Saya melihat bug di suatu tempat&quot; menjadi &quot;Bug muncul pada (142, 12, -67) dengan konfigurasi LOD ini.&quot;</p>
<hr>
<p>Bagian 11 dari 12.<br>
Sebelumnya: <a href="/id/blog/2026-02-25-open-world-browser-part-10-seam-chaos">Bagian 10 - Kekacauan sambungan dan pertarungan bos di sudut</a><br>
Berikutnya: <a href="/id/blog/2026-02-25-open-world-browser-part-12-lessons">Bagian 12 - Cincin, kabut langit, dan apa yang akan kami lakukan lagi</a><br>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Membangun dunia terbuka di browser, bagian 12: Cincin, kabut langit, dan apa yang akan kami lakukan lagi]]></title>
            <link>https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-12-lessons</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-part-12-lessons</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Spike 24 menutup bab ini dengan transisi cincin clipmap, integrasi kabut skybox, dan satu daftar panjang pelajaran yang diperoleh dengan susah payah.]]></description>
            <content:encoded><![CDATA[<h1>Membangun dunia terbuka di browser, bagian 12: Cincin, kabut langit, dan apa yang akan kami lakukan lagi</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Baru di sini? Gunakan <a href="/id/blog/2026-02-25-open-world-browser-series-guide">panduan seri</a>. Panduan ini menjelaskan apa itu spike dan menyediakan tautan ke semua bagian.</p>
<p>Spike 24 awalnya seharusnya hanya &quot;menambahkan cincin clipmap ke medan.&quot; Namun, spike ini berubah menjadi penutup besar yang sekaligus menyentuh rendering, shader, infrastruktur modul, dan integrasi visual.</p>
<p>Tugas utama untuk medan adalah menghasilkan cincin clipmap konsentris di vertex shader. Setiap cincin merupakan mesh grid datar yang berpusat pada kamera, dengan vertex yang digeser berdasarkan sampel heightmap. Cincin terdalam menggunakan resolusi penuh. Setiap cincin berikutnya menggandakan jarak antar-vertex dan mencakup area yang lebih luas. Bagian tersulitnya adalah batas antarcincin: ketika cincin beresolusi tinggi bertemu dengan cincin beresolusi rendah, vertex tepi pada mesh yang lebih rapat harus menempel ke titik tengah tepi mesh yang lebih kasar. Kami melakukan morphing tepi 2:1 dengan mendeteksi vertex batas (vertex dengan koordinat grid ganjil di sepanjang tepi cincin), lalu menempelkan ketinggiannya ke titik tengah dua tetangga genapnya, $h = \tfrac{1}{2}(h_\text{left} + h_\text{right})$. Itulah tepatnya posisi tepi tunggal dari cincin kasar, sehingga tepi halus dan kasar menggambarkan garis yang sama. Hasilnya adalah sambungan kedap tanpa geometri transisi.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0;border:1px solid rgba(255,255,255,0.12)">
<iframe src="/id/spikes/24-gpu-clipmap-rings/" title="Cincin Clipmap dan Kabut Langit Spike 24" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background:#000" loading="lazy" allowfullscreen></iframe>
</div>
<p><a href="/id/spikes/24-gpu-clipmap-rings/" target="_blank">Buka Spike 24 di tab baru ↗</a> · <a href="/id/blog/spike-source?spike=24-gpu-clipmap-rings">Lihat kode sumber</a></p>
<p>Berikutnya adalah integrasi kabut dan langit. Kami ingin medan yang jauh memudar ke warna langit sebenarnya, bukan ke warna konstan yang datar. Itu berarti shader kabut perlu mengetahui warna langit pada arah setiap fragmen. Kami memuat tekstur skybox HDR equirectangular dan mengambil sampelnya di fragment shader menggunakan arah pandang dari kamera ke fragmen, yang dikonversi menjadi koordinat UV equirectangular melalui node <code>equirectUV</code> milik TSL. Faktor kabut dihitung berdasarkan jarak menggunakan <code>positionView.z.negate()</code> untuk kedalaman dalam ruang kamera, lalu dipadukan dengan <code>smoothstep</code> antara jarak dekat dan jauh.</p>
<p>Pengkabelan modul ternyata lebih menjengkelkan daripada bagian geometri mana pun. Kami meningkatkan versi ke Three.js 0.183.1, yang merombak keluaran build-nya. Import <code>three/tsl</code> harus mengarah ke <code>three.tsl.js</code>, sementara secara internal TSL mengimpor <code>three/webgpu</code> sebagai bare specifier. Kedua pemetaan tersebut harus dituliskan secara eksplisit di import map HTML. Jika salah satunya tidak ada, muncul galat samar &quot;does not provide an export&quot; atau &quot;failed to resolve module specifier&quot; tanpa petunjuk pemetaan mana yang salah. Setelah keduanya dimasukkan ke import map, graph shader berhasil dimuat dengan benar.</p>
<p>Kami juga mengalami masalah orientasi skybox yang membuat tekstur dirender terbalik. Solusinya adalah mengatur <code>flipY = true</code> pada tekstur equirectangular. Ini merupakan nilai default Three.js untuk tekstur yang dimuat, tetapi di kode awal kami nilainya diatur ke <code>false</code>.</p>
<p>Implementasi kabut awal mengambil sampel langit dari arah yang hampir konstan, sehingga menghasilkan pita tipis berwarna cakrawala alih-alih gradasi alami. Solusinya adalah menghitung arah dunia aktual dari kamera ke fragmen per piksel menggunakan <code>positionWorld.sub(cameraPosition).normalize()</code>, lalu meneruskannya ke <code>equirectUV</code> untuk mengambil warna kabut. Dengan demikian, fragmen medan memudar ke warna langit yang benar-benar berada di belakangnya, sehingga terlihat tepat dari sudut kamera mana pun.</p>
<p>Di balik semua perbaikan individual itu, hasil utamanya tetap tercapai. Kini kami memiliki sistem medan yang menggabungkan pengeditan volumetrik jarak dekat (marching cubes dengan sambungan Transvoxel), chunk heightmap jarak menengah, dan cincin clipmap jarak jauh, yang semuanya diatur oleh lapisan kebijakan untuk menentukan mode, LOD, dan perilaku transisi.</p>
<p>Jika saya harus menyebutkan pola yang akan saya ulangi di proyek berikutnya, inilah daftarnya:</p>
<p>Mulailah dengan spike risiko sebelum mengerjakan fitur. Spike 1 menjawab pertanyaan &quot;apakah kita bisa melakukan rendering dengan cukup cepat&quot; bahkan sebelum kami berinvestasi dalam pipeline konten.</p>
<p>Bekukan baseline yang sudah terbukti baik sebelum melakukan lompatan integrasi. Spike 13 dan 14 menghemat waktu berhari-hari yang mungkin kami habiskan untuk melacak regresi dengan bisect.</p>
<p>Terapkan kebijakan dan observabilitas sebelum memulai maraton optimasi. Spike 23 mengubah bug misterius menjadi kondisi bernama dengan aturan pemicu.</p>
<p>Lakukan pengujian saat bergerak, bukan melalui tangkapan layar. Lompatan clipmap, kedipan sambungan, dan sendatan streaming tidak terlihat pada frame diam.</p>
<p>Ukur biaya waktu frame untuk setiap fitur, bukan FPS rata-rata. Nilai rata-rata menyembunyikan lonjakan yang benar-benar dirasakan pengguna.</p>
<p>Dan publikasikan bagian-bagian yang berantakan. Langkah-langkah yang salah, perburuan bayangan buffer usang, dua hari menyalahkan logika transisi ketika ternyata draw range yang salah. Justru dari bagian-bagian itulah orang benar-benar bisa belajar.</p>
<h2>Pemeriksaan realitas eksternal: devlog Vuntra City</h2>
<p>Setelah menyelesaikan seri ini, kami meninjau devlog <code>@VuntraCity</code> sebagai pemeriksaan implementasi eksternal terhadap asumsi kami sendiri mengenai dunia terbuka. Proyek tersebut merupakan proyek UE5 native, bukan stack browser, tetapi pola sistemnya cukup serupa sehingga perbandingannya tetap berguna.</p>
<p>Sinyal pertama adalah bahwa kecepatan pergerakan harus diperlakukan sebagai kontrol streaming, bukan sekadar bagian gameplay. Di Vuntra City, transportasi berkecepatan tinggi sengaja diarahkan melewati bagian atas sebagian besar interior, dan jangkauan detail disesuaikan dengan kecepatan gerakan untuk menghindari pergantian spawn yang berlebihan dan kemacetan (<a href="https://www.youtube.com/watch?v=KKeBElJS6-M">sistem transportasi</a>, <a href="https://www.youtube.com/watch?v=aPuYXyJet38">teknik performa</a>). Ini sejalan dengan arah lapisan kebijakan kami: mode pergerakan harus secara langsung memengaruhi radius chunk, aktivasi interior, dan jumlah pekerjaan yang diizinkan per frame.</p>
<p>Sinyal kedua adalah arsitektur. Sistem peta dan alamat mereka memerlukan pemisahan topologi dunia dari objek yang dirender agar kueri global dapat dijalankan untuk wilayah yang belum dimuat (<a href="https://www.youtube.com/watch?v=6dLn1GQpu2c">peta dan alamat</a>). Pemisahan yang sama juga kami perlukan di browser untuk pencarian dunia, penentuan rute misi, pemindaian moderasi, dan pengindeksan POI tanpa memaksakan jalur data yang terikat pada rendering.</p>
<p>Sinyal ketiga adalah pembagian tingkat simulasi. Desain mereka untuk satu juta NPC menjaga state jadwal kasar tetap ringan dan global, lalu hanya mengalokasikan anggaran perilaku yang mahal di dekat pemain (<a href="https://www.youtube.com/watch?v=nBV0yAAJUf0">ikhtisar satu juta NPC</a>, <a href="https://www.youtube.com/watch?v=eUi7DB1ar3s">pembahasan mendalam sistem</a>). Hal ini memperkuat model simulasi kami sendiri yang mengutamakan AOI, dengan fidelitas jarak dekat dan determinisme jarak jauh sebagai kebutuhan terpisah yang memiliki anggaran masing-masing.</p>
<p>Sinyal keempat adalah kualitas desain, bukan skala mentah. Momen eksplorasi terbaik mereka berasal dari distribusi berbobot, pencilan langka, dan petunjuk navigasi diegetik, bukan dari overlay UI yang terus-menerus ditampilkan (<a href="https://www.youtube.com/watch?v=4MZ5-KQW3pc">catatan lingkungan prosedural</a>, <a href="https://www.youtube.com/watch?v=ixR1hqZJlv4">alur tanpa minimap</a>). Bagi kami, ini menjadi pengingat bahwa sistem teknis harus disetel untuk menghasilkan variasi yang dapat ditemukan, bukan sekadar throughput maksimum.</p>
<h2>Teknologi yang dirujuk dalam bab ini</h2>
<p><strong>Geometri cincin clipmap.</strong> Setiap cincin merupakan mesh grid datar yang berpusat pada kamera, dengan vertex yang digeser berdasarkan sampel heightmap. Cincin terdalam menggunakan resolusi penuh. Setiap cincin berikutnya menggandakan jarak antar-vertex dan mencakup area yang lebih luas. Bagian tersulitnya adalah batas: ketika cincin beresolusi tinggi bertemu dengan cincin beresolusi rendah, vertex tepi pada mesh yang lebih rapat menempel ke titik tengah tepi mesh yang lebih kasar. Teknik ini berasal dari makalah SIGGRAPH 2004 karya Losasso dan Hoppe (<a href="https://hhoppe.com/geomclipmap.pdf">PDF</a>) dan dijelaskan secara terperinci dalam <a href="https://developer.nvidia.com/gpugems/gpugems2/part-i-geometric-complexity/chapter-2-terrain-rendering-using-gpu-based-geometry">GPU Gems 2, Bab 2</a>. Lihat <a href="/id/guides/landscape-generation-browser#geometry-clipmaps">panduan lanskap kami mengenai geometry clipmap</a>.</p>
<p><strong>Morphing tepi 2:1.</strong> Pada batas antara dua cincin clipmap, cincin yang lebih rapat memiliki vertex di posisi yang tidak dimiliki cincin yang lebih kasar. Vertex batas dengan koordinat grid ganjil di sepanjang tepi cincin dideteksi, lalu ketinggiannya diinterpolasi di antara dua vertex genap di sebelahnya. Hasilnya adalah sambungan kedap tanpa geometri transisi khusus. Interpolasi dijalankan di vertex shader: <code>morphedHeight = mix(heightLeft, heightRight, 0.5)</code> untuk vertex batas, menggunakan kerangka geomorphing yang sama seperti yang dijelaskan dalam <a href="/id/guides/landscape-generation-browser#geomorphing-pop-free-lod-transitions">panduan kami</a>.</p>
<p><strong>Pemetaan skybox equirectangular.</strong> Satu gambar 2D yang memetakan seluruh bola arah langit menggunakan proyeksi garis bujur-garis lintang. Sumbu horizontal mencakup 0–360 derajat, sedangkan sumbu vertikal mencakup 0–180 derajat. Arah pandang ternormalisasi $\hat{d} = (d_x, d_y, d_z)$ dikonversi menjadi koordinat UV dengan membaca garis bujur dan garis lintangnya:</p>
<p>$$
u = \frac{1}{2} + \frac{\operatorname{atan2}(d_z,, d_x)}{2\pi}, \qquad v = \frac{1}{2} - \frac{\arcsin(d_y)}{\pi}
$$</p>
<p>Di Three.js, pengaturan <code>texture.mapping = EquirectangularReflectionMapping</code> bersama <code>SRGBColorSpace</code> mengaktifkan tekstur tersebut sebagai latar scene. Di TSL, <code>equirectUV(direction)</code> menerapkan konversi yang sama, mengubah arah pandang 3D menjadi koordinat UV 2D untuk mengambil sampel tekstur.</p>
<p><strong>Warna kabut per fragmen dari langit.</strong> Kabut standar memadukan fragmen menuju satu warna konstan. Untuk scene dengan skybox terperinci, hasilnya terlihat salah karena warna langit berbeda-beda berdasarkan arah. Solusinya adalah menghitung arah dunia dari kamera ke fragmen per piksel (<code>positionWorld.sub(cameraPosition).normalize()</code>), lalu mengambil sampel skybox pada arah tersebut sebagai warna kabut. Setiap fragmen memudar menuju warna langit yang benar-benar berada di belakangnya, menghasilkan perpaduan yang tepat dari sudut kamera mana pun. Faktor kabut menggunakan <code>smoothstep(nearDist, farDist, viewDepth)</code> dengan <code>positionView.z.negate()</code> untuk kedalaman dalam ruang kamera.</p>
<p><strong>Import map untuk modul ES.</strong> Mekanisme bawaan browser (<code>&lt;script type=&quot;importmap&quot;&gt;</code>) yang memetakan bare module specifier (seperti <code>three/tsl</code>) ke URL sebenarnya. Ketika Three.js 0.183.1 merombak keluaran build-nya, <code>three/tsl</code> harus mengarah ke <code>three.tsl.js</code>, sementara secara internal TSL mengimpor <code>three/webgpu</code> sebagai bare specifier. Kedua pemetaan harus dituliskan secara eksplisit di import map, atau browser akan menghasilkan galat &quot;does not provide an export&quot; atau &quot;failed to resolve module specifier&quot;.</p>
<h2>Bacaan lebih lanjut</h2>
<p>Untuk pembahasan lebih mendalam mengenai teknologi yang digunakan di sepanjang seri ini, lihat panduan pendamping kami:</p>
<ul>
<li><a href="/id/guides/landscape-generation-browser">Pembuatan Lanskap dengan LOD Dinamis dan Streaming untuk Dunia Terbuka di Browser</a> membahas heightmap, SDF, marching cubes, Transvoxel, geometry clipmap, geomorphing, arsitektur streaming, material medan, dan rendering vegetasi.</li>
<li><a href="/id/guides/browser-3d-open-world-tech">Teknologi Dunia Terbuka 3D di Browser untuk Dunia Kreator Multipemain</a> membahas stack rendering, WebGPU, fisika, jaringan, arsitektur multipemain, serta pelajaran dari Skyrim, The Witcher 3, Breath of the Wild, dan GTA V.</li>
</ul>
<p>Terima kasih telah mengikuti perjalanan dua belas bagian ini.</p>
<p>Bagian 1: <a href="/id/blog/2026-02-25-open-world-browser-part-01-risk-first">Kami memulainya dengan mencoba menghancurkannya</a><br>
Bagian 2: <a href="/id/blog/2026-02-25-open-world-browser-part-02-worker-physics">Fisika worker dan kekhawatiran akan input lag</a><br>
Bagian 3: <a href="/id/blog/2026-02-25-open-world-browser-part-03-the-unflashy-spikes">Spike yang tidak mencolok tetapi menyelamatkan kami</a><br>
Bagian 4: <a href="/id/blog/2026-02-25-open-world-browser-part-04-streaming-before-fancy">Streaming sebelum medan yang canggih</a><br>
Bagian 5: <a href="/id/blog/2026-02-25-open-world-browser-part-05-budgeting-the-pretty">Mengatur anggaran untuk bagian yang indah</a><br>
Bagian 6: <a href="/id/blog/2026-02-25-open-world-browser-part-06-clipmaps">Clipmap mengubah jalan cerita</a><br>
Bagian 7: <a href="/id/blog/2026-02-25-open-world-browser-part-07-marching-cubes">Marching cubes dan gua nyata pertama</a><br>
Bagian 8: <a href="/id/blog/2026-02-25-open-world-browser-part-08-webgpu-integration">Integrasi tanpa kehilangan baseline kami</a><br>
Bagian 9: <a href="/id/blog/2026-02-25-open-world-browser-part-09-transvoxel-first-cut">Transvoxel dimulai dengan kerangka awal</a><br>
Bagian 10: <a href="/id/blog/2026-02-25-open-world-browser-part-10-seam-chaos">Kekacauan sambungan dan pertarungan bos di sudut</a><br>
Bagian 11: <a href="/id/blog/2026-02-25-open-world-browser-part-11-policy-modes">Mode kebijakan, bukan mode hardcode</a></p>
<hr>
<p>Bagian 12 dari 14.<br>
Sebelumnya: <a href="/id/blog/2026-02-25-open-world-browser-part-11-policy-modes">Bagian 11 - Mode kebijakan, bukan mode hardcode</a><br>
Berikutnya: <a href="/id/blog/2026-04-13-open-world-browser-part-13-terrain-sculpting">Bagian 13 - Memahat medan dan matinya fungsi matematika</a><br>
Panduan seri: <a href="/id/blog/2026-02-25-open-world-browser-series-guide">/id/blog/2026-02-25-open-world-browser-series-guide</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Panduan seri dunia terbuka di browser]]></title>
            <link>https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-series-guide</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-02-25-open-world-browser-series-guide</guid>
            <pubDate>Wed, 25 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Urutan baca untuk seri dunia terbuka di browser yang terdiri dari 29 bagian, ditambah glosarium spike dalam bahasa sederhana dan peta demo langsung.]]></description>
            <content:encoded><![CDATA[<h1>Panduan seri dunia terbuka di browser</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO dan Co-Founder Cinevva</em></p>
<p>Halaman ini adalah pusat navigasi untuk seluruh seri.</p>
<p>Jika Anda tiba dari salah satu bagian secara acak, mulailah dari sini.</p>
<p>Pembaruan Maret 2026: kami menambahkan pemeriksaan silang implementasi eksternal dari devlog Vuntra City di <a href="/id/blog/2026-02-25-open-world-browser-part-12-lessons">Bagian 12</a> dan memperluas <a href="/id/guides/browser-3d-open-world-tech">panduan teknologi dunia terbuka di browser</a> pendamping dengan temuan yang sama.</p>
<p>Pembaruan April 2026: Bagian 13-14 membahas pemahatan medan (Spike 25-27) serta lapisan visual/gameplay: tekstur multi-material, vegetasi terinstansiasi, dan pengontrol karakter dengan tabrakan HM+SDF (Spike 28-30).</p>
<p>Pembaruan Mei 2026: seri ini berlanjut hingga 29 bagian. Bagian 15-29 membahas fase panjang di tengah proses pengembangan, medan dan air multipemain, refaktor struktur kode, animasi dan penyebaran berbantuan AI, imposter dan paralaks, visibility buffer yang tidak memberikan hasil sepadan, awan dan culling meshlet, avatar yang diproses secara batch dan suara berbasis kedekatan, persistensi dunia dan angin GPU, karakter universal, tiga pendekatan untuk air, pulau prosedural, rumput dan oklusi, serta pengontrol karakter modular yang dapat menggerakkan tubuh apa pun (Spike 31-60).</p>
<p>Pembaruan Juni 2026: Bagian 30 menambahkan kamera yang memperhitungkan tabrakan, boom spring-arm dengan kontrak collider modular dan probe signed-distance yang menghentikan pandangan saat bertemu ceruk batu dan langit-langit gua, bukan hanya bukit.</p>
<h2>Arti &quot;spike&quot; dalam seri ini</h2>
<p>Spike adalah eksperimen singkat dan terfokus.</p>
<p>Setiap spike menguji satu pertanyaan berisiko. Kami menjaga cakupannya tetap sempit, mengukur hal-hal yang penting, lalu memutuskan langkah berikutnya. Anggaplah spike sebagai alat untuk belajar, bukan fitur yang sudah dipoles.</p>
<p>Dalam proyek ini, spike sebagian besar berupa halaman mandiri di bawah <code>/spikes/*</code> yang dapat Anda jalankan secara langsung.</p>
<h2>Baca seri ini secara berurutan</h2>
<ol>
<li><a href="/id/blog/2026-02-25-open-world-browser-part-01-risk-first">Bagian 1: Kami memulainya dengan mencoba merusaknya</a></li>
<li><a href="/id/blog/2026-02-25-open-world-browser-part-02-worker-physics">Bagian 2: Fisika worker dan kekhawatiran akan input lag</a></li>
<li><a href="/id/blog/2026-02-25-open-world-browser-part-03-the-unflashy-spikes">Bagian 3: Spike tidak mencolok yang menyelamatkan kami</a></li>
<li><a href="/id/blog/2026-02-25-open-world-browser-part-04-streaming-before-fancy">Bagian 4: Streaming sebelum medan yang canggih</a></li>
<li><a href="/id/blog/2026-02-25-open-world-browser-part-05-budgeting-the-pretty">Bagian 5: Menetapkan anggaran untuk elemen visual</a></li>
<li><a href="/id/blog/2026-02-25-open-world-browser-part-06-clipmaps">Bagian 6: Clipmap mengubah arah cerita</a></li>
<li><a href="/id/blog/2026-02-25-open-world-browser-part-07-marching-cubes">Bagian 7: Marching cubes dan gua nyata pertama</a></li>
<li><a href="/id/blog/2026-02-25-open-world-browser-part-08-webgpu-integration">Bagian 8: Integrasi tanpa kehilangan baseline kami</a></li>
<li><a href="/id/blog/2026-02-25-open-world-browser-part-09-transvoxel-first-cut">Bagian 9: Transvoxel dimulai dengan sebuah kerangka</a></li>
<li><a href="/id/blog/2026-02-25-open-world-browser-part-10-seam-chaos">Bagian 10: Kekacauan seam dan pertarungan bos di sudut</a></li>
<li><a href="/id/blog/2026-02-25-open-world-browser-part-11-policy-modes">Bagian 11: Mode berbasis kebijakan, bukan mode yang di-hardcode</a></li>
<li><a href="/id/blog/2026-02-25-open-world-browser-part-12-lessons">Bagian 12: Ring, kabut langit, dan apa yang akan kami lakukan lagi</a></li>
<li><a href="/id/blog/2026-04-13-open-world-browser-part-13-terrain-sculpting">Bagian 13: Pemahatan medan dan matinya fungsi matematika</a></li>
<li><a href="/id/blog/2026-04-13-open-world-browser-part-14-world-comes-alive">Bagian 14: Dunia mulai hidup</a></li>
<li><a href="/id/blog/2026-04-13-open-world-browser-part-15-multiplayer-and-water">Bagian 15: Ganti baseline, lalu sinkronkan</a></li>
<li><a href="/id/blog/2026-04-28-open-world-browser-part-16-structure-and-authoring">Bagian 16: Struktur untuk dunia yang terus berkembang</a></li>
<li><a href="/id/blog/2026-05-01-open-world-browser-part-17-animations-and-search">Bagian 17: Animasi yang tidak memerlukan retargeting dan pencarian aset langsung</a></li>
<li><a href="/id/blog/2026-05-02-open-world-browser-part-18-ai-scattering">Bagian 18: Kuas penyebar yang terasa seperti ditempatkan oleh AI</a></li>
<li><a href="/id/blog/2026-05-04-open-world-browser-part-19-imposters">Bagian 19: Imposter yang harus bertahan di dalam hutan</a></li>
<li><a href="/id/blog/2026-05-05-open-world-browser-part-20-parallax-occlusion">Bagian 20: Memalsukan kedalaman pada bidang datar</a></li>
<li><a href="/id/blog/2026-05-06-open-world-browser-part-21-visibility-buffer">Bagian 21: Renderer lebih cepat yang ternyata tidak lebih cepat</a></li>
<li><a href="/id/blog/2026-05-07-open-world-browser-part-22-clouds-and-meshlets">Bagian 22: Awan yang dapat disinari dan culling yang perlu terus diberi data</a></li>
<li><a href="/id/blog/2026-05-08-open-world-browser-part-23-avatars-and-voice">Bagian 23: Lima puluh avatar dan satu suara di dalam ruangan</a></li>
<li><a href="/id/blog/2026-05-09-open-world-browser-part-24-persistence-and-wind">Bagian 24: Menyimpan dunia dan angin yang dapat dilihat</a></li>
<li><a href="/id/blog/2026-05-10-open-world-browser-part-25-universal-characters">Bagian 25: Satu skeleton untuk setiap pakaian</a></li>
<li><a href="/id/blog/2026-05-12-open-world-browser-part-26-water">Bagian 26: Tiga cara membuat air</a></li>
<li><a href="/id/blog/2026-05-13-open-world-browser-part-27-island-and-terrain">Bagian 27: Pulau dari noise dan tanah yang tampak seperti tanah</a></li>
<li><a href="/id/blog/2026-05-14-open-world-browser-part-28-grass-and-occlusion">Bagian 28: Rumput hingga cakrawala dan tanah yang menyembunyikan dirinya sendiri</a></li>
<li><a href="/id/blog/2026-05-15-open-world-browser-part-29-pluggable-character">Bagian 29: Satu pengontrol untuk tubuh apa pun</a></li>
<li><a href="/id/blog/2026-06-04-open-world-browser-part-30-collision-aware-camera">Bagian 30: Kamera yang menghormati dinding</a></li>
</ol>
<h2>Peta spike langsung</h2>
<p>Mulailah dari sini jika Anda ingin menjelajahi linimasa teknis secara langsung.</p>
<p><a href="/id/spikes/01-terrain/" target="_blank">Spike 1</a> medan dan instancing · <a href="/id/blog/spike-source?spike=01-terrain">kode sumber</a><br>
<a href="/id/spikes/02-rapier-worker/" target="_blank">Spike 2</a> fisika worker · <a href="/id/blog/spike-source?spike=02-rapier-worker">kode sumber</a><br>
Spike 3 menguji beban broadcast Durable Object sebagai skrip layanan, bukan halaman mandiri<br>
Spike 4 menguji batasan kualitas seluler melalui parameter kueri Spike 1<br>
Spike 5 menguji keandalan perilaku LLM dan dijalankan sebagai skrip, bukan halaman mandiri<br>
<a href="/id/spikes/06-chunk-streaming/" target="_blank">Spike 6</a> pemuatan dan pertukaran chunk · <a href="/id/blog/spike-source?spike=06-chunk-streaming">kode sumber</a><br>
<a href="/id/spikes/07-gpu-vegetation/" target="_blank">Spike 7</a> vegetasi dari peta kepadatan · <a href="/id/blog/spike-source?spike=07-gpu-vegetation">kode sumber</a><br>
<a href="/id/spikes/08-terrain-material/" target="_blank">Spike 8</a> biaya material medan · <a href="/id/blog/spike-source?spike=08-terrain-material">kode sumber</a><br>
<a href="/id/spikes/09-csm-shadows/" target="_blank">Spike 9</a> anggaran bayangan bertingkat · <a href="/id/blog/spike-source?spike=09-csm-shadows">kode sumber</a><br>
<a href="/id/spikes/10-clipmap-geomorph/" target="_blank">Spike 10</a> clipmap dan geomorphing · <a href="/id/blog/spike-source?spike=10-clipmap-geomorph">kode sumber</a><br>
<a href="/id/spikes/11-chunk-streaming/" target="_blank">Spike 11</a> streaming chunk heightmap · <a href="/id/blog/spike-source?spike=11-chunk-streaming">kode sumber</a><br>
<a href="/id/spikes/12-webgpu-marching-cubes/" target="_blank">Spike 12</a> marching cubes WebGPU · <a href="/id/blog/spike-source?spike=12-webgpu-marching-cubes">kode sumber</a><br>
<a href="/id/spikes/13-threejs-webgpu/" target="_blank">Spike 13</a> baseline integrasi WebGPU · <a href="/id/blog/spike-source?spike=13-threejs-webgpu">kode sumber</a><br>
<a href="/id/spikes/14-threejs-webgpu-incremental/" target="_blank">Spike 14</a> penguatan bertahap · <a href="/id/blog/spike-source?spike=14-threejs-webgpu-incremental">kode sumber</a><br>
<a href="/id/spikes/15-transvoxel-seam/" target="_blank">Spike 15</a> kerangka seam · <a href="/id/blog/spike-source?spike=15-transvoxel-seam">kode sumber</a><br>
<a href="/id/spikes/16-transvoxel-face/" target="_blank">Spike 16</a> face Transvoxel pertama · <a href="/id/blog/spike-source?spike=16-transvoxel-face">kode sumber</a><br>
<a href="/id/spikes/17-dual-mc-lod/" target="_blank">Spike 17</a> LOD MC ganda · <a href="/id/blog/spike-source?spike=17-dual-mc-lod">kode sumber</a><br>
<a href="/id/spikes/18-transvoxel-heightmap-seam/" target="_blank">Spike 18</a> seam heightmap · <a href="/id/blog/spike-source?spike=18-transvoxel-heightmap-seam">kode sumber</a><br>
<a href="/id/spikes/19-transvoxel-corner-grid/" target="_blank">Spike 19</a> sudut beresolusi campuran · <a href="/id/blog/spike-source?spike=19-transvoxel-corner-grid">kode sumber</a><br>
<a href="/id/spikes/20-gpu-transvoxel-corner/" target="_blank">Spike 20</a> seam sudut GPU · <a href="/id/blog/spike-source?spike=20-gpu-transvoxel-corner">kode sumber</a><br>
<a href="/id/spikes/21-gpu-mc-transvoxel-corner/" target="_blank">Spike 21</a> seam sudut MC GPU · <a href="/id/blog/spike-source?spike=21-gpu-mc-transvoxel-corner">kode sumber</a><br>
<a href="/id/spikes/22-gpu-mc-heightmap-fallback/" target="_blank">Spike 22</a> fallback dari MC ke HM · <a href="/id/blog/spike-source?spike=22-gpu-mc-heightmap-fallback">kode sumber</a><br>
<a href="/id/spikes/23-policy-chunk-modes/" target="_blank">Spike 23</a> mode chunk berbasis kebijakan · <a href="/id/blog/spike-source?spike=23-policy-chunk-modes">kode sumber</a><br>
<a href="/id/spikes/24-gpu-clipmap-rings/" target="_blank">Spike 24</a> ring clipmap dan kabut langit · <a href="/id/blog/spike-source?spike=24-gpu-clipmap-rings">kode sumber</a><br>
<a href="/id/spikes/25-heightmap-brush/" target="_blank">Spike 25</a> kuas heightmap pada data hasil sampling · <a href="/id/blog/spike-source?spike=25-heightmap-brush">kode sumber</a><br>
<a href="/id/spikes/26-sdf-brush/" target="_blank">Spike 26</a> kuas SDF melalui komputasi GPU · <a href="/id/blog/spike-source?spike=26-sdf-brush">kode sumber</a><br>
<a href="/id/spikes/27-hm-mc-brush/" target="_blank">Spike 27</a> integrasi HM + MC + kuas · <a href="/id/blog/spike-source?spike=27-hm-mc-brush">kode sumber</a><br>
<a href="/id/spikes/28-multi-material/" target="_blank">Spike 28</a> tekstur multi-material · <a href="/id/blog/spike-source?spike=28-multi-material">kode sumber</a><br>
<a href="/id/spikes/29-vegetation/" target="_blank">Spike 29</a> vegetasi dan rumput shader · <a href="/id/blog/spike-source?spike=29-vegetation">kode sumber</a><br>
<a href="/id/spikes/30-physics/" target="_blank">Spike 30</a> fisika medan dan pengontrol karakter · <a href="/id/blog/spike-source?spike=30-physics">kode sumber</a><br>
<a href="/id/spikes/31-multiplayer-sync/" target="_blank">Spike 31</a> sinkronisasi medan multipemain · <a href="/id/blog/spike-source?spike=31-multiplayer-sync">kode sumber</a><br>
<a href="/id/spikes/32-water-swimming/" target="_blank">Spike 32</a> air dan berenang · <a href="/id/blog/spike-source?spike=32-water-swimming">kode sumber</a><br>
<a href="/id/spikes/33-code-structure/" target="_blank">Spike 33</a> refaktor struktur kode · <a href="/id/blog/spike-source?spike=33-code-structure">kode sumber</a><br>
<a href="/id/spikes/34-world-authoring/" target="_blank">Spike 34</a> pembuatan konten di dalam dunia · <a href="/id/blog/spike-source?spike=34-world-authoring">kode sumber</a><br>
<a href="/id/spikes/35-combat-animations/" target="_blank">Spike 35</a> animasi pertarungan dan retargeting · <a href="/id/blog/spike-source?spike=35-combat-animations">kode sumber</a><br>
<a href="/id/spikes/36-polyhaven-models/" target="_blank">Spike 36</a> pencarian aset Poly Haven langsung · <a href="/id/blog/spike-source?spike=36-polyhaven-models">kode sumber</a><br>
<a href="/id/spikes/37-ai-scattering/" target="_blank">Spike 37</a> penyebaran prop berbantuan AI · <a href="/id/blog/spike-source?spike=37-ai-scattering">kode sumber</a><br>
<a href="/id/spikes/38-imposters/" target="_blank">Spike 38</a> imposter oktahedral · <a href="/id/blog/spike-source?spike=38-imposters">kode sumber</a><br>
<a href="/id/spikes/39-parallax-pom/" target="_blank">Spike 39</a> parallax occlusion mapping · <a href="/id/blog/spike-source?spike=39-parallax-pom">kode sumber</a><br>
<a href="/id/spikes/40-visibility-buffer/" target="_blank">Spike 40</a> renderer visibility buffer · <a href="/id/blog/spike-source?spike=40-visibility-buffer">kode sumber</a><br>
<a href="/id/spikes/41-imposter-forest/" target="_blank">Spike 41</a> imposter di dalam hutan · <a href="/id/blog/spike-source?spike=41-imposter-forest">kode sumber</a><br>
<a href="/id/spikes/42-imposter-flicker/" target="_blank">Spike 42</a> perbaikan kedipan imposter · <a href="/id/blog/spike-source?spike=42-imposter-flicker">kode sumber</a><br>
<a href="/id/spikes/43-clouds-atmosphere/" target="_blank">Spike 43</a> atmosfer dan awan volumetrik · <a href="/id/blog/spike-source?spike=43-clouds-atmosphere">kode sumber</a><br>
<a href="/id/spikes/44-meshlet-clusters/" target="_blank">Spike 44</a> culling Hi-Z meshlet · <a href="/id/blog/spike-source?spike=44-meshlet-clusters">kode sumber</a><br>
<a href="/id/spikes/45-avatar-network-sync/" target="_blank">Spike 45</a> skinning avatar secara batch dan sinkronisasi jaringan · <a href="/id/blog/spike-source?spike=45-avatar-network-sync">kode sumber</a><br>
<a href="/id/spikes/46-proximity-voice/" target="_blank">Spike 46</a> obrolan suara berbasis kedekatan · <a href="/id/blog/spike-source?spike=46-proximity-voice">kode sumber</a><br>
<a href="/id/spikes/47-world-persistence/" target="_blank">Spike 47</a> persistensi dunia dengan server sebagai otoritas · <a href="/id/blog/spike-source?spike=47-world-persistence">kode sumber</a><br>
Spike 48 mengintegrasikan rig avatar dan digunakan kembali sebagai kode bersama oleh spike berikutnya (tanpa halaman mandiri)<br>
<a href="/id/spikes/49-gpu-wind-props/" target="_blank">Spike 49</a> angin GPU pada prop dan dedaunan · <a href="/id/blog/spike-source?spike=49-gpu-wind-props">kode sumber</a><br>
<a href="/id/spikes/50-universal-characters/" target="_blank">Spike 50</a> karakter universal dan item yang dapat dikenakan · <a href="/id/blog/spike-source?spike=50-universal-characters">kode sumber</a><br>
<a href="/id/spikes/51-water-ssr-caustics/" target="_blank">Spike 51</a> air dengan refleksi screen-space · <a href="/id/blog/spike-source?spike=51-water-ssr-caustics">kode sumber</a><br>
<a href="/id/spikes/52-water-planar/" target="_blank">Spike 52</a> air dengan cermin planar · <a href="/id/blog/spike-source?spike=52-water-planar">kode sumber</a><br>
<a href="/id/spikes/53-water-pro/" target="_blank">Spike 53</a> pustaka air siap produksi · <a href="/id/blog/spike-source?spike=53-water-pro">kode sumber</a>
<a href="/id/spikes/54-procgen-island/" target="_blank">Spike 54</a> pembuatan pulau prosedural · <a href="/id/blog/spike-source?spike=54-procgen-island">kode sumber</a><br>
<a href="/id/spikes/55-terrain-shading/" target="_blank">Spike 55</a> shading medan dan penyamaran pengulangan tekstur · <a href="/id/blog/spike-source?spike=55-terrain-shading">kode sumber</a><br>
<a href="/id/spikes/56-grass/" target="_blank">Spike 56</a> rumput cross-quad berbasis GPU · <a href="/id/blog/spike-source?spike=56-grass">kode sumber</a><br>
<a href="/id/spikes/57-terrain-occlusion/" target="_blank">Spike 57</a> occlusion culling medan · <a href="/id/blog/spike-source?spike=57-terrain-occlusion">kode sumber</a><br>
<a href="/id/spikes/58-pluggable-character/" target="_blank">Spike 58</a> pengontrol karakter modular · <a href="/id/blog/spike-source?spike=58-pluggable-character">kode sumber</a><br>
<a href="/id/spikes/59-pluggable-with-avatar/" target="_blank">Spike 59</a> pengontrol dengan avatar sungguhan · <a href="/id/blog/spike-source?spike=59-pluggable-with-avatar">kode sumber</a><br>
<a href="/id/spikes/60-polygon-animations/" target="_blank">Spike 60</a> animasi poligon Synty · <a href="/id/blog/spike-source?spike=60-polygon-animations">kode sumber</a></p>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Breaker Belt: Snake bertemu Arkanoid, dibuat dengan vibe coding dalam tiga hari]]></title>
            <link>https://app.cinevva.com/id/blog/2026-02-18-a-breaker-belt</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-02-18-a-breaker-belt</guid>
            <pubDate>Wed, 18 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Ular kosmik menghancurkan bata dalam 50 gelombang dengan musik reaktif, narasi AI, dan 23 jenis bata. Dua orang. Tiga hari. Web, seluler, dan PC.]]></description>
            <content:encoded><![CDATA[<h1>A Breaker Belt: Snake bertemu Arkanoid, dibuat dengan vibe coding dalam tiga hari</h1>
<p><em>Oleh <a href="/id/about">Mariana Muntean</a>, CEO Cinevva</em></p>
<img src="https://cdn.cinevva.com/blog/breaker-belt-cover.webp" alt="Gameplay A Breaker Belt: ular kosmik neon menghancurkan bata di luar angkasa" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Kami membuat game tempat ular Anda menjadi pemukul dan bata-batanya melawan balik. Game ini dirilis untuk web, seluler, dan PC. Kami berdua mengerjakannya dalam waktu sekitar tiga hari. Tidak terus-menerus dan tanpa kerja berlebihan. Dan game ini benar-benar seru dimainkan.</p>
<p>Bagian terakhir itulah yang patut diperhatikan.</p>
<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:8px;margin:1.5rem 0">
<iframe src="https://www.youtube.com/embed/VaFkfCT3OuU" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0" allow="accelerometer;autoplay;clipboard-write;encrypted-media;gyroscope;picture-in-picture" allowfullscreen></iframe>
</div>
<h2>Perpaduan yang tidak pernah diminta siapa pun</h2>
<p>Snake berfokus pada pertumbuhan dan kesadaran spasial. Arkanoid berfokus pada refleks dan prediksi sudut. Keduanya berasal dari filosofi desain yang sama sekali berbeda, dan menggabungkannya terdengar seperti ide yang akan ditolak dengan sopan.</p>
<p>Namun, <a href="https://app.cinevva.com/engine">A Breaker Belt</a> berhasil memadukannya. Anda adalah ular kosmik, lengkungan hidup dari arus neon yang dirangkai dari ruas-ruas logam hanyut dan sutra komet, meliuk melintasi medan asteroid berisi blok-blok yang dapat dihancurkan. Kepala Anda adalah pemukulnya. Ekor Anda yang terus memanjang menjadi senjata terhebat sekaligus ancaman paling konstan. Bola-bola memantul dari tubuh Anda untuk menghancurkan bata, tetapi satu belokan yang salah hingga menabrak ekor sendiri akan mengakhiri permainan.</p>
<p>Eksperimen lintas genre seaneh ini biasanya mati sebelum sempat dimainkan siapa pun, karena biaya pengembangan untuk mengetahui apakah sebuah ide aneh dapat berfungsi secara tradisional dihitung dalam hitungan bulan. Di sini, biayanya diukur dalam beberapa sore.</p>
<h2>Apa yang benar-benar dirilis</h2>
<p>Cakupannya membuat proyek ini menarik. Ini bukan prototipe game jam dengan persegi panjang sementara dan tanpa suara.</p>
<p>Game ini memiliki 50 gelombang. Bukan 50 variasi dari tembok bata yang sama. Formasinya berevolusi dari lengkungan awal yang ramah bagi pemain baru menjadi cincin benteng yang menuntut tembakan bersudut melalui celah samping, lalu berubah menjadi labirin diagonal berlapis dengan bukaan selebar satu petak yang memerlukan kendali presisi. Bata peledak menghancurkan bata-bata di sekitarnya. Bata hantu muncul dan lenyap dari keberadaan. Bata regeneratif pulih setelah dihancurkan, memaksa Anda memprioritaskan target alih-alih menyapu dari kiri ke kanan. Bata portal memindahkan bola Anda ke sisi lain arena. Sumur gravitasi membelokkan tembakan menjadi himne lambat yang melengkung. Pemancar laser menggambar garis merah di kehampaan. Bata peniru tampak tidak berbahaya sampai memutuskan sebaliknya. Pada gelombang ke-15, Anda akan menavigasi sesuatu yang terasa bukan lagi seperti teka-teki, melainkan seperti sistem hidup yang mempelajari kebiasaan Anda.</p>
<p>Musiknya bukan sekadar putaran berulang. Ini adalah soundtrack reaktif yang berkembang mengikuti permainan Anda. Sistem dasarnya memainkan lini bas, synth utama, pad, kick, snare, dan hi-hat dalam tangga nada E minor pada 140 BPM. Seiring meningkatnya intensitas aksi, lapisan perkusi dan synth tambahan perlahan masuk. Ketika keadaan mereda di antara gelombang, pad ambient mengambil alih. Musiknya bernapas bersama Anda. Seorang komposer khusus akan menghabiskan waktu berminggu-minggu untuk menyempurnakan responsivitas seperti itu. Di sini, semuanya menjadi bagian dari alur kreatif.</p>
<p>Efek suaranya bukan sampel yang diambil dari paket gratis. Setiap suara bata pecah, pengambilan power-up, pantulan bola, dan tabrakan disintesis secara real time. Kontak dengan kepala memiliki nada berbeda dari kontak dengan ekor. Reverb hangat menciptakan nuansa luar angkasa. Filter low-pass menjaga suara tetap memuaskan tanpa menjadi tajam. Saat Anda merangkai kombo, audionya memberi tahu Anda lebih dahulu daripada layar.</p>
<p>Lalu ada penceritaannya. Setiap gelombang dibuka dengan bagian naratif yang disampaikan oleh suara buatan AI. Penulisannya memiliki kepribadian yang kuat. Gelombang pertama: &quot;Mereka menyebutnya Breaker Belt: pita puing hasil rekayasa yang mengitari bintang tua seperti sebuah peringatan.&quot; Pada gelombang ke-38: &quot;Belt itu tidak lagi terasa seperti dinding dan mulai terasa seperti pikiran. Ia tidak menguji refleksmu, melainkan kebiasaanmu. Kau mematahkan kebiasaan itu. Belt menyadarinya.&quot; Ada 50 bab mitologi kosmik yang membuat Anda peduli pada alasan Anda menjadi ular yang menghancurkan bata di luar angkasa.</p>
<p>Latar belakangnya juga berevolusi. Gelombang awal menampilkan hamparan bintang nila yang tenang dengan hujan meteor lembut. Menjelang pertengahan permainan, pita aurora dan awan nebula mulai muncul. Pada tahap akhir, suasananya berubah menjadi Badai Ion sepenuhnya, dengan guratan sian tajam di ruang yang nyaris hitam. Mulai gelombang ke-15, Anda memasuki wilayah Cakrawala Peristiwa: kehampaan dalam yang diselingi filamen nebula bergerak lambat dan efek lensa lubang hitam yang samar. Game ini menyampaikan perkembangan melalui atmosfer sama kuatnya dengan melalui tingkat kesulitan.</p>
<p>Semua ini dapat dimainkan dengan papan ketik, gamepad, atau layar sentuh. Dirilis untuk web, seluler, dan PC dari satu basis kode. Tanpa build terpisah. Tanpa proses porting.</p>
<h2>Tim yang ternyata tidak diperlukan</h2>
<p>Inilah bagian yang seharusnya membuat setiap pengembang game berhenti sejenak.</p>
<p>Game dengan kedalaman konten seperti ini biasanya membutuhkan seorang desainer game, beberapa pemrogram, seniman 2D, desainer suara, komposer musik, desainer level, penulis narasi, dan tim QA. Totalnya delapan atau sembilan orang. Dengan ritme pengembangan indie yang wajar, Anda membutuhkan tiga hingga enam bulan kerja terkoordinasi. Rapat harian, tiket Jira, pipeline aset, dan debugging khusus tiap platform.</p>
<p>Kami berdua membuatnya dalam satu akhir pekan panjang menggunakan <a href="https://app.cinevva.com/engine">Cinevva Engine</a>.</p>
<p>Talenta yang dibutuhkan tidak berubah. Yang berubah adalah perbandingan antara niat kreatif dan beban implementasi. Waktu kami digunakan untuk menentukan seperti apa rasa game ini seharusnya, bukan untuk bergulat dengan alat agar semuanya dapat terwujud.</p>
<h2>Mengapa ini penting jika Anda berkarya</h2>
<p>Pertanyaan yang menarik bukanlah apakah alat AI dapat membantu membuat game lebih cepat. Pertanyaan itu sudah terjawab. Pertanyaan yang menarik adalah apa yang terjadi pada ide-ide yang dahulu terlalu berisiko untuk dicoba.</p>
<p>&quot;Snake, tetapi Anda menjadi pemukul di arena Arkanoid&quot; bukanlah sesuatu yang akan disetujui produser. Beberapa pengembang indie telah mencoba variasi perpaduan ini di <a href="http://itch.io">itch.io</a> (<a href="https://newdron.itch.io/breaksnake">BreakSnake</a>, <a href="https://neop87.itch.io/snakeout">SnakeOut</a>, <a href="https://merrak.itch.io/snake-break">Snake Break</a>), tetapi semuanya merupakan eksperimen game jam berskala kecil. Perpaduan genre ini belum pernah benar-benar diproduksi dengan musik reaktif, narasi AI, puluhan jenis bata, dan desain level yang terus meningkat sepanjang 50 gelombang. Dalam pengembangan tradisional, tingkat penyempurnaan seperti itu untuk konsep berisiko biasanya dibatalkan dalam rapat bahkan sebelum satu baris kode pun ditulis.</p>
<p>Ketika mencoba sesuatu yang aneh hanya memerlukan satu sore, bukan anggaran satu kuartal, ide-ide nyeleneh pun dapat diwujudkan. Sebagian ternyata benar-benar bagus. A Breaker Belt adalah salah satunya.</p>
<h2>Mainkan. Atau buat versi Anda sendiri.</h2>
<p><a href="https://app.cinevva.com/engine">A Breaker Belt</a> dapat dimainkan sekarang juga di web, seluler, dan PC. Jika game ini membuat Anda ingin membangun sesuatu, <a href="https://app.cinevva.com/engine">Cinevva Engine</a> dapat digunakan secara gratis. Jelaskan apa yang Anda inginkan, lakukan iterasi terhadap hasilnya, lalu rilis saat sudah siap. Fitur <a href="https://app.cinevva.com/tools/music">musik</a>, <a href="https://app.cinevva.com/tools/sfx">efek suara</a>, <a href="https://app.cinevva.com/tools/flux">seni</a>, dan <a href="https://app.cinevva.com/tools/hunyuan3d">model 3D</a> sudah tersedia di dalamnya.</p>
<p>Ide game aneh Anda mungkin hanya berjarak tiga hari dari kenyataan.</p>
<hr>
<p><em><a href="https://app.cinevva.com/engine">Mainkan A Breaker Belt</a> | <a href="https://app.cinevva.com/engine">Buat game Anda sendiri</a> | <a href="https://cinevva.com/charts">Jelajahi game komunitas</a></em></p>
<p><strong>Terkait:</strong></p>
<ul>
<li><a href="/id/signals/2026-03-13-vibe-coding-new-game-jam">Vibe coding adalah game jam baru</a> — bagaimana alat AI mempersempit jarak antara ide dan prototipe</li>
<li><a href="/id/guides/game-jams-hackathons">Game Jam &amp; Hackathon</a> — format jam yang memungkinkan perpaduan aneh terwujud</li>
<li><a href="/id/guides/web-game-engines-comparison">Perbandingan Engine Game Web</a> — engine untuk merilis game ke web, seluler, dan PC</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kami tidak menyangka akan membangun sebuah stasiun radio]]></title>
            <link>https://app.cinevva.com/id/blog/2026-02-17-we-didnt-expect-a-radio-station</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-02-17-we-didnt-expect-a-radio-station</guid>
            <pubDate>Tue, 17 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Kami memiliki generator musik di Cinevva agar kreator game dapat membuat soundtrack. Orang-orang mulai membuat musik hanya karena mereka bisa. Setelah 362 trek, Cinevva Radio kini mengudara.]]></description>
            <content:encoded><![CDATA[<h1>Kami tidak menyangka akan membangun sebuah stasiun radio</h1>
<p><em>Oleh <a href="/id/about">Mariana Muntean</a>, CEO Cinevva</em></p>
<img src="https://cdn.cinevva.com/blog/cinevva-radio-lofi-cafe.png" alt="Cinevva Community Radio dengan 8 stasiun, termasuk Soundstage, Voltage, Lo-Fi Cafe, Main Stage, Ivory Tower, dan Electric Dreams, saat ini memutar Quiet Flute Drone" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<p>Kami memiliki <a href="https://app.cinevva.com/tools/music">generator musik</a> di platform Cinevva agar kreator game dapat membuat soundtrack game dan SFX tanpa kerumitan lisensi. Apa yang terjadi selanjutnya sama sekali tidak kami rencanakan. Orang-orang mulai membuat musik karena mereka memang ingin membuat musik. Bukan untuk game atau proyek. Hanya untuk berkarya musik.</p>
<h2>Bella Bay membuat lebih dari 100 trek dalam dua minggu</h2>
<p>Saya tidak melebih-lebihkan. Salah satu kreator kami, Bella Bay, menghasilkan lebih dari 100 trek dalam waktu sekitar dua minggu. Saat mendengarkan semuanya di <a href="https://cinevva.com/radio">Cinevva Radio</a>, Anda bisa mendengar perkembangannya. Trek-trek awalnya merupakan eksperimen. Trek-trek berikutnya terdengar seperti karya seseorang yang telah menemukan gayanya. Percepatan kreativitas semacam itu tidak terjadi ketika Anda harus bersusah payah menghadapi peralatan Anda. Itu terjadi ketika peralatan tidak lagi menghalangi proses kreatif.</p>
<p>Bella Bay bukanlah pengecualian dalam hal semangat, hanya dalam hal jumlah. Di seluruh platform, orang-orang mulai memperlakukan generator musik bukan sebagai alat bantu untuk membuat aset game, melainkan sebagai instrumen kreatif. Para produser bereksperimen dengan genre yang belum pernah mereka coba. Orang-orang terus menyempurnakan sebuah karakter suara sampai terasa pas. Musisi rumahan yang sebelumnya tidak pernah memiliki akses ke perangkat produksi lengkap tiba-tiba mendapatkannya dan langsung mencurahkan seluruh kemampuan mereka.</p>
<h2>Jadi, kami membangun sebuah radio</h2>
<p>Ini memang harus dilakukan.</p>
<p>Kami memiliki begitu banyak trek yang tersimpan di akun para pengguna tanpa ruang bersama. Tidak ada cara untuk menemukan karya orang lain. Tidak ada cara untuk secara tak sengaja menemukan sebuah trek yang mengubah suasana sore Anda.</p>
<p><a href="https://cinevva.com/radio">Cinevva Radio</a> kini mengudara. Delapan stasiun. 362 trek buatan komunitas, dan jumlahnya terus bertambah setiap hari. Setiap lagu dibuat oleh seseorang di platform ini. Begitu Anda membukanya, sesuatu langsung diputar. Anda tidak perlu mencari. Anda tidak perlu memilih. Anda hanya perlu mendengarkan.</p>
<p><strong><a href="https://cinevva.com/radio#cinematic">Soundstage</a></strong> adalah stasiun terbesar kami. Ada 111 trek musik sinematik dan epik. Sejujurnya, saya tidak menyangka ini akan terjadi. Orang-orang sangat suka membuat musik dramatis bergaya film.</p>
<p><strong><a href="https://cinevva.com/radio#mixed">Discovery</a></strong> menampung semua karya yang tidak bisa dimasukkan dengan rapi ke dalam satu genre. Ada 78 trek. Irama Latin berdampingan dengan Afrobeats, lalu country, lalu sesuatu yang sulit dideskripsikan. Stasiun ini benar-benar liar.</p>
<p><strong><a href="https://cinevva.com/radio#pop">Main Stage</a></strong> berisi trek pop dan vokal. Ada 56 trek dengan lirik dan vokal lengkap. Orang-orang menulis lagu cinta, lagu putus cinta, musik rohani, dan balada. Beberapa di antaranya benar-benar mudah melekat di kepala.</p>
<p><strong><a href="https://cinevva.com/radio#rock">Voltage</a></strong> berisi musik rock dan metal. Ada 53 trek. Riff gitar, energi punk, grunge, dan hard rock. Saya sering menyalakan stasiun ini sambil bekerja.</p>
<p><strong><a href="https://cinevva.com/radio#lofi">Lo-Fi Cafe</a></strong> persis seperti namanya. Ada 25 trek ambien santai untuk belajar, bekerja, atau sekadar menikmati suasana.</p>
<p><strong><a href="https://cinevva.com/radio#electronic">Electric Dreams</a></strong> memiliki 22 trek elektronik dan synth. Synthwave, techno, EDM, serta drum and bass.</p>
<p><strong><a href="https://cinevva.com/radio#classical">Ivory Tower</a></strong> berisi musik klasik dan orkestra. Ada 10 trek. Komposisi piano, aransemen gesek, dan karya simfonik. Masih kecil, tetapi terus berkembang.</p>
<p><strong><a href="https://cinevva.com/radio#hiphop">The Cipher</a></strong> berisi hip-hop dan rap. Sejauh ini ada 7 trek. Ini stasiun terbaru dan masih mencari karakternya.</p>
<h2>Apa yang Anda lihat saat mendengarkan</h2>
<p>Saat membuka <a href="https://cinevva.com/radio">Cinevva Radio</a>, Anda akan mendengarkan siaran langsung. Anggaplah ini bukan seperti aplikasi daftar putar, melainkan seperti stasiun radio sungguhan. Trek diputar terus-menerus. Anda dapat memberikan reaksi secara langsung, mengobrol dengan pendengar lain, dan melihat siapa yang membuat setiap trek.</p>
<p>Nama kreator ditampilkan di layar saat trek mereka diputar. Nama mereka, prompt mereka, dan genrenya. Jika mendengar sesuatu yang Anda sukai, Anda akan tahu siapa pembuatnya. Ini adalah konten buatan komunitas dengan lapisan penemuan di atasnya. Tidak ada algoritma yang menentukan karya mana yang layak. Tidak ada penjaga gerbang. Anda membuat sebuah trek, trek itu masuk ke stasiun yang sesuai dengan genrenya, lalu orang-orang mendengarkannya.</p>
<h2>Ini lebih besar daripada sekadar fitur</h2>
<p>Selama puluhan tahun, produksi musik membutuhkan perangkat lunak mahal, pelatihan bertahun-tahun, dan akses ke peralatan yang tidak mampu dibeli kebanyakan orang. Kini, kami melihat jenis kreator yang berbeda. Orang-orang yang berpikir melalui deskripsi dan perasaan, bukan not dan tanda birama.</p>
<p>&quot;Jazz malam hujan dengan piano rusak&quot; adalah sebuah arahan kreatif. Orang yang menulis prompt itu membuat keputusan artistik. Mereka mengarahkan suasana, instrumentasi, dan karakter emosionalnya. Kebetulan saja mereka tidak bisa bermain piano.</p>
<p>Saya tidak merasa hal itu membuat karya mereka menjadi kurang sah. Menurut saya, ini berarti definisi &quot;musisi&quot; sedang meluas. Dan melihat seseorang seperti Bella Bay berkembang dari nol menjadi seratus trek dalam dua minggu menunjukkan kepada saya bahwa dorongan kreatif itu selalu ada. Hanya saja, peralatannya belum tersedia.</p>
<h2>Apa selanjutnya</h2>
<p>Kami sedang mengembangkan profil komunitas tempat para produser dapat memamerkan katalog mereka dan membangun basis pengikut. <a href="https://cinevva.com/charts">Halaman tangga lagu</a> sudah menampilkan karya komunitas dari semua alat, dan kami ingin menghadirkan energi yang sama secara khusus untuk musik.</p>
<p>Namun saat ini, radionya sudah mengudara. <a href="https://cinevva.com/radio">Silakan dengarkan</a>. Dan jika ingin membuat trek sendiri, <a href="https://app.cinevva.com/tools/music">generator musik</a> dapat digunakan secara gratis. Trek Anda mungkin akan diputar di radio.</p>
<hr>
<p><em><a href="https://cinevva.com/radio">Dengarkan Cinevva Radio</a> | <a href="https://app.cinevva.com/tools/music">Buat musik</a> | <a href="https://cinevva.com/charts">Jelajahi karya komunitas</a></em></p>
<p><strong>Terkait:</strong></p>
<ul>
<li><a href="/id/guides/frontier-gen-ai-models">Model AI Generatif Sumber Terbuka Terdepan</a> — model AI musik dan audio yang bekerja di balik layar</li>
<li><a href="/id/tutorials/web-audio-api-games">Web Audio API untuk game</a> — membangun audio interaktif di browser</li>
<li><a href="/id/signals/2026-03-13-vibe-coding-new-game-jam">Vibe coding adalah game jam baru</a> — bagaimana mendeskripsikan maksud menjadi masukan kreatif utama</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Pikiran intuitif di era AI]]></title>
            <link>https://app.cinevva.com/id/blog/2026-02-10-the-intuitive-mind</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-02-10-the-intuitive-mind</guid>
            <pubDate>Tue, 10 Feb 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Jensen Huang mengatakan bahwa keterampilan matematika mentah kini telah menjadi komoditas. Inilah alasan pandangan itu begitu relevan bagi seseorang yang gagal dalam SAT, mengabaikan aturan, dan membangun sesuatu yang benar-benar diinginkan orang.]]></description>
            <content:encoded><![CDATA[<h1>Pikiran intuitif di era AI</h1>
<p><em>Oleh <a href="/id/about">Mariana Muntean</a>, CEO Cinevva</em></p>
<img src="https://cdn.cinevva.com/blog/game-jam-houston-2018.png" alt="Mariana Muntean bersama teman-teman sekelas selama game jam 48 jam di Houston pada 2018" style="width:100%;border-radius:8px;margin:1.5rem 0" />
<small>Bersama teman-teman sekelas selama game jam 48 jam di Houston, 2018</small>
<p>AI pada dasarnya telah menjadikan logika mentah dan kemampuan komputasi sebagai komoditas. Keterampilan yang dulu kita agung-agungkan—berhitung di luar kepala, mengenali pola, dan mengurai algoritma kompleks dengan tekun—kini semuanya dapat dilakukan oleh AI. Lebih cepat. Lebih baik. Tanpa merasa lelah. Apakah kita masih perlu memahaminya? Tentu saja, tetapi persepsi telah berubah. Sekarang semua orang perlu menyesuaikan diri dengan era baru—era interaksi intuitif dan hasil nyata.</p>
<p>Menurut <a href="https://business.columbia.edu/insights/digital-future/nvidia-ceo-jensen-huang-reveals-keys-ai-and-leadership">Jensen Huang</a>, CEO NVIDIA, yang kini penting adalah kemampuan untuk merasakan sebuah &quot;vibe&quot; dan melihat apa yang akan terjadi sebelum datanya tersedia. Perpaduan antara literasi teknis dan empati yang mendalam. Pemahaman intuitif yang tidak dapat disentuh silikon.</p>
<p>Saya belum pernah mendengar seseorang dengan kredibilitas seperti dirinya mengatakan sesuatu yang begitu langsung membenarkan seluruh perjalanan hidup saya.</p>
<h2>SAT dan sistem yang tidak dirancang untuk saya</h2>
<p>Beberapa tahun lalu, saya mengikuti SAT dan gagal. Saya tidak bangga akan hal itu, tetapi saya juga tidak mencoba lagi. Ada sesuatu yang terasa sangat keliru dari keseluruhan prosesnya, dan saya tidak bisa menghilangkan perasaan itu, sebanyak apa pun orang menyuruh saya untuk belajar lebih giat dan mencobanya lagi.</p>
<p>Jika melihat ke belakang, saya rasa saya benar.</p>
<p>SAT dirancang untuk sistem pendidikan Amerika. Kedengarannya jelas, tetapi implikasinya sangat mendalam. Sekolah menengah di Amerika mengajarkan pola, jenis pertanyaan, dan cara membingkai masalah tertentu. Sejak sekolah dasar, para siswa tumbuh dalam gaya ujian standar semacam itu. Ketika tiba waktunya mengikuti SAT, mereka sudah menginternalisasi ritmenya.</p>
<p>Pelajar internasional tidak memiliki keuntungan tersebut. Kami berasal dari sistem dengan filosofi pendidikan yang berbeda. Sekolah-sekolah Eropa sering kali lebih menekankan kedalaman daripada keluasan, ujian berbasis esai daripada pilihan ganda, dan pembelaan lisan daripada lembar jawaban. Sistem Asia memiliki ujian standarnya sendiri, tetapi mengukur hal-hal yang berbeda dengan cara yang berbeda. Tradisi pendidikan Amerika Selatan, Afrika, dan Timur Tengah masing-masing memiliki logikanya sendiri.</p>
<p>Ketika seorang pelajar internasional dihadapkan pada SAT, yang diuji bukan hanya pengetahuannya. Yang diuji juga seberapa cepat ia dapat beradaptasi dengan budaya ujian asing sambil sekaligus menunjukkan penguasaan materi. Kefasihan budaya diuji sama besarnya dengan kemampuan akademis.</p>
<p>Saya diharapkan mempersiapkan diri selama satu musim panas dan meraih nilai sempurna. Mempelajari seluruh budaya ujian, melepaskan naluri pendidikan saya sendiri, lalu tampil pada tingkat yang akan mengesankan petugas penerimaan kampus Amerika. Semuanya hanya dalam beberapa bulan.</p>
<p>Saya memilih untuk tidak melakukannya.</p>
<p>Ketika masih muda, kita cerdas dengan cara yang berbeda. Cara-cara intuitif. Saya sedang membuka jalan bagi diri sendiri, meskipun saat itu saya belum bisa menjelaskan dengan tepat alasannya. Ada sesuatu dalam diri saya yang tahu bahwa sistem ini bukan untuk saya.</p>
<h2>Memilih mengikuti jalur kreatif</h2>
<p>Saya mempelajari pengembangan dan desain game karena menyukai gagasan menggunakan kreativitas dan efek visual untuk membangun dunia virtual yang dapat dimainkan dan dijelajahi orang. Saya menyukai perpaduan seni dan teknologi, penceritaan dan interaktivitas.</p>
<p>Apa yang saya temukan mengejutkan saya.</p>
<p>Game membutuhkan kedalaman teknis yang serius. Simulasi fisika, deteksi tabrakan, matematika vektor, perhitungan pencahayaan, optimasi. Saya sudah mengetahui itu sejak awal. Matematika dan rekayasa bukanlah penghalang dalam pengembangan game. Keduanya merupakan bagian dari hal yang membuat game dapat berfungsi.</p>
<p>Masalahnya adalah jurang antara visi kreatif dan implementasi. Engine dan alat yang mendominasi industri dirancang oleh engineer untuk engineer. Semuanya berjalan berdasarkan &quot;if&quot; dan &quot;then&quot; serta blueprint berbasis node. Ingin membuat efek pusaran? Pelajari pemrograman shader. Ingin suasana pencahayaan tertentu? Selami grafik material. Ingin gerakan karakter yang terasa tepat? Habiskan waktu berjam-jam untuk men-debug pengontrol karakter atau parameter fisika.</p>
<p>Jika Anda adalah orang yang berpikir secara visual, jika Anda berpikir dalam warna-warna cerah dan gambar bergerak, jika ide datang kepada Anda sebagai adegan utuh dengan suara, tekstur, dan bobot emosional, Anda harus menerjemahkan semuanya ke dalam bahasa teknis sebelum bisa mewujudkan satu pun bagiannya. Anda melihat dunia dalam pikiran, lengkap dengan pencahayaan, atmosfer, dan cara karakter bergerak melintasi ruang. Kemudian Anda duduk di depan komputer dan menghabiskan enam jam berikutnya untuk men-debug alasan karakter Anda jatuh menembus lantai.</p>
<p>Fondasi teknis itu penting. Namun, alat-alat tersebut memaksa kreator berkutat dalam detail implementasi alih-alih mengabstraksikan kompleksitas itu. Membuat game seharusnya terasa seperti menceritakan kisah atau menyutradarai film yang dapat diikuti orang. Itulah keajaiban media ini. Namun, yang terasa justru seperti mengikuti ujian rekayasa sebelum Anda bahkan bisa memulai.</p>
<p>Sutradara film tidak menghabiskan waktu bertahun-tahun mempelajari engine fisika sebelum dapat mengekspresikan visinya. Mereka memperoleh anggaran dan tim yang menangani eksekusi teknis. Namun, dalam pengembangan game indie, Anda jarang memiliki anggaran. Yang Anda miliki adalah waktu dan akses ke alat. Dan jika Anda orang yang menguasai teknis, Anda dapat membuat game yang luar biasa. Namun hanya jika demikian.</p>
<p>Begitulah kita mendapatkan judul seperti Limbo, yang dibuat oleh tim kecil dengan visi artistik tunggal dan kemampuan teknis untuk mewujudkannya. Atau Undertale, yang sebagian besar dibuat oleh satu orang yang kebetulan memiliki perpaduan tepat antara naluri kreatif dan kemampuan pemrograman. Atau Stardew Valley, ketika Eric Barone menghabiskan waktu bertahun-tahun mempelajari sendiri segala hal, mulai dari pixel art dan komposisi musik hingga pemrograman C#.</p>
<p>Game-game ini berhasil melawan rintangan yang luar biasa besar. Namun, untuk setiap Limbo, ada jutaan visi kreatif yang mati karena alat-alat yang digunakan menuntut kefasihan teknis yang tidak dimiliki kreatornya. Kurang dari 3% pengembang game indie pernah mencapai kesuksesan yang berarti. Berapa banyak game brilian yang tidak pernah dibuat karena kreatornya terbentur dinding &quot;if&quot; dan &quot;then&quot;, lalu menyerah?</p>
<p>Hambatan untuk masuk bukanlah kreativitas. Hambatannya adalah pembatasan akses teknis yang tertanam dalam alat-alat itu sendiri.</p>
<h2>Membangun sesuatu yang seharusnya sudah ada</h2>
<p>Jadi, 5 tahun lalu saya mulai membangun sesuatu yang berbeda.</p>
<p>Gagasannya sederhana: pengembangan game seharusnya dapat diakses siapa saja yang memiliki visi kreatif. Anda seharusnya tidak memerlukan gelar ilmu komputer untuk mengekspresikan diri melalui media interaktif. Alat-alatnya harus menyesuaikan diri dengan cara orang kreatif benar-benar berpikir, bukan sebaliknya.</p>
<p>Para VC dari Sequoia, Pear, Draper, dan puluhan firma lain mengatakan kepada saya bahwa ini tidak akan berhasil. Ini B2C. Pasarnya tidak ada. Pengembang indie tidak mau membayar apa pun. Anda tidak bisa menyederhanakan pengembangan game tanpa mengorbankan kemampuan. Gamer menginginkan game yang kompleks, dan game kompleks membutuhkan alat yang kompleks. Jutaan alasan yang disamarkan sebagai analisis pasar.</p>
<p>Orang-orang mengatakan saya gila. Mungkin memang begitu. Namun, saya terus kembali pada pertanyaan yang sama: mengapa anggaran jutaan dolar harus menjadi prasyarat untuk berekspresi secara kreatif? Sutradara film dan produser game ternama memiliki tim dan sumber daya. Semua orang lainnya hanya mendapat editor kode dan doa. Saya ingin membangun sesuatu yang menutup kesenjangan tersebut. Anda mendeskripsikan apa yang diinginkan, dan hal itu terwujud di depan mata. Seluruh diri saya tahu bahwa inilah yang benar. Saya bisa merasakannya di setiap sel tubuh saya.</p>
<p>Saat ini, ribuan orang menggunakan Cinevva setiap hari untuk membuat aset game 3D, game, musik, level, dan pengalaman. Proyek-proyek yang telah dibuat sejauh ini meraih jutaan tayangan. Bertumbuh setiap hari. Presentasi dua menit di Sand Hill Road bukanlah format yang tepat untuk mengatakan, &quot;Saya gagal dalam SAT, tetapi percayalah pada intuisi saya.&quot;</p>
<h2>Arti intuisi yang sebenarnya</h2>
<p><a href="https://singjupost.com/transcript-jensen-huangs-interview-cisco-ai-summit-2026/">Huang</a> tidak sekadar menyampaikan pandangan filosofis. Ia sedang menggambarkan pergeseran nyata dalam hal-hal yang dianggap sebagai kecerdasan bernilai.</p>
<p>Selama puluhan tahun, kita mengoptimalkan hal-hal yang salah. Kita membangun sistem pendidikan yang menghargai hafalan dan perhitungan. Kita merancang ujian standar yang mengukur pencocokan pola berdasarkan masalah yang pernah dilihat sebelumnya. Kita merekrut orang berdasarkan kredensial yang membuktikan bahwa mereka mampu bertahan selama empat tahun melewati pembatasan akademis. AI baru saja membuat semua itu menjadi kurang istimewa.</p>
<p>Hal yang tidak dapat dilakukan AI, setidaknya belum, adalah merasakan apa yang hilang. Merasakan ketika ada sesuatu yang tidak beres. Menangkap secara intuitif apa yang dibutuhkan orang sebelum mereka sendiri mampu mengungkapkannya. Membaca suasana. Memahami konteks yang tidak tercakup dalam dataset apa pun.</p>
<p>Saya mencurahkan waktu, pengalaman hidup internasional, uang, dan pengetahuan intuitif saya untuk membangun Cinevva. Itu adalah perpaduan yang sulit diperoleh di perguruan tinggi. Sulit diuji melalui SAT. Sulit ditangkap oleh sistem kredensial apa pun yang dirancang sebelum AI membuat kemampuan kognitif mentah tersedia secara melimpah.</p>
<p>Enam belas atau dua puluh tahun lalu, ilmuwan komputer menentukan seperti apa alat-alat seharusnya terlihat dan bagaimana cara kerjanya. Mereka membangunnya untuk diri mereka sendiri, untuk orang-orang yang berpikir seperti mereka. Kami semua diharapkan menyesuaikan diri. Era itu akan segera berakhir. Orang-orang yang akan membentuk apa yang hadir berikutnya adalah mereka yang memahami apa yang benar-benar diinginkan manusia. Mereka yang dapat merasakan ketika ada sesuatu yang salah dan ketika ada sesuatu yang benar. Mereka yang membangun untuk manusia, bukan demi keanggunan teknis.</p>
<p>Saya memercayai sesuatu dalam diri saya yang dianggap tidak berharga oleh sistem. Dan saya benar.</p>
<hr>
<p><strong>Terkait:</strong></p>
<ul>
<li><a href="/id/blog/2026-01-18-skills-over-degrees">Pasar kerja sedang bertransformasi — dari kredensial ke keterampilan</a></li>
<li><a href="/id/guides/game-dev-courses">Kursus Pengembangan Game Online</a> — jalur yang mengutamakan keterampilan dan melewati pembatasan tradisional</li>
<li><a href="/id/signals/2026-03-04-everyone-wants-ai-game-engine">Sekarang semua orang ingin menjadi engine game AI</a> — pergeseran industri menuju alat yang menyesuaikan diri dengan cara orang berpikir</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Kontroversi AI, kepercayaan, dan ekonomi pasca-AI untuk game]]></title>
            <link>https://app.cinevva.com/id/blog/2026-01-18-ai-controversy-and-post-ai-economy</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-01-18-ai-controversy-and-post-ai-economy</guid>
            <pubDate>Sun, 18 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Sudut pandang praktis: AI bukanlah inti persoalannya—kepercayaanlah yang utama. Mengapa pelabelan, filter, dan distribusi yang adil lebih penting daripada perdebatan 'pro' versus 'anti' AI.]]></description>
            <content:encoded><![CDATA[<h1>Kontroversi AI, kepercayaan, dan ekonomi pasca-AI untuk game</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO Cinevva</em></p>
<p>AI dalam game berubah menjadi ladang ranjau sungguhan sekitar pertengahan 2024. Pekerjaan menghilang. Orang-orang yakin merekalah yang berikutnya. Masalah hak cipta yang bahkan para pengacara pun tak mampu menguraikannya. Perdebatan estetika tanpa akhir yang terus berputar-putar. Steam dibanjiri hal-hal yang tak pernah diminta siapa pun. Dan di balik semuanya, ada kekhawatiran mengusik yang kini dirasakan setiap kreator: &quot;apakah aku benar-benar sedang membuat sesuatu, atau cuma... mengetik prompt?&quot;</p>
<p>Kami mengelola sebuah platform. Ada satu hal yang cepat Anda pelajari dari pekerjaan itu.</p>
<p><strong>Tak seorang pun suka merasa ditipu.</strong></p>
<h2>Angka-angka ini mengejutkan kami</h2>
<p>Kami memperkirakan adopsi AI akan meningkat. Namun, tidak seperti ini. Berikut situasinya pada akhir 2025:</p>
<table>
<thead>
<tr>
<th>Yang kami pantau</th>
<th>2024</th>
<th>2025</th>
<th>Perubahannya</th>
</tr>
</thead>
<tbody>
<tr>
<td>Game Steam yang mengungkapkan penggunaan AI</td>
<td>~1.000</td>
<td>7.818</td>
<td>Naik 7x</td>
</tr>
<tr>
<td>Rilis baru di Steam yang menggunakan AI</td>
<td>~3%</td>
<td>~20%</td>
<td>Satu dari lima</td>
</tr>
<tr>
<td>Pengembang yang menganggap AI menurunkan kualitas</td>
<td>34%</td>
<td>47%</td>
<td>Naik tiga belas poin</td>
</tr>
<tr>
<td>Pengembang yang menganggap AI meningkatkan kualitas</td>
<td>—</td>
<td>11%</td>
<td>Tidak banyak</td>
</tr>
<tr>
<td>Pendapatan dari game yang mengungkapkan penggunaan AI</td>
<td>—</td>
<td>$660 juta</td>
<td>Dua belas game menembus pendapatan delapan digit</td>
</tr>
</tbody>
</table>
<p>Sumber: analisis Tom's Hardware / Totally Human Media, GDC 2025 Developer Survey, Unity 2025 Gaming Report</p>
<h2>Apa yang sebenarnya terjadi hingga pemain menjadi seskeptis ini</h2>
<p>Sikap ini tidak muncul begitu saja. Ada masalah nyata yang terjadi. Dan orang-orang mengingatnya.</p>
<h3>Para pengisi suara mengetahui bahwa suara mereka telah dikloning—pada hari peluncuran</h3>
<p><em>Tomb Raider 4-6 Remastered</em> dirilis dengan versi pertunjukan suara aslinya yang dihasilkan AI. Para pengisi suara baru mengetahuinya bersamaan dengan semua orang. Pada hari peluncuran. Penerbit akhirnya menghapus suara tersebut melalui patch setelah tekanan hukum meningkat. Mogok SAG-AFTRA selama sebelas bulan itu? Skenario seperti inilah yang memicunya.</p>
<h3>&quot;Sampah AI&quot; kini menjadi istilah yang benar-benar digunakan orang</h3>
<p><em>Call of Duty: Black Ops 6</em> diam-diam menambahkan pengungkapan penggunaan AI ke halaman Steam-nya. Setelah game itu telanjur dirilis. Para pemain sudah melihat kejanggalannya—glitch visual tersebar di mana-mana. Salah satu karakter di layar pemuatan memiliki enam jari. &quot;Sampah AI&quot; menjadi istilah singkat untuk apa pun yang terlihat... janggal. Hampa. Seolah tak ada yang cukup peduli untuk memeriksanya.</p>
<h3>Sebuah nominasi penghargaan lenyap</h3>
<p>Nominasi Game of the Year untuk <em>Clair Obscur: Expedition 33</em> dicabut oleh Indie Game Awards. Padahal game yang dirilis tidak menggunakan AI. Masalahnya adalah placeholder AI selama pengembangan—materi internal yang tidak pernah sampai ke pemain. Aset final sepenuhnya dibuat manusia. Tetap saja tidak berpengaruh. Berminggu-minggu dihabiskan untuk memperdebatkan di mana tepatnya batas harus ditarik.</p>
<h3>Tim yang tidak pernah menyentuh AI harus membuktikannya</h3>
<p><em>Chessplus</em> dan <em>Peak</em> sama-sama dituduh menggunakan AI. Keduanya sama sekali tidak menggunakannya. Keduanya merupakan nomine penghargaan. Kedua tim pengembang akhirnya harus menggali tangkapan layar lama dan berkas layer hanya untuk menunjukkan bahwa karya mereka dibuat dengan tangan. Tim <em>Peak</em> merangkumnya dengan sangat baik: &quot;Kami mungkin sampah, tetapi kami adalah sampah artisanal buatan manusia yang bersumber secara lokal.&quot;</p>
<h3>Studio mengambil arah yang benar-benar berlawanan</h3>
<p><strong>SNK</strong>—para moderator Discord mengundurkan diri setelah visual yang tampak seperti buatan AI muncul dalam trailer <em>Fatal Fury: City of the Wolves</em>. <strong>Games Workshop</strong>—melarang AI sepenuhnya di semua properti Warhammer. <strong>Larian Studios</strong>—mengatakan bahwa mereka hanya menggunakan AI untuk sketsa konsep yang sangat awal bagi Baldur's Gate 3, tanpa sedikit pun penggunaannya dalam game final. <strong>Tim Sweeney</strong>—menyatakan bahwa label AI Steam tidak berguna dan harus dihapus. <strong>Valve</strong>—membalas bahwa pengembang yang mengeluhkan label AI biasanya khawatir karya mereka terlihat &quot;minim upaya.&quot;</p>
<h2>Menemukan game telah berubah menjadi persoalan kepercayaan</h2>
<p>Kini, berbagai hal dibuat lebih cepat daripada kemampuan siapa pun untuk mengevaluasinya dengan layak. Pertanyaannya pun berubah:</p>
<p>Apa sebenarnya yang sedang saya lihat?
Siapa yang membuatnya?
Apakah saya akan menyesali waktu yang saya habiskan untuk ini?
Apakah semua ini sesuai dengan yang dijanjikan trailernya?</p>
<p>Kemungkinan besar tidak akan ada penyelesaian besar. Tidak ada keputusan definitif tentang AI versus karya manusia.</p>
<p>Yang lebih mungkin terjadi: <strong>filter, transparansi nyata, dan struktur insentif yang mendorong kejujuran</strong>.</p>
<h2>Studio kecil terjebak di tengah semua ini</h2>
<p>Pengembang indie berada dalam posisi yang aneh.</p>
<p><strong>Keuntungannya memang sulit disangkal:</strong>
Anda dapat melakukan iterasi lebih cepat. Biaya turun ketika empat orang harus membuat semuanya. Pengembang solo kini benar-benar bisa menyelesaikan proyek mereka. Pelokalan tidak lagi menghabiskan seluruh anggaran Anda.</p>
<p><strong>Kerugiannya juga sama nyatanya:</strong>
Hasil yang terasa generik. Kekhawatiran tentang data pelatihan dan kekayaan intelektual yang belum berani disentuh pengacara. Merilis sistem yang tidak sepenuhnya Anda pahami—sebagian orang menyebutnya utang pemahaman. Dianggap sebagai bagian dari banjir rilis minim upaya. Hampir separuh pengembang yang disurvei menganggap AI secara keseluruhan membuat game menjadi lebih buruk.</p>
<p>Laporan Unity tahun 2025 menyebutkan bahwa 79% pengembang bersikap positif terhadap alat AI. Kedengarannya cukup meyakinkan. Kenyataannya lebih rumit. Tim yang memanfaatkannya dengan baik cenderung menggunakan AI untuk bagian-bagian membosankan—pekerjaan kasar, draf awal, dan rutinitas QA yang menjemukan. Arahan kreatif? Itu tetap dipegang manusia.</p>
<h2>Posisi Cinevva: netral terhadap AI, tegas soal kejujuran</h2>
<p>Kami tidak menolak game karena menggunakan AI. Kami juga tidak memberi perlakuan khusus.</p>
<p>Aturannya sederhana: <strong>jika AI terlibat, katakan dengan jujur.</strong> Pemain menentukan sendiri apa yang penting bagi mereka. Dengan begitu, filter benar-benar berfungsi.</p>
<ul>
<li><a href="/id/ai-content">Kebijakan konten yang dihasilkan AI</a></li>
</ul>
<h2>Filter bekerja lebih baik daripada perdebatan</h2>
<p>Perdebatan AI dalam dunia game tidak akan mencapai konsensus dalam waktu dekat. Mungkin tidak akan pernah. Namun, preferensi setiap orang? Itu cukup jelas.</p>
<p>Sebagian pemain secara khusus menginginkan seni yang diarahkan manusia. Tulisan yang berasal dari seseorang. Keahlian yang tampak nyata.</p>
<p>Sebagian lainnya benar-benar tidak peduli. Yang seru tetaplah seru.</p>
<p>Filter memungkinkan kedua kelompok menemukan apa yang mereka cari. Tak seorang pun harus menang.</p>
<h2>Model pembayaran lebih penting daripada pendapat siapa pun</h2>
<p>Ketika pendapatan bergantung pada <strong>waktu bermain</strong>, bukan penjualan unit, Anda menghasilkan uang dengan cara:</p>
<p>Membuat pemain cepat tertarik. Mempertahankan perhatian mereka. Memberikan apa yang dijanjikan pemasaran Anda.</p>
<p>Kualitas menjadi jalan yang paling jelas. Cara Anda membuatnya menjadi kurang penting.</p>
<p>Trailer Anda menjanjikan terlalu banyak? Pemain langsung pergi. Retensi anjlok. Tunjukkan dengan tepat apa yang akan mereka dapatkan? Mereka akan bertahan. Waktu bermain bertambah. Pendapatan masuk. Mekanisme ekonominya akan menyeleksi dengan sendirinya.</p>
<h2>Hal yang kemungkinan terjadi pada 2026</h2>
<p><strong>Lebih banyak aturan</strong>—cakupan EU AI Act terus meluas. Perlindungan suara dan kemiripan diri di AS semakin kuat, terutama setelah SAG-AFTRA.</p>
<p><strong>Alat khusus</strong>—AI yang dibuat khusus untuk tim kecil. Dirancang agar manusia tetap memegang kendali.</p>
<p><strong>Label yang lebih cerdas</strong>—&quot;Dibuat dengan AI&quot; terlalu sederhana. Akan muncul pembedaan antara alur kerja berbantuan AI dan aset final yang dihasilkan AI.</p>
<p><strong>Audiens terpecah</strong>—sebagian pemain akan sengaja mencari game yang dibuat secara tradisional. Sebagian lainnya tidak akan memikirkannya sama sekali. Kedua kelompok cukup besar untuk dijadikan target.</p>
<p><strong>Persaingan platform</strong>—cara etalase menangani transparansi dan penemuan game akan menjadi pembeda yang nyata.</p>
<h2>Apa yang benar-benar mendorong kemajuan</h2>
<p>Perdebatan tidak akan menyelesaikan persoalan AI. Hal-hal berikutlah yang akan melakukannya:</p>
<ol>
<li><strong>Pemain</strong> memilih berdasarkan apa yang benar-benar penting bagi mereka</li>
<li><strong>Kreator</strong> bersikap jujur tentang cara mereka bekerja</li>
<li><strong>Platform</strong> membuat alat yang membantu kedua kelompok saling menemukan</li>
</ol>
<p>Itulah ekonomi pasca-AI. Bukan kubu-kubu yang saling berperang. Kepercayaanlah yang menyatukan semuanya.</p>
<hr>
<p><strong>Terkait:</strong></p>
<ul>
<li><a href="/id/ai-content">Kebijakan konten yang dihasilkan AI</a></li>
<li><a href="/id/creators">Untuk kreator game</a></li>
<li><a href="/id/faq">Pertanyaan umum</a></li>
<li><a href="/id/guides/frontier-gen-ai-models">Model AI Generatif Sumber Terbuka Terdepan</a>—model-model tertentu dan cara kerjanya</li>
<li><a href="/id/signals/2026-03-06-open-source-ai-pollution">Sumber terbuka memiliki masalah polusi AI</a>—yang terjadi ketika keluaran AI membanjiri proyek sumber terbuka</li>
</ul>
]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Pasar kerja sedang bertransformasi — dari kredensial ke keterampilan]]></title>
            <link>https://app.cinevva.com/id/blog/2026-01-18-skills-over-degrees</link>
            <guid isPermaLink="true">https://app.cinevva.com/id/blog/2026-01-18-skills-over-degrees</guid>
            <pubDate>Sun, 18 Jan 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[90% perusahaan kini memprioritaskan keterampilan daripada gelar. Inilah artinya bagi para lulusan baru yang memasuki dunia teknologi dan pengembangan game.]]></description>
            <content:encoded><![CDATA[<h1>Pasar kerja sedang bertransformasi — dari kredensial ke keterampilan</h1>
<p><em>Oleh <a href="/id/about">Oleg Sidorkin</a>, CTO Cinevva</em></p>
<p>Saya melihat sepupu saya lulus dengan predikat kehormatan pada 2023. Gelar ilmu komputer dari perguruan tinggi negeri yang bagus. IPK yang solid. Ia menghabiskan empat belas bulan melamar pekerjaan sebelum akhirnya mendapatkannya. Sementara itu, seorang teman yang berhenti kuliah pada tahun kedua untuk membuat game indie mendapat tiga tawaran hanya dalam sebulan setelah memutuskan untuk mencari pekerjaan.</p>
<p>Itu bukan lagi sebuah anomali. Itulah polanya.</p>
<h2>Angka-angka akhirnya menyusul apa yang selama ini kita rasakan</h2>
<p>Pada 2025, <strong>90% pemimpin SDM</strong> melaporkan bahwa mereka merekrut kandidat di luar jalur gelar sarjana empat tahun tradisional (<a href="https://fortune.com/2025/07/01/90-percent-hr-leaders-looking-to-hire-outside-of-traditional-college-degrees-as-they-prioritize-skills/">Fortune</a>). Seperempat perusahaan di AS menghapus persyaratan gelar sarjana sepenuhnya (<a href="https://www.hrdive.com/news/employer-eliminate-degree-requirements-2025/748998/">HR Dive</a>). Dan inilah bagian yang terasa menyakitkan jika Anda baru saja selesai melunasi pinjaman pendidikan: <strong>94% pemberi kerja mengatakan bahwa karyawan yang direkrut berdasarkan keterampilan berkinerja lebih baik daripada mereka yang direkrut berdasarkan kredensial</strong> (<a href="https://www.forbes.com/sites/cynthiapong/2024/12/26/90-of-companies-make-better-hires-based-on-skills-over-degrees/">Forbes</a>).</p>
<p>Verizon kini mengatakan bahwa 99% posisi mereka tidak memerlukan gelar. Sergey Brin mengakui bahwa Google merekrut &quot;banyak sekali&quot; orang tanpa gelar sarjana. IBM menjadikan separuh lowongan mereka di AS tidak mewajibkan gelar melalui program &quot;New Collar&quot;.</p>
<p>Ini bukan karena perusahaan sedang berbaik hati. Mereka menyadari bahwa gelar tidak dapat memprediksi siapa yang benar-benar akan bekerja dengan baik.</p>
<h2>Mengapa sistem lama gagal</h2>
<p>Jawaban jujurnya? Gelar menjadi filter yang malas.</p>
<p>Saat Anda merekrut dan menerima 400 lamaran, mewajibkan gelar sarjana akan memangkas tumpukan itu menjadi separuh. Namun, itu tidak memberi tahu Anda siapa yang benar-benar mampu melakukan pekerjaannya. Itu hanya memberi tahu Anda siapa yang memiliki uang, waktu, dan kestabilan keluarga untuk duduk di ruang kelas selama empat tahun. Korelasinya dengan kemampuan selalu lebih lemah daripada yang selama ini kita akui.</p>
<p>Dan sekarang, tiga hal terjadi sekaligus:</p>
<p><strong>Keterampilan berubah terlalu cepat.</strong> Game engine, alat AI, framework web. Saat komite kurikulum menyetujui mata kuliah tentang sesuatu, hal tersebut sudah ketinggalan zaman. Gelar empat tahun mengajarkan teori dari empat tahun lalu. Di dunia teknologi, itu sudah menjadi sejarah kuno.</p>
<p><strong>Portofolio menjadi bukti yang tak terbantahkan.</strong> Mengapa menebak apakah seseorang bisa membuat kode jika Anda dapat melihat GitHub mereka? Mengapa bertanya-tanya apakah mereka mampu merilis game jika halaman <a href="http://itch.io">itch.io</a> mereka memiliki lima proyek yang sudah selesai beserta ulasan pemain?</p>
<p><strong>Perusahaan semakin terdesak.</strong> Kekurangan talenta memang nyata. Mengecualikan semua orang tanpa gelar berarti mengecualikan orang-orang yang mungkin justru sesuai dengan kebutuhan Anda. Sejumlah manajer perekrutan menyadari hal ini dengan cara yang sulit, setelah melihat developer otodidak jauh mengungguli karyawan bergelar yang mereka rekrut.</p>
<h2>Industri game sudah melihat perubahan ini akan datang</h2>
<p>Menurut saya, industri game sudah lebih maju dalam hal ini, dan penting untuk memahami alasannya.</p>
<p>Studio tidak pernah terlalu peduli di mana Anda berkuliah. Mereka peduli pada apa yang sudah Anda rilis. Game jam 48 jam yang dibuat dengan baik memberi tahu manajer perekrutan lebih banyak daripada gelar desain game empat tahun. Itu membuktikan bahwa Anda dapat menyelesaikan sesuatu di bawah tekanan. Itu membuktikan bahwa Anda mampu mengambil keputusan sulit tentang cakupan. Itu membuktikan bahwa gamenya dapat dimainkan, bukan sekadar teori.</p>
<p>Jika Anda mencoba memasuki industri game pada 2026, inilah yang benar-benar penting (<a href="https://www.dice.com/career-advice/aspiring-video-game-designers-in-2025-what-you-need-to-know">Dice</a>, <a href="https://combinegr.com/2025-global-gaming-employment-outlook-trends-talent-strategy/">CombineGR</a>): dua atau tiga demo yang matang dan dapat dimainkan. Studi kasus yang menjelaskan apa yang Anda lakukan dan alasannya. Bukti bahwa Anda menyelesaikan proyek. Penguasaan setidaknya satu game engine utama, yang ditunjukkan melalui proyek nyata.</p>
<p>Manajer perekrutan tidak mencari potensi. Mereka mencari bukti.</p>
<h2>Bagian tidak nyaman yang tidak pernah dibicarakan</h2>
<p>Ada sesuatu yang membuat saya frustrasi ketika mendalami risetnya.</p>
<p>Sebuah studi Harvard/Burning Glass menemukan bahwa perusahaan yang menghapus persyaratan gelar sering kali tidak benar-benar merekrut lebih banyak kandidat tanpa gelar. Peningkatannya hanya sekitar 3,5 poin persentase (<a href="https://www.forbes.com/sites/jenamcgregor/2024/02/14/companies-are-dropping-diploma-requirements-for-more-jobs-but-hiring-few-non-degreed-workers-to-fill-them/">Forbes</a>). Kebijakannya berubah. Praktik perekrutannya tertinggal.</p>
<p>Artinya, jika Anda menempuh jalur nontradisional, Anda tetap harus bekerja lebih keras. Pintunya memang lebih terbuka dibandingkan sebelumnya, tetapi Anda belum melangkah masuk dengan posisi yang setara. Portofolio Anda harus menjadi bukti yang tak terbantahkan. Proyek Anda harus berbicara lebih lantang daripada kredensial orang lain.</p>
<p>Itu tidak adil. Namun, mengetahuinya membantu Anda mempersiapkan diri.</p>
<h2>Hal yang akan saya sampaikan kepada seseorang yang baru memulai sekarang</h2>
<p>Jika Anda sedang berkuliah, jangan berhenti. Namun, pahami bahwa gelar saja kini tidak lagi cukup. Buat berbagai proyek sampingan. Ikuti game jam. Dapatkan <a href="https://grow.google/certificates/">Google Career Certificate</a> atau sertifikasi Unity. Perlakukan gelar sebagai salah satu dari beberapa kredensial, bukan satu-satunya kredensial.</p>
<p>Jika Anda tidak mengejar gelar, jalur Anda berbeda, tetapi belum tentu lebih sulit. Bangun proyek secara intensif. Rilis karya Anda. Dokumentasikan semuanya. <a href="https://github.com">GitHub</a> Anda, halaman <a href="https://itch.io">itch.io</a> Anda, situs pribadi Anda. Itulah kredensial Anda sekarang.</p>
<p>Apa pun jalurnya, berlatihlah menjelaskan pekerjaan Anda. Bukan hanya apa yang Anda buat, tetapi juga mengapa Anda mengambil keputusan tersebut. Apa yang akan Anda lakukan secara berbeda. Apa yang Anda pelajari. Pewawancara mengingat orang yang mampu mengartikulasikan cara berpikirnya.</p>
<h2>Ini lebih besar daripada sekadar perekrutan</h2>
<p>Apa yang terjadi di sini bukan sekadar perubahan cara perusahaan mengisi posisi. Ini adalah perubahan terhadap apa yang kita hargai secara kolektif.</p>
<p>Selama puluhan tahun, kredensial berfungsi sebagai filter. Mahal, memakan waktu, tetapi mudah dipahami. Jika seseorang memiliki gelar, Anda dapat mengasumsikan beberapa hal. Gelar adalah sebuah sinyal, bukan ukuran langsung, tetapi itu sudah dianggap cukup baik.</p>
<p>Kini, sinyal tersebut mulai kehilangan makna. Teknologi memungkinkan kita melihat apa yang benar-benar dapat dilakukan seseorang. Kerja jarak jauh membuktikan bahwa hasil lebih penting daripada di mana Anda duduk. AI membuat pengetahuan teoretis menjadi kurang bernilai dibandingkan penerapan praktis.</p>
<p>Saya sungguh menganggap perubahan ini penuh harapan, meskipun transisinya kacau. Dulu pertanyaannya adalah &quot;di mana Anda belajar?&quot; Sekarang pertanyaannya adalah &quot;apa yang dapat Anda buat?&quot;</p>
<p>Itu pertanyaan yang lebih baik.</p>
<hr>
<h2>Sumber</h2>
<ul>
<li><a href="https://fortune.com/2025/07/01/90-percent-hr-leaders-looking-to-hire-outside-of-traditional-college-degrees-as-they-prioritize-skills/">Fortune: 90% pemimpin SDM merekrut kandidat di luar jalur gelar tradisional</a></li>
<li><a href="https://www.forbes.com/sites/cynthiapong/2024/12/26/90-of-companies-make-better-hires-based-on-skills-over-degrees/">Forbes: 90% perusahaan memperoleh karyawan yang lebih baik melalui perekrutan berbasis keterampilan</a></li>
<li><a href="https://www.forbes.com/sites/jenamcgregor/2024/02/14/companies-are-dropping-diploma-requirements-for-more-jobs-but-hiring-few-non-degreed-workers-to-fill-them/">Forbes: Perusahaan menghapus persyaratan gelar, tetapi hanya merekrut sedikit pekerja tanpa gelar</a></li>
<li><a href="https://www.hrdive.com/news/employer-eliminate-degree-requirements-2025/748998/">HR Dive: Pemberi kerja menghapus persyaratan gelar</a></li>
<li><a href="https://www.computerworld.com/article/1623286/no-degree-no-problem-tech-firms-move-away-from-college-requirement-for-new-hires.html">Computerworld: Perusahaan teknologi beralih dari persyaratan gelar</a></li>
<li><a href="https://www.dice.com/career-advice/aspiring-video-game-designers-in-2025-what-you-need-to-know">Dice: Calon desainer video game pada 2025</a></li>
<li><a href="https://combinegr.com/2025-global-gaming-employment-outlook-trends-talent-strategy/">CombineGR: Prospek Ketenagakerjaan Industri Game Global 2025</a></li>
</ul>
<hr>
<p><strong>Terkait:</strong></p>
<ul>
<li><a href="/id/guides/game-jams-hackathons">Cara sukses dalam game jam</a></li>
<li><a href="/id/guides/game-dev-courses">Kursus Pengembangan Game Online</a> — jalur pembelajaran yang mengutamakan keterampilan untuk setiap anggaran</li>
<li><a href="/id/tutorials/agentic-code-tools">Alat pemrograman AI agentik</a> — alat yang membentuk ulang keterampilan yang penting</li>
<li><a href="/id/blog/2026-02-10-the-intuitive-mind">Pikiran intuitif</a> — mengapa intuisi lebih penting daripada kredensial</li>
</ul>
]]></content:encoded>
        </item>
    </channel>
</rss>
