← Kembali ke blog

Posisi Bloom saat ini: pilihan desain, kemajuan, dan apa yang berikutnya

Bloom genap berusia lima minggu pekan ini. Setelah tiga ratus sebelas commit, kami ingin menuliskan apa yang sudah ada, kenapa kami membuatnya seperti itu, dan bagian mana yang masih kasar.

Pitch-nya, dalam satu kalimat

Tulis game-mu dalam TypeScript, kompilasi secara ahead-of-time, dan rilis binary native sungguhan di macOS, Windows, Linux, iOS dan tvOS — atau bundle WASM untuk web. Tanpa Electron, tanpa WebView, tanpa runtime JavaScript yang ditanam di game yang kamu rilis.

Kalimat itu menanggung beban yang banyak. Ia juga menjadi alasan kenapa sebagian besar keputusan desain awal kami terlihat seperti sekarang.

Kenapa TypeScript

Kami tidak memilih TypeScript karena cinta JavaScript. Kami memilihnya karena ini bahasa bertipe statis yang paling banyak dipakai dengan sistem tipe struktural, ekosistem tooling yang luas, dan sintaks yang tidak menakuti siapa pun. Sebagian besar orang yang ingin kami ajak bikin game sudah pernah merilis TypeScript. Sangat sedikit yang pernah merilis C++.

Kami juga ingin bahasa yang bisa dikompilasi ahead-of-time secara bersih, tanpa menyeret garbage collector dan interpreter bytecode ke setiap binary yang dirilis. Itu mencoret apa pun yang butuh runtime berat (Python, C#, JS-as-language). TypeScript — dikurangi bagian dynamic-by-default-nya — ternyata jadi titik manis.

Kenapa Perry

Perry adalah kompiler ahead-of-time yang mengubah TypeScript-mu jadi kode native. Jalur TS-ke-binary inilah yang membuat kami bisa berjanji “tanpa overhead runtime.” Game-mu menjadi satu binary yang memanggil core Rust melalui C ABI yang stabil. Tidak ada V8, tidak ada Bun, tidak ada JIT.

Memilih Perry membuat kami bisa kejam soal permukaan bahasa yang kami ekspos. API Bloom adalah fungsi dan interface biasa — tanpa class, tanpa decorator, tanpa proxy, tanpa eval. Kalau ada fitur TypeScript yang tidak terkompilasi bersih ke pemanggilan native, kami tidak memakainya di API. Hasilnya: API yang muat di satu cheatsheet dan build yang muat di kepalamu.

Kenapa wgpu dan bukan empat renderer terpisah

Insting pertama kami adalah menulis renderer Metal, lalu DirectX 12, lalu Vulkan. Kami berhasil membantah diri sendiri dalam satu akhir pekan. Empat backend berarti empat bahasa shader, empat model resource, empat permukaan bug, dan empat tempat untuk lupa soal HiDPI.

Sebagai gantinya, seluruh renderer ditulis sekali di atas wgpu. Shader pakai WGSL. Kami dapat Metal di platform Apple, DirectX 12 di Windows, Vulkan di Linux dan Android, serta WebGPU (dengan fallback WebGL) di browser — dari satu codebase. Konsekuensinya, kami terikat ke set fitur wgpu, dan beberapa hal eksotis (mesh shader, ray tracing) belum bisa untuk sekarang. Buat tim kecil, kami pikir itu pertukaran yang adil.

Apa yang sebenarnya sudah ada hari ini

Kami berusaha tidak menaruh apa pun di situs marketing yang belum berfungsi. Berikut yang sudah nyata, hari ini:

  • Sembilan modul yang bisa diimporbloom/core, bloom/shapes, bloom/textures, bloom/text, bloom/audio, bloom/models, bloom/math, bloom/physics dan bloom/scene.
  • Renderer PBR sungguhan — material berlapis bergaya substrate, cascaded shadow map dengan caching untuk geometri statis, tone mapping ACES/AgX, auto-exposure, bloom, depth of field, motion blur, SSGI, SSAO, TAA, dan CAS sharpen pass untuk skala render pecahan.
  • Animasi skeletal di GPU — impor glTF 2.0, linear blend skinning empat-tulang di GPU, hingga 128 sendi per skeleton.
  • Physics Jolt — rigid dan soft body, character controller, kendaraan, raycast, constraint, callback kontak. Target web menggunakan fallback JoltPhysics.js sehingga kode yang sama berjalan di browser.
  • Enam platform target — macOS, Windows, Linux, iOS, tvOS, dan Web. Android sebagian sudah tersambung tetapi belum siap rilis.
  • Hot reload — simpan shader WGSL atau JSON material dan perubahan terlihat di layar dalam kurang dari satu detik selama pengembangan. Kode pemantau file dibuang dari build rilis.
  • Tujuh belas proyek contoh — dari Pong 170 baris sampai memuat scene Intel Sponza dan Bistro.

Beberapa hal terkini yang kami banggakan

Renderer-nya punya bulan yang bagus. Beberapa sorotan:

  • Auto-DRS. Renderer menyetel sendiri render scale-nya untuk mencapai target framerate, lalu menjalankan upscale plus RCAS sharpen pass supaya gambar tetap tajam. Kamu set target FPS; engine yang melakukan sisanya.
  • Refleksi planar. Capture mirror-plane sungguhan dengan oblique-clip dan fallback IBL ketika anggaran refleksi sudah habis. Berguna untuk air, lantai poles, dan etalase toko.
  • Splat mapping berbasis texture-array. Layer terrain dan detail kini bisa mengikat texture array dengan mip yang benar, jadi kamu bisa melukis beberapa material per tile tanpa membayar satu draw call per layer.
  • Imposter baker. CLI kecil yang membakar atlas imposter oktahedral untuk LOD jauh. Kami butuh ini begitu mulai menjatuhkan hutan ke dalam scene.
  • HiDPI lintas platform. Windows, Linux dan Web akhirnya berbagi penanganan HiDPI yang sama seperti yang sudah dimiliki macOS dan iOS. UI tetap tajam di setiap layar.

Hal-hal yang tidak kami pura-pura sudah selesai

Kami juga berutang daftar yang kurang menarik:

  • Android. Crate platform-nya ada dan sebagian besar permukaan FFI sudah tersambung, tetapi lem native-activity belum selesai. Kami belum menyuruh siapa pun merilis Android dengan Bloom.
  • watchOS. Shader sudah terkompilasi, stub platform sudah ada, tetapi kami terhambat oleh dukungan watchOS di Perry sebelum ini benar-benar nyata.
  • Geometri tervirtualisasi. Tidak ada padanan Nanite, tidak ada mesh shader, tidak ada hardware ray tracing. Ini ada di roadmap, belum di binary.
  • Batas animasi skeletal. 128 sendi per skeleton, batas keras, karena ukuran UBO. Rig besar perlu workaround untuk saat ini.
  • Scene graph-nya masih muda. Transform, visibilitas, bayangan dan binding material semua jalan. Sistem query dan pass optimisasi yang lebih luas belum ada.
  • Shader buatan pengguna. Kamu bisa menulis WGSL secara manual dan memuatnya melalui pipeline material, tetapi belum ada shader graph di dalam engine dan belum ada kompilasi shader runtime dari TypeScript.

Bentuk dari API

Kami banyak meminjam dari Raylib untuk bagian immediate-mode pada API. Kalau kamu pernah menulis game Raylib, memori ototmu langsung nyambung:

import { initWindow, windowShouldClose, beginDrawing,
         endDrawing, clearBackground, drawText, Colors } from "bloom";

initWindow(800, 450, "Hello Bloom");

while (!windowShouldClose()) {
  beginDrawing();
  clearBackground(Colors.RAYWHITE);
  drawText("Hello, Bloom!", 190, 200, 20, Colors.DARKGRAY);
  endDrawing();
}

Untuk pekerjaan 3D dan physics, filosofi yang sama berlaku: interface biasa, fungsi murni, tanpa state machine tersembunyi. Sebuah kamera adalah object literal. Sebuah rigid body adalah handle. Pipeline rendering dikonfigurasi dengan memanggil fungsi dalam urutan tertentu, bukan dengan mendaftarkan listener pada orkestrator yang tak terlihat.

Apa yang berikutnya

Daftar pendek kami untuk beberapa minggu ke depan:

  • Menyelesaikan lem native-activity Android dan menyebut Android siap rilis.
  • Mendorong pekerjaan scene graph melewati “basic” ke yang benar-benar berguna: query, penghalusan frustum culling, helper instancing.
  • Merilis potongan pertama integrasi editor sehingga kamu bisa beriterasi pada sebuah scene tanpa me-restart game.
  • Membuka source dari game-game contoh, termasuk demo yang sedikit lebih besar daripada Pong.
  • Menulis pipeline kompilasi Perry secara detail. Beberapa orang sudah meminta.

Coba sendiri

Bloom adalah open source di bawah MIT. Seluruh repository ada di GitHub. Kalau kamu mau mengikuti tanpa fork, dokumentasi punya quick start 12 baris, dan halaman showcase mendaftarkan apa yang sedang kami bangun sendiri dengannya.

Apa pun pilihanmu: terima kasih sudah menengok. Kami akan terus posting di sini saat bagian-bagian besar mendarat.