Wo Bloom steht: Designentscheidungen, Fortschritt und was als Nächstes kommt
Bloom ist diese Woche fünf Wochen alt geworden. Nach 311 Commits wollten wir aufschreiben, was wir haben, warum wir es so gebaut haben und welche Teile noch rau sind.
Der Pitch in einem Satz
Schreib dein Spiel in TypeScript, kompiliere es ahead-of-time und liefere ein echtes natives Binary auf macOS, Windows, Linux, iOS und tvOS aus — oder ein WASM-Bundle fürs Web. Kein Electron, kein WebView, keine eingebettete JavaScript-Runtime in deinem ausgelieferten Spiel.
Dieser Satz hat eine Menge Arbeit geleistet. Er ist auch der Grund, warum die meisten unserer frühen Designentscheidungen so aussehen, wie sie aussehen.
Warum TypeScript
Wir haben TypeScript nicht gewählt, weil wir JavaScript lieben. Wir haben es gewählt, weil es die am weitesten verbreitete statisch typisierte Sprache mit einem strukturellen Typsystem, einem riesigen Tooling-Ökosystem und einer Syntax ist, die niemanden abschreckt. Die meisten Leute, mit denen wir Spiele machen wollen, haben schon TypeScript ausgeliefert. Sehr wenige haben jemals C++ ausgeliefert.
Wir wollten außerdem eine Sprache, die sich sauber ahead-of-time kompilieren lässt, ohne einen Garbage Collector und einen Bytecode-Interpreter in jedes ausgelieferte Binary zu schleppen. Damit fielen alle Sprachen mit schwerer Runtime weg (Python, C#, JS-die-Sprache). TypeScript — abzüglich der dynamisch-by-default-Teile — hat sich als Sweet Spot herausgestellt.
Warum Perry
Perry ist der Ahead-of-Time-Compiler, der dein TypeScript in nativen Code verwandelt. Der Weg von TS zum Binary ist der Teil, der uns “kein Runtime-Overhead” versprechen lässt. Dein Spiel wird zu einem einzigen Binary, das über ein stabiles C-ABI in einen Rust-Kern aufruft. Es gibt kein V8, kein Bun, keinen JIT.
Mit Perry konnten wir kompromisslos sein, was die Sprachoberfläche angeht, die wir freigeben. Die Bloom-API besteht aus Funktionen und schlichten Interfaces — keine Klassen, keine Decorators, keine Proxies, kein eval. Wenn ein TypeScript-Feature sich nicht sauber zu einem nativen Aufruf kompiliert, verwenden wir es in der API nicht. Das Ergebnis ist eine API, die auf ein Cheatsheet passt, und ein Build, der in deinen Kopf passt.
Warum wgpu und nicht vier maßgeschneiderte Renderer
Unser erster Impuls war, einen Metal-Renderer zu schreiben, dann einen DirectX 12-Renderer, dann einen Vulkan-Renderer. An einem Wochenende haben wir uns das wieder ausgeredet. Vier Backends bedeuten vier Shader-Sprachen, vier Ressourcenmodelle, vier Bug-Oberflächen und vier Stellen, an denen man HiDPI vergessen kann.
Stattdessen ist der gesamte Renderer einmal auf wgpu geschrieben. Shader sind WGSL. Wir bekommen Metal auf Apple-Plattformen, DirectX 12 auf Windows, Vulkan auf Linux und Android und WebGPU (mit WebGL-Fallback) im Browser — aus einer Codebasis. Der Preis ist, dass wir an wgpus Feature-Set gebunden sind, und ein paar exotische Dinge (Mesh-Shader, Raytracing) sind vorerst vom Tisch. Wir halten das für einen fairen Deal für ein kleines Team.
Was heute tatsächlich drin ist
Wir versuchen, nichts auf die Marketing-Site zu schreiben, was nicht funktioniert. Hier ist, was heute echt ist:
- Neun importierbare Module —
bloom/core,bloom/shapes,bloom/textures,bloom/text,bloom/audio,bloom/models,bloom/math,bloom/physicsundbloom/scene. - Ein echter PBR-Renderer — geschichtete Materialien im Substrate-Stil, Cascaded Shadow Maps mit Caching für statische Geometrie, ACES/AgX-Tonemapping, Auto-Exposure, Bloom, Tiefenschärfe, Motion Blur, SSGI, SSAO, TAA und ein CAS-Schärfungs-Pass für fraktionale Render-Skalierungen.
- GPU-Skelettanimation — glTF 2.0-Import, Linear Blend Skinning mit vier Knochen auf der GPU, bis zu 128 Joints pro Skelett.
- Jolt-Physik — Rigid- und Soft-Bodies, Charaktercontroller, Fahrzeuge, Raycasts, Constraints, Kontakt-Callbacks. Das Web-Target nutzt den JoltPhysics.js-Fallback, sodass derselbe Code im Browser läuft.
- Sechs Zielplattformen — macOS, Windows, Linux, iOS, tvOS und Web. Android ist teilweise verdrahtet, aber noch nicht ausliefertauglich.
- Hot Reload — speichere einen WGSL-Shader oder ein Material-JSON, und die Änderung ist während der Entwicklung in unter einer Sekunde auf dem Bildschirm. Der File-Watching-Code wird in Release-Builds entfernt.
- Siebzehn Beispielprojekte — von einem 170-Zeilen-Pong bis zum Laden der Intel Sponza- und Bistro-Szenen.
Ein paar Dinge, auf die wir kürzlich stolz sind
Der Renderer hatte einen guten Monat. Ein paar Highlights:
- Auto-DRS. Der Renderer justiert seine Render-Skalierung selbst, um deine Ziel-Framerate zu treffen, und führt dann einen Upscale plus RCAS-Schärfungs-Pass aus, damit das Bild knackig bleibt. Du legst eine Ziel-FPS fest; den Rest macht die Engine.
- Planare Reflexionen. Echte Spiegelflächen-Captures mit Oblique-Clip und IBL-Fallback, wenn das Reflexionsbudget aufgebraucht ist. Nützlich für Wasser, polierte Böden und Schaufenster.
- Texture-Array-Splat-Mapping. Terrain- und Detail-Layer können jetzt ein Texture Array mit korrekten Mips binden, sodass du mehrere Materialien pro Tile malen kannst, ohne pro Layer einen Draw Call zu zahlen.
- Imposter-Baker. Ein kleines CLI, das octahedrale Imposter-Atlanten für entfernte LODs bäckt. Wir brauchten das in dem Moment, in dem wir anfingen, Wälder in Szenen zu setzen.
- Plattformübergreifendes HiDPI. Windows, Linux und Web teilen sich endlich dasselbe HiDPI-Handling, das macOS und iOS schon hatten. UI bleibt auf jedem Display scharf.
Dinge, von denen wir nicht behaupten, sie seien fertig
Wir schulden dir auch die unschmeichelhafte Liste:
- Android. Der Platform-Crate existiert und der Großteil der FFI-Oberfläche ist verdrahtet, aber der Native-Activity-Klebstoff ist noch nicht fertig. Wir sagen niemandem, dass er Android mit Bloom ausliefern soll.
- watchOS. Shader kompilieren, der Plattform-Stub ist da, aber wir sind durch Perrys watchOS-Support blockiert, bevor das echt wird.
- Virtualisierte Geometrie. Kein Nanite-Äquivalent, keine Mesh-Shader, kein Hardware-Raytracing. Das steht auf der Roadmap, nicht im Binary.
- Skelettanimations-Limit. 128 Joints pro Skelett, hartes Limit, wegen der UBO-Größe. Große Rigs brauchen heute Workarounds.
- Der Szenengraph ist jung. Transformationen, Sichtbarkeit, Schatten und Material-Binding funktionieren alle. Query-Systeme und breitere Optimierungs-Passes existieren noch nicht.
- User-Shader. Du kannst WGSL von Hand schreiben und über die Material-Pipeline laden, aber es gibt keinen In-Engine-Shader-Graph und keine Runtime-Shader-Kompilierung aus TypeScript.
Die Form der API
Wir haben uns für die Immediate-Mode-Teile der API stark bei Raylib bedient. Wenn du schon ein Raylib-Spiel geschrieben hast, überträgt sich die Muscle Memory:
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();
} Für 3D- und Physik-Arbeit gilt dieselbe Philosophie: schlichte Interfaces, reine Funktionen, keine versteckten Zustandsmaschinen. Eine Kamera ist ein Object Literal. Ein Rigid Body ist ein Handle. Die Render-Pipeline wird konfiguriert, indem man Funktionen in einer bestimmten Reihenfolge aufruft, nicht indem man Listener auf einem unsichtbaren Orchestrator registriert.
Was als Nächstes kommt
Unsere Kurzliste für die nächsten Wochen:
- Den Android-Native-Activity-Klebstoff fertigstellen und Android als ausliefertauglich erklären.
- Die Szenengraph-Arbeit über “basic” hinaus zu wirklich nützlich treiben: Queries, Verfeinerung des Frustum-Cullings, Instancing-Helfer.
- Eine erste Version der Editor-Integration landen, sodass du an einer Szene iterieren kannst, ohne dein Spiel neu zu starten.
- Die Beispielspiele als Open Source veröffentlichen, inklusive einer Demo, die etwas größer ist als Pong.
- Die Perry-Kompilierungspipeline im Detail aufschreiben. Mehrere Leute haben danach gefragt.
Probier es aus
Bloom ist Open Source unter MIT. Das gesamte Repository liegt auf GitHub. Wenn du mitlesen willst, ohne zu forken, gibt es in den Docs einen 12-zeiligen Quick Start, und die Showcase-Seite listet, was wir selbst damit bauen.
So oder so: Danke fürs Reinschauen. Wir posten hier weiter, sobald größere Stücke landen.