Add ManaVoxel — a 2D top-down pixel platform for creating and programming miniature worlds in the browser. This commit includes: - SvelteKit + PixiJS 8 web app with chunk-based tilemap renderer - Game engine: camera (scroll/zoom), input (keyboard/mouse/touch), player with AABB collision, editor/play mode toggle - Pixel editor tools: brush, eraser, flood fill, pipette, box fill, line (Bresenham), undo/redo stack - Shared types package: materials, areas, items, network protocol, inventory - Demo world generator with terrain, buildings, trees - Material palette UI with 15 materials, keyboard shortcuts - Comprehensive design documents (Roblox analysis, tech stack options, voxel resolution analysis, 2D alternative comparison, full project plan) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
42 KiB
Voxel Platform MVP: Design & Technische Architektur
Eine reine Voxel-Welt, in der alles im Spiel erschaffen und programmiert wird
Inhaltsverzeichnis
- Die Vision
- Voxel-Rendering: Techniken & Tradeoffs
- Voxel-Resolution: Optionen & adaptive Skalierung
- Der In-Game Voxel-Editor
- Programmierbare Items & Artefakte
- MVP-Definition: Was ist das Minimum?
- Technische Architektur des MVP
- Gefahren, Schwierigkeiten & Mitigationen
- Datenmodell
- Build-Plan
1. Die Vision
Was macht diese Plattform einzigartig?
Roblox: Entwickler bauen Games in einem externen Editor (Roblox Studio)
→ Spieler spielen die fertigen Games
Minecraft: Spieler bauen Strukturen aus vordefinierten Bloecken
→ Bloecke haben keine programmierbare Logik (ohne Mods)
Unsere Plattform:
Alles entsteht IM SPIEL -- in einem Voxel-Editor
→ Spieler FORMEN Items/Objekte aus Voxeln (wie digitale Toepferei)
→ Spieler PROGRAMMIEREN diese Items (Trigger, Effekte, Verhalten)
→ Spieler TEILEN ihre Kreationen (Marketplace, Cross-Game)
→ Spieler SPIELEN in Welten aus diesen Kreationen
Der Kern-Loop:
Erschaffen (Voxel-Editor)
│
▼
Programmieren (Visual Scripting / Code)
│
▼
Testen (sofort spielbar)
│
▼
Teilen (Marketplace, andere Welten)
│
▼
Entdecken & Spielen
│
└──→ zurueck zu Erschaffen (inspiriert durch Entdecktes)
2. Voxel-Rendering: Techniken & Tradeoffs
Die vier gaengigen Ansaetze
1. Greedy Meshing (Minecraft-Ansatz)
Voxel-Daten (3D-Array) Optimiertes Mesh
┌─┬─┬─┬─┐ ┌───────────┐
│█│█│█│█│ benachbarte gleiche │ │
├─┼─┼─┼─┤ Flaechen werden → │ 1 Quad │
│█│█│█│█│ zu einem Quad │ statt 8 │
├─┼─┼─┼─┤ zusammengefasst │ │
│ │ │ │ │ └───────────┘
└─┴─┴─┴─┘
- Wie es funktioniert: Voxel-Daten werden pro Chunk (z.B. 16x16x16) durchlaufen. Benachbarte Voxel gleichen Typs werden zu einem einzelnen Quad (Rechteck) zusammengefasst. Nur sichtbare Flaechen werden gerendert (Flaechen zwischen zwei soliden Bloecken werden weggelassen).
- Performance: Exzellent. Reduziert Triangle-Count um 80-95%. Minecraft-artige Welten mit Millionen Bloecken laufen auf Handys.
- Qualitaet: Blockig. Alle Kanten sind rechtwinklig. Klassischer "Voxel-Look".
- Empfehlung: Bester Startpunkt fuer MVP. Bewaehrt, schnell, einfach zu implementieren.
2. Marching Cubes / Surface Nets (glatte Voxel)
Voxel-Daten (SDF/Dichte) Glattes Mesh
┌─┬─┬─┬─┐ ╭───────────╮
│▓│█│█│▓│ Isosurface wird │ │
├─┼─┼─┼─┤ extrahiert und → │ Glattes │
│█│█│█│█│ als Dreiecksmesh │ Mesh │
├─┼─┼─┼─┤ gerendert │ │
│▓│▓│▓│▓│ ╰───────────╯
└─┴─┴─┴─┘
- Wie es funktioniert: Statt diskreter Bloecke speichert jeder Voxel einen Dichte-Wert (Signed Distance Field). Marching Cubes extrahiert eine Isosurface als Dreiecksmesh.
- Performance: Langsamer als Greedy Meshing. Mehr Dreiecke, komplexere Mesh-Generierung.
- Qualitaet: Glatte, organische Formen. Terrain wie in No Man's Sky, Deep Rock Galactic.
- Empfehlung: Fuer Phase 2 (Terrain-Sculpting). Nicht fuer MVP.
3. Sparse Voxel Octree (SVO) + Ray Marching
Octree-Struktur GPU Ray Marching
┌───────────┐ Kamera → Strahl →
│ ┌─┬─┐ │ Octree traversieren →
│ │█│ │ │ Leere Bereiche Farbe + Normal zurueck
│ ├─┼─┤ │ werden nicht →
│ │ │█│ │ gespeichert Kein Mesh noetig!
│ └─┴─┘ │
└───────────┘
- Wie es funktioniert: Voxel-Daten werden in einem Octree gespeichert (jeder Knoten teilt sich in 8 Kinder). GPU-Compute-Shader schiesst Strahlen durch den Octree und findet Voxel-Treffer.
- Performance: GPU-intensiv, aber skaliert besser bei hoher Resolution. Kein Mesh-Generation-Bottleneck.
- Qualitaet: Kann extrem hohe Resolutionen rendern. Teardown nutzt dies (2cm Voxel, 500M+ Voxel).
- Empfehlung: Langfristig interessant, aber zu komplex fuer MVP. Braucht tiefes GPU-Wissen.
4. Hybrid: Greedy Mesh + Octree LOD
Nah: Greedy Meshing (volle Resolution, wenige Chunks)
│
Mittel: Octree LOD Level 1 (halbe Resolution, mehr Chunks)
│
Fern: Octree LOD Level 2 (viertel Resolution, Horizont)
│
Sehr fern: Impostors oder gar nicht rendern
- Wie es funktioniert: Nahbereich wird klassisch mit Greedy Meshing gerendert. Entfernte Chunks werden in niedrigerer Resolution gerendert (Octree-LOD). Sehr entfernte Bereiche werden als 2D-Impostors oder gar nicht angezeigt.
- Performance: Best of both worlds. Nah: hohe Qualitaet. Fern: niedrige Kosten.
- Empfehlung: Ziel-Architektur. Greedy Mesh fuer MVP, Octree-LOD in Phase 2.
Empfehlung fuer unseren Stack
Phase 1 (MVP): Greedy Meshing + Chunk-System (16³ oder 32³)
Phase 2: + Octree-LOD fuer Fernbereich
Phase 3: + Optional: SVO Ray Marching fuer Ultra-Detail-Modus
3. Voxel-Resolution: Optionen & adaptive Skalierung
Resolution-Stufen
| Resolution | Voxelgroesse | Vergleich | Voxel pro m³ | Speicher/Chunk (32³) |
|---|---|---|---|---|
| Low (Minecraft) | 1.0 m | Minecraft-Bloecke | 1 | ~32 KB |
| Medium | 0.5 m | LEGO-artig | 8 | ~256 KB |
| High | 0.25 m | Detaillierter | 64 | ~2 MB |
| Very High | 0.1 m | Trove/Hytale-aehnlich | 1.000 | ~32 MB |
| Ultra (Teardown) | 0.02 m | Fotorealistisch zerstoerbar | 125.000 | nicht praktikabel als Array |
Empfehlung: 0.25m Basis-Resolution mit adaptiver Skalierung
Warum 0.25m (25cm)?
- Detailliert genug fuer erkennbare Items: Ein Schwert ist ~4-6 Voxel breit, ein Charakter ~7 Voxel breit, ~24 hoch
- Blocky genug fuer charmante Aesthetik (MagicaVoxel-Style)
- Performant genug fuer Browser/Mobile
- Editierbar -- einzelne Voxel sind gross genug zum Anklicken/Platzieren
- Ein 32³-Chunk deckt 8m x 8m x 8m ab -- ein Raum, ein kleines Haus
Alternative: 0.125m (12.5cm, 8 Voxel pro Meter)
- Doppelte Detail-Stufe, aber 8x mehr Daten
- Fuer Items/Artefakte im Editor (Zoom-Modus), nicht fuer ganze Welten
Adaptive Skalierung pro Geraet
┌─────────────────────────────────────────────────────┐
│ RENDERING QUALITY TIERS │
│ │
│ Tier 1: High-End Desktop (RTX 3060+) │
│ ├─ View Distance: 256m (32 Chunks) │
│ ├─ Voxel Resolution: 0.25m (volle Basis) │
│ ├─ LOD: 3 Stufen │
│ ├─ Schatten: Ja (Shadow Maps) │
│ ├─ AO: Screen-Space Ambient Occlusion │
│ └─ Max Voxel im Sichtfeld: ~2M │
│ │
│ Tier 2: Mid-Range Desktop / Tablet │
│ ├─ View Distance: 128m (16 Chunks) │
│ ├─ Voxel Resolution: 0.25m (nah), 0.5m (fern) │
│ ├─ LOD: 2 Stufen │
│ ├─ Schatten: Vereinfacht │
│ ├─ AO: Voxel-basiert (precomputed) │
│ └─ Max Voxel im Sichtfeld: ~800K │
│ │
│ Tier 3: Low-End / Mobile │
│ ├─ View Distance: 64m (8 Chunks) │
│ ├─ Voxel Resolution: 0.5m (nah), 1.0m (fern) │
│ ├─ LOD: 1 Stufe │
│ ├─ Schatten: Nein (nur Ambient) │
│ ├─ AO: Nein │
│ └─ Max Voxel im Sichtfeld: ~200K │
│ │
│ Automatische Erkennung: │
│ - WebGPU Adapter Limits (max texture size, etc.) │
│ - FPS-Monitoring: Tier runterstufen bei <30fps │
│ - User Override moeglich │
└─────────────────────────────────────────────────────┘
Wie funktioniert LOD fuer Voxel?
Chunk auf LOD 0 (volle Resolution, 0.25m):
┌─┬─┬─┬─┬─┬─┬─┬─┐
│A│A│B│B│A│A│C│C│
├─┼─┼─┼─┼─┼─┼─┼─┤
│A│A│B│B│A│A│C│C│
├─┼─┼─┼─┼─┼─┼─┼─┤
│D│D│D│D│E│E│E│E│
├─┼─┼─┼─┼─┼─┼─┼─┤
│D│D│D│D│E│E│E│E│
└─┴─┴─┴─┴─┴─┴─┴─┘
Chunk auf LOD 1 (halbe Resolution, 0.5m):
┌───┬───┬───┬───┐
│ A │ B │ A │ C │ ← 2x2 Voxel → 1 Voxel
├───┼───┼───┼───┤ (dominanter Typ gewinnt)
│ D │ D │ E │ E │
└───┴───┴───┴───┘
Chunk auf LOD 2 (viertel Resolution, 1.0m):
┌───────┬───────┐
│ A │ A │ ← 4x4 Voxel → 1 Voxel
├───────┼───────┤
│ D │ E │
└───────┴───────┘
LOD-Meshes werden vorberechnet wenn der Chunk sich aendert und gecached. Der Uebergang zwischen LOD-Stufen nutzt ein "Skirt" (ueberlappende Kante) um Luecken zu vermeiden.
Dual-Resolution fuer Items vs. Welt
WELT-VOXEL: 0.25m Resolution
├── Terrain, Gebaeude, Landschaft
├── Grosse Strukturen
└── Immer Greedy Meshing + LOD
ITEM-VOXEL: 0.0625m (6.25cm) Resolution -- 4x feiner!
├── Schwerter, Werkzeuge, Schmuck, Ruenen
├── Kleine detaillierte Objekte
├── Im Voxel-Editor: Zoom auf Item-Grid
└── Als Mesh gerendert (einmal generiert, wiederverwendet)
Warum zwei Resolutionen?
Ein Schwert bei 0.25m waere ~4 Voxel lang -- zu grob. Bei 0.0625m ist es ~16 Voxel lang und kann echte Details haben (Klinge, Griff, Verzierung). Die Item-Meshes werden einmal generiert und als regulaere 3D-Objekte in der Welt platziert -- kein Performance-Unterschied zum Rendern normaler Meshes.
4. Der In-Game Voxel-Editor
Editor-Modi
┌─────────────────────────────────────────────────────┐
│ VOXEL EDITOR │
│ │
│ [Welt-Modus] [Item-Modus] [Charakter-Modus] │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ │ │
│ │ 3D Viewport │ │
│ │ (Bevy Renderer) │ │
│ │ │ │
│ │ Voxel-Cursor zeigt Platzierungsort │ │
│ │ │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ Werkzeuge: │
│ [Pinsel] [Radierer] [Fuellen] [Pipette] │
│ [Box] [Kugel] [Linie] [Spiegeln] │
│ [Kopieren] [Einfuegen] [Undo] [Redo] │
│ │
│ Palette: │
│ [█ Stein] [█ Holz] [█ Glas] [█ Metall] [█ ...] │
│ [█ Custom Farbe/Material] │
│ │
│ Eigenschaften (rechte Seite): │
│ ┌─────────────────────┐ │
│ │ Material: Stein │ │
│ │ Farbe: #8B7355 │ │
│ │ Transparenz: 0% │ │
│ │ Leuchten: Nein │ │
│ │ Physik: Solid │ │
│ │ Sound: stone_hit │ │
│ └─────────────────────┘ │
└─────────────────────────────────────────────────────┘
Welt-Modus (0.25m Voxel)
- Terrain formen, Gebaeude bauen, Landschaften gestalten
- Grosse Pinsel (1-10 Voxel Radius)
- Terrain-Tools: Erhoehen, Absenken, Glaeetten, Malen
- Prefab-System: Gespeicherte Strukturen wiederverwenden
- Kollaborativ -- mehrere Creator gleichzeitig (CRDT via mana-sync)
Item-Modus (0.0625m Voxel)
- Feindetailliertes Sculpting fuer Items, Werkzeuge, Artefakte
- 32x32x32 Grid (= 2m x 2m x 2m reale Groesse) oder kleiner
- MagicaVoxel-aehnliche UX: Rotation, Schicht-fuer-Schicht-Editing
- Anchor Points: Wo das Item gehalten/getragen/platziert wird
- Hit Box: Kollisionsbereich definieren
- Animation Frames: Mehrere Zustaende fuer animierte Items (optional)
Charakter-Modus (0.0625m oder 0.125m)
- Avatar-Koerper aus Voxeln gestalten
- Vordefinierte Skelett-Struktur (Kopf, Torso, Arme, Beine)
- Voxel werden ans Skelett gebunden (Rigging)
- Animations-Preview mit Standard-Animationen (Laufen, Springen, Idle)
Editor-UX: Touch/Mobile-tauglich
Desktop: Mobile/Tablet:
- Mausrad: Zoom - Pinch: Zoom
- Rechtsklick: Orbit - 2-Finger-Drag: Orbit
- Linksklick: Platzieren - Tap: Platzieren
- Shift+Klick: Loeschen - Long Press: Loeschen
- Ctrl+Z: Undo - Shake/Button: Undo
- Tastatur: Tool-Shortcuts - Toolbar unten
5. Programmierbare Items & Artefakte
Das Property-System
Jedes Voxel-Item bekommt ein Component-basiertes Property-System (ECS-nativ):
Schwert "Flammenklinge" (Voxel-Item)
│
├── VoxelData → 32x8x2 Voxel-Grid (Klinge + Griff)
├── ItemInfo → Name, Beschreibung, Icon, Creator
├── Holdable → Anchor: rechte Hand, Offset, Rotation
├── MeleeDamage → Basis: 10, Typ: Slash
├── ElementalEffect → Feuer, Staerke: 5, Partikel: flame_burst
├── Durability → Max: 100, Aktuell: 100, RepairCost: 5 Mana
├── Rarity → Legendary (goldener Rahmen)
├── Tradeable → true, MinPrice: 50 Mana
├── OnHit → Script: "spawn_fire_particles(target)"
├── OnEquip → Script: "player.glow(orange)"
└── CustomProperties → { "forged_by": "alice", "enchant_level": 3 }
Drei Programmier-Ebenen
Ebene 1: Property Sliders (fuer alle, ab 6 Jahre)
┌─────────────────────────────────────────┐
│ ITEM EIGENSCHAFTEN │
│ │
│ Schaden: [████████░░] 80 │
│ Reichweite: [██░░░░░░░░] 20 │
│ Geschwind.: [██████░░░░] 60 │
│ Haltbarkeit: [██████████] 100 │
│ │
│ Element: [🔥 Feuer ▼] │
│ Sound: [⚔️ Schwert-Treffer ▼] │
│ Partikel: [✨ Funkenspur ▼] │
│ Seltenheit: [⭐ Legendaer ▼] │
│ │
│ [Testen] [Speichern] │
└─────────────────────────────────────────┘
Kein Code, keine Logik. Einfach Werte einstellen. Das Item "funktioniert" sofort mit Standard-Verhalten basierend auf den Werten.
Ebene 2: Trigger-Action System (ab 8-10 Jahre)
┌─────────────────────────────────────────┐
│ VERHALTEN EDITOR │
│ │
│ WENN [Spieler beruehrt ▼] │
│ DANN [Spieler bekommt Item ▼] │
│ │
│ WENN [Item benutzt wird ▼] │
│ DANN [Feuerball schiessen ▼] │
│ UND [Sound abspielen: boom ▼] │
│ UND [5 Schaden an Ziel ▼] │
│ WARTE [0.5 Sekunden] │
│ DANN [Partikel an Ziel ▼] │
│ │
│ WENN [Haltbarkeit = 0 ▼] │
│ DANN [Item zerstoeren ▼] │
│ UND [Sound: glass_break ▼] │
│ │
│ [+ Neue Regel] [Testen] [Speichern] │
└─────────────────────────────────────────┘
Verfuegbare Trigger:
- Spieler beruehrt / betritt Bereich / verlaesst Bereich
- Item wird benutzt (Primaer / Sekundaer)
- Item wird aufgenommen / abgelegt / geworfen
- Timer (alle X Sekunden)
- HP unter/ueber X
- Tageszeit / Wetter
- Anderes Item in der Naehe
- Custom Event (von anderen Items ausgeloest)
Verfuegbare Aktionen:
- Schaden/Heilen
- Partikel/Sound/Licht abspielen
- Spieler teleportieren / pushen / verlangsamen
- Item spawnen / zerstoeren
- Voxel setzen / loeschen (Welt veraendern!)
- Nachricht anzeigen
- Variable setzen / abfragen
- Custom Event senden
Ebene 3: TypeScript-Scripting (ab 12+ Jahre, Creator)
// sword_flame.ts -- Kompiliert zu WASM, laeuft in Sandbox
import { onHit, onEquip, spawn, damage, particles } from '@platform/api';
// Wird aufgerufen wenn das Schwert trifft
onHit((event) => {
const target = event.target;
// Basis-Schaden
damage(target, 10 + this.properties.enchantLevel * 2);
// Feuer-Effekt
particles.spawn('fire_burst', target.position, {
count: 20,
lifetime: 0.5,
color: '#ff4400',
});
// Feuer-DoT (Damage over Time)
target.addEffect('burning', {
damage: 2,
interval: 1.0,
duration: 3.0,
});
// Haltbarkeit reduzieren
this.durability -= 1;
if (this.durability <= 0) {
this.destroy();
particles.spawn('shatter', this.position);
}
});
onEquip((player) => {
player.setGlow({ color: '#ff6600', intensity: 0.5 });
});
Wie die drei Ebenen zusammenspielen
Ebene 1 (Sliders) ──kompiliert──→ Standard-Trigger-Actions
│
Ebene 2 (Trigger-Action) ──kompiliert──→ TypeScript
│
Ebene 3 (TypeScript) ──kompiliert──→ WASM (Wasmtime Sandbox)
Alles wird zu WASM. Ebene 1 und 2 sind nur UX-Schichten ueber dem gleichen System. Ein Kind, das mit Slidern anfaengt, kann spaeter die generierten Trigger-Actions sehen und modifizieren -- und irgendwann den TypeScript-Code direkt schreiben. Nahtloser Lernpfad.
Cross-Game Item-Portabilitaet
Item "Flammenklinge" existiert als:
├── VoxelData (Aussehen) → Reist immer mit
├── ItemInfo (Metadaten) → Reist immer mit
├── Platform Properties → Vom Game interpretiert
│ ├── Rarity: Legendary
│ ├── Element: Fire
│ └── BaseDamage: 10
└── Game-spezifische Scripts → NUR im Ursprungs-Game
In Game A (Fantasy RPG):
→ Schwert macht 10 Schaden + Feuer-DoT
→ Scripts laufen wie vom Creator definiert
In Game B (Parkour):
→ Schwert ist kosmetisch (kein Kampfsystem)
→ Wird als Avatar-Accessoire angezeigt
→ Rarity bestimmt visuellen Glow-Effekt
In Game C (Trading Card Game):
→ Schwert-Voxelmodell wird als Karten-Illustration genutzt
→ Properties (Damage, Element) werden als Kartenwerte interpretiert
Regel: Platform-Properties reisen. Game-spezifische Scripts bleiben im Ursprungs-Game. Jedes Game entscheidet selbst, wie es Platform-Properties interpretiert.
6. MVP-Definition: Was ist das Minimum?
MVP = "Eine Welt, ein Editor, Items programmieren, zusammen spielen"
WAS IM MVP IST: WAS NICHT IM MVP IST:
✅ Voxel-Welt (0.25m, flat terrain) ❌ Terrain-Generation (Perlin Noise)
✅ Welt-Editor (platzieren/loeschen) ❌ Marching Cubes / glatte Voxel
✅ Item-Editor (0.0625m, detailliert) ❌ Charakter-Editor (Standard-Avatar)
✅ Property Sliders (Ebene 1) ❌ TypeScript-Scripting (Ebene 3)
✅ Trigger-Action (Ebene 2) ❌ Cross-Game Items
✅ Multiplayer (2-20 Spieler) ❌ Matchmaking (manuelle Server)
✅ Basis-Physik (Gravitation, Kollision)❌ Voxel-Destruction-Physik
✅ Inventar (Items aufheben/tragen) ❌ Marketplace (manuelles Teilen)
✅ Login (mana-auth) ❌ Economy (kein Mana im MVP)
✅ Offline-Editor (Dexie.js) ❌ Voice Chat
✅ Guest Mode ❌ AI NPCs
✅ Basis-Beleuchtung (Ambient + Sun) ❌ Dynamische Schatten
✅ 5-10 Basis-Materialien ❌ Custom Materialien
✅ Speichern/Laden (Local-First) ❌ Versionierung
MVP User Stories
Als Spieler kann ich:
- Eine Voxel-Welt betreten (Browser, kein Download)
- Bloecke platzieren und loeschen (Welt-Editor)
- Ein Item im Voxel-Editor formen (z.B. ein Schwert)
- Dem Item Eigenschaften geben (Schaden, Element, Sound)
- Dem Item Verhalten geben ("Wenn benutzt → Feuerball")
- Das Item in mein Inventar nehmen und benutzen
- Die Welt mit Freunden teilen (Link → Multiplayer)
- Offline im Editor arbeiten und spaeter synchronisieren
- Als Gast spielen ohne Account
Als Creator kann ich: 10. Eine komplette Spielwelt bauen (Terrain + Gebaeude + Items) 11. Items mit komplexen Trigger-Action-Ketten programmieren 12. Die Welt veroeffentlichen (andere koennen beitreten)
7. Technische Architektur des MVP
Chunk-System
Welt = Grid aus Chunks
Chunk (32 x 32 x 32 Voxel = 8m x 8m x 8m bei 0.25m Resolution):
┌──────────────────────────────────┐
│ header: │
│ position: (cx, cy, cz) │
│ dirty: bool │
│ mesh: Option<GpuMesh> │
│ lod_meshes: [Option<GpuMesh>] │
│ │
│ data: │
│ voxels: [u16; 32*32*32] │ ← 64 KB pro Chunk
│ (material_id + flags) │
│ │
│ palette: [(Color, MaterialType)]│ ← Chunk-lokale Palette
│ (max 256 Eintraege) │
└──────────────────────────────────┘
Speicher pro Chunk: ~64 KB (Voxel) + ~1-10 KB (Palette) + Mesh (variabel)
100 Chunks geladen: ~8 MB Voxel-Daten + ~50 MB Meshes = ~58 MB
→ Passt problemlos in Browser-WASM-Memory
Voxel-Daten-Encoding
Jeder Voxel = 16 Bit (u16):
Bits 0-7: Material-Index (256 Materialien pro Chunk-Palette)
Bit 8: Transparent (ja/nein)
Bit 9: Emissive (leuchtet ja/nein)
Bits 10-11: Rotation (0°, 90°, 180°, 270° -- fuer nicht-symmetrische Bloecke)
Bits 12-15: Reserved (Custom Flags, Zustaende)
Material 0 = Luft (leer)
Alternative fuer hoehere Vielfalt: u32 (4 Bytes pro Voxel)
→ 128 KB pro 32³ Chunk, 16M Farben, mehr Flags
→ Empfehlung: Mit u16 starten, u32 wenn noetig
Mesh-Generation Pipeline (WebGPU Compute)
Chunk aendert sich (Voxel gesetzt/geloescht)
│
▼
Greedy Meshing Algorithmus (CPU oder GPU Compute)
│
├── Fuer jede der 6 Richtungen (+X, -X, +Y, -Y, +Z, -Z):
│ 1. Scanne Schicht fuer Schicht
│ 2. Finde zusammenhaengende Rechtecke gleichen Materials
│ 3. Erzeuge ein Quad pro Rechteck
│
▼
Vertex Buffer (Position, Normal, UV, Color, AO)
│
▼
Upload zu GPU → Rendern
Performance-Ziel: <5ms pro Chunk-Remesh (damit Echtzeit-Editing fluessig)
Bevy ECS Architektur
// Kern-Components fuer das Voxel-System
// Ein Chunk in der Welt
struct Chunk {
position: IVec3, // Chunk-Koordinaten
voxels: [u16; 32*32*32], // Voxel-Daten
palette: Vec<Material>, // Chunk-lokale Material-Palette
dirty: bool, // Mesh muss neu generiert werden
}
// Ein Voxel-Item (im Inventar oder in der Welt)
struct VoxelItem {
voxels: Vec<u16>, // Item-Voxel-Daten (variable Groesse)
dimensions: UVec3, // z.B. 16x32x4
resolution: f32, // 0.0625 fuer Items
anchor: Vec3, // Haltepunkt
hitbox: Aabb, // Kollisionsbox
}
// Properties eines Items
struct ItemProperties {
name: String,
damage: Option<f32>,
element: Option<Element>,
durability: Option<(f32, f32)>, // (aktuell, max)
rarity: Rarity,
custom: HashMap<String, Value>,
}
// Trigger-Action-Behavior
struct ItemBehavior {
triggers: Vec<Trigger>, // Wann
actions: Vec<Action>, // Was passiert
wasm_module: Option<WasmModule>, // Kompiliertes Script
}
// Spieler
struct Player {
inventory: Vec<Entity>, // Item-Entities
held_item: Option<Entity>, // Aktuell gehaltenes Item
position: Vec3,
health: f32,
}
Netzwerk-Protokoll fuer Voxel-Sync
CHUNK SYNC (Unreliable, haeufig):
Client verbindet sich:
1. Server sendet alle Chunks im Radius (komprimiert)
- RLE (Run-Length Encoding) + LZ4: ~64 KB Chunk → ~2-10 KB komprimiert
- Bei 100 Chunks: ~200 KB - 1 MB Initial-Load
2. Spieler bewegt sich:
- Server sendet neue Chunks am Rand
- Client entlaedt Chunks ausserhalb des Radius
3. Voxel-Aenderung:
Client → Server: SetVoxel { chunk: (2,0,1), pos: (15,3,7), material: 42 }
Server validiert (Berechtigung? Physik OK?)
Server → Alle Clients im Bereich: VoxelChanged { ... }
Batching: Mehrere Aenderungen pro Frame zusammenfassen
ITEM SYNC (Reliable, bei Aenderung):
Item erstellt/modifiziert:
Client → Server: CreateItem { voxel_data, properties, behavior }
Server validiert (WASM-Script sicher? Properties in Bounds?)
Server speichert → PostgreSQL + mana-sync
Server → Relevante Clients: ItemCreated { ... }
Kompression: Voxel-Daten klein halten
Rohe Chunk-Daten: 32³ × 2 Bytes = 65.536 Bytes (64 KB)
RLE (Run-Length Encoding):
[0,0,0,0,0,5,5,5,0,0] → [(0,5), (5,3), (0,2)]
Typisch 60-90% Reduktion fuer natuerliche Welten
LZ4 (schnelle Kompression):
Nach RLE nochmal ~50% Reduktion
Dekompression: ~2 GB/s (vernachlaessigbar)
Typische komprimierte Chunk-Groesse:
Leerer Chunk (nur Luft): ~10 Bytes
Flaches Terrain: ~500 Bytes - 2 KB
Komplexes Gebaeude: ~5-15 KB
Maximal gefuellter Chunk: ~30 KB
Netzwerk-Budget pro Spieler:
100 Chunks geladen × 5 KB = ~500 KB Initialtransfer
Laufend: ~1-5 KB/s fuer Aenderungen
→ Trivial fuer jede Internetverbindung
Local-First: Offline Voxel-Editor
Dexie.js Schema:
worlds: {
id: string,
name: string,
seed: number,
created: Date,
modified: Date,
settings: WorldSettings
}
chunks: {
id: string, // world_id + chunk_position
worldId: string,
position: [number, number, number],
voxelData: Uint8Array, // Komprimiert (RLE + LZ4)
palette: Material[],
version: number, // Fuer Sync-Konflikte
modified: Date
}
items: {
id: string,
worldId: string,
voxelData: Uint8Array, // Komprimiertes Item-Grid
dimensions: [number, number, number],
properties: ItemProperties,
behavior: TriggerAction[],
script?: string, // TypeScript-Quellcode
wasmBinary?: Uint8Array, // Kompiliertes WASM
modified: Date
}
inventory: {
id: string,
playerId: string,
itemId: string,
slot: number,
quantity: number
}
Sync via mana-sync:
- Chunks: Field-Level LWW (wie bestehende Collections)
- Items: Ganzes Item synct (Items sind klein genug)
- Konflikte: Letzter Schreiber gewinnt (LWW) -- fuer Voxel OK
(Alternative: CRDT per Voxel -- overkill fuer MVP)
8. Gefahren, Schwierigkeiten & Mitigationen
Technische Gefahren
1. Mesh-Generation-Performance
Problem: Jedes Mal wenn ein Spieler einen Block setzt, muss der Chunk-Mesh neu generiert werden. Greedy Meshing fuer 32³ = 32.768 Voxel braucht ~2-10ms auf CPU. Bei schnellem Bauen (10 Bloecke/Sekunde) wird das zum Bottleneck.
Mitigation:
- Mesh-Generation in Web Worker (separater Thread)
- Dirty-Flag-System: Nur geaenderte Chunks remeshen
- Doppel-Buffering: Alten Mesh anzeigen waehrend neuer generiert wird
- GPU Compute Meshing (WebGPU): ~10x schneller als CPU, aber komplexer zu implementieren
- Rate Limiting: Max 2-3 Chunk-Remeshes pro Frame
2. Memory auf Mobile/Low-End
Problem: 100 Chunks × (64 KB Voxel + 200 KB Mesh) = ~26 MB nur fuer sichtbare Welt. Dazu kommen Engine, UI, WASM-Runtime. Mobile Browser haben oft nur 200-500 MB WASM-Memory.
Mitigation:
- Weniger Chunks auf Mobile laden (8 statt 32 Radius)
- Komprimierte Voxel-Daten (RLE), nur dekomprimieren wenn gebraucht
- Mesh-LOD: Entfernte Chunks haben einfachere Meshes
- Chunk-Eviction: LRU-Cache, aelteste Chunks entladen
- Memory-Budget-System: Automatisch Qualitaet reduzieren bei Speicherdruck
3. Netzwerk-Bandbreite bei vielen Aenderungen
Problem: 20 Spieler bauen gleichzeitig → hunderte Voxel-Aenderungen/Sekunde → Bandbreite explodiert.
Mitigation:
- Delta-Compression: Nur geaenderte Voxel senden, nicht ganze Chunks
- Batching: Aenderungen pro Tick zusammenfassen (16ms-Fenster)
- Priorisierung: Nahe Aenderungen zuerst, ferne spaeter
- Rate Limit pro Spieler: Max 30 Voxel-Aenderungen/Sekunde
- Area of Interest: Nur Aenderungen im sichtbaren Bereich empfangen
4. WASM-Script-Sicherheit
Problem: User-Scripts koennten Endlosschleifen haben, zu viel Memory nutzen, oder unerwartete Interaktionen zwischen Items verursachen.
Mitigation:
- Fuel Metering: Max 10.000 Instructions pro Item-Tick
- Memory Limit: 4 MB pro Script (ein Item braucht typisch <100 KB)
- Timeout: Script wird nach 5ms abgebrochen
- Capability System: Scripts koennen nur deklarierte APIs nutzen
- Sandboxed Side Effects:
damage()geht nicht direkt → wird als Event an Server gesendet, Server validiert - Anti-Spam: Max 10 Events pro Script pro Sekunde
5. Voxel-Physik ist schwer
Problem: Wenn ein Spieler Bloecke unter einem Gebaeude entfernt, sollte es einstuerzen? Strukturelle Integritaet ist ein extrem schwieriges Problem (O(n) Floodfill bei jeder Aenderung).
Mitigation fuer MVP:
- Keine strukturelle Integritaet im MVP. Bloecke schweben, wie in Minecraft Creative Mode.
- Items haben Schwerkraft (fallen, wenn nicht auf einem Block)
- Spieler haben Schwerkraft
- Phase 2: Optionale "Gravity" Flag pro Chunk → einfacher Floodfill
- Phase 3: Echte strukturelle Integritaet (wie Valheim/Teardown) -- grosser Engineering-Aufwand
6. Cross-Platform Rendering-Konsistenz
Problem: Ein Item sieht auf Desktop anders aus als auf Mobile (verschiedene LOD-Stufen, Beleuchtung).
Mitigation:
- Items werden mit fester Resolution gerendert (immer 0.0625m, kein LOD fuer Items)
- Nur Welt-Chunks bekommen LOD
- Beleuchtung: Ambient + einfache Directional Light → sieht ueberall gleich aus
- Optional: Item-Preview als 2D-Sprite cachen (fuer Inventar-Anzeige)
Design-Gefahren
7. "Minecraft-Klon"-Wahrnehmung
Problem: Jedes Voxel-Game wird sofort mit Minecraft verglichen.
Differenzierung:
- Programmierbare Items -- das hat Minecraft nicht (ohne Mods)
- In-Game Item-Editor mit hoher Resolution -- kein externes Tool
- Trigger-Action-System -- nicht nur Bauen, sondern Verhalten definieren
- Cross-Game Items -- Items reisen zwischen Welten
- Browser-nativ -- kein Download
- Aesthetik: MagicaVoxel-Style statt Minecraft-Bloecke (0.25m statt 1m, Farben statt Texturen)
8. Zu komplex fuer Kinder
Problem: Drei Programmier-Ebenen + Voxel-Editor + 3D-Navigation = Ueberforderung.
Mitigation:
- Onboarding-Tutorial: Geführtes Erstes Item bauen → Property Slider → Benutzen → Wow-Moment
- Templates: Vorgefertigte Items zum Modifizieren (einfacher als from scratch)
- Progressive Disclosure: Trigger-Actions erst zeigen wenn Sliders gemeistert
- TypeScript erst fuer angemeldete Creator (nicht im Guest Mode)
9. Moderation von Voxel-Inhalten
Problem: Spieler bauen unangemessene Formen aus Voxeln (wie Roblox's "Condo Games"-Problem, aber mit Voxeln).
Mitigation:
- Voxel-Modell → Render zu Bild → Vision-Classifier (bestehende AI-Pipeline)
- Community-Reporting
- Automatische Scans bei Veroeffentlichung
- Spaeter: Behavioral Analysis (welche Spieler besuchen welche Welten)
10. Performance-Erwartungen im Browser
Problem: Browser-Spiele werden als "langsam" wahrgenommen. WebGPU ist neu.
Realitaet:
- WebGPU + WASM ist 80-90% von nativem Performance
- Voxel-Rendering ist GPU-freundlich (einfache Geometrie, wenig Overdraw)
- Minecraft Java Edition laeuft auf aelterer Technik und ist beliebter als Bedrock
- Ziel: 60fps auf Mid-Range Desktop, 30fps auf Mid-Range Mobile
9. Datenmodell
PostgreSQL Schema (Server-Side)
-- Welten
CREATE TABLE worlds (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
creator_id UUID NOT NULL REFERENCES users(id),
name TEXT NOT NULL,
description TEXT,
settings JSONB DEFAULT '{}',
is_published BOOLEAN DEFAULT false,
max_players INTEGER DEFAULT 20,
created_at TIMESTAMPTZ DEFAULT now(),
updated_at TIMESTAMPTZ DEFAULT now()
);
-- Chunks (komprimierte Voxel-Daten)
CREATE TABLE chunks (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
world_id UUID NOT NULL REFERENCES worlds(id) ON DELETE CASCADE,
position_x INTEGER NOT NULL,
position_y INTEGER NOT NULL,
position_z INTEGER NOT NULL,
voxel_data BYTEA NOT NULL, -- RLE + LZ4 komprimiert
palette JSONB DEFAULT '[]',
version INTEGER DEFAULT 1,
updated_at TIMESTAMPTZ DEFAULT now(),
UNIQUE(world_id, position_x, position_y, position_z)
);
CREATE INDEX idx_chunks_world ON chunks(world_id);
-- Items (Voxel-Kreationen)
CREATE TABLE items (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
creator_id UUID NOT NULL REFERENCES users(id),
name TEXT NOT NULL,
description TEXT,
voxel_data BYTEA NOT NULL, -- Komprimiertes Voxel-Grid
dimensions SMALLINT[3] NOT NULL, -- z.B. {16, 32, 4}
resolution REAL DEFAULT 0.0625,
properties JSONB DEFAULT '{}',
behavior JSONB DEFAULT '[]', -- Trigger-Action-Regeln
wasm_binary BYTEA, -- Kompiliertes Script
rarity TEXT DEFAULT 'common',
is_published BOOLEAN DEFAULT false,
thumbnail_url TEXT, -- Gerendertes Preview-Bild
created_at TIMESTAMPTZ DEFAULT now(),
updated_at TIMESTAMPTZ DEFAULT now()
);
-- Inventar
CREATE TABLE inventories (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
player_id UUID NOT NULL REFERENCES users(id),
item_id UUID NOT NULL REFERENCES items(id),
world_id UUID REFERENCES worlds(id), -- NULL = globales Inventar
slot INTEGER,
quantity INTEGER DEFAULT 1,
instance_data JSONB DEFAULT '{}', -- Haltbarkeit etc. pro Instanz
UNIQUE(player_id, item_id, world_id, slot)
);
-- Materialien (globaler Katalog)
CREATE TABLE materials (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
color TEXT NOT NULL, -- Hex
type TEXT DEFAULT 'solid', -- solid, transparent, liquid, emissive
texture_url TEXT,
properties JSONB DEFAULT '{}'
);
Dexie.js Schema (Client-Side, Local-First)
const db = new Dexie('voxel-platform');
db.version(1).stores({
worlds: 'id, creatorId, name, isPublished, updatedAt',
chunks: 'id, worldId, [worldId+posX+posY+posZ], updatedAt',
items: 'id, creatorId, name, rarity, isPublished, updatedAt',
inventories: 'id, playerId, itemId, worldId',
materials: 'id, name, type',
});
10. Build-Plan
Phase 0: Voxel Engine Proof of Concept (6-8 Wochen)
Woche 1-2: Bevy + wgpu im Browser
□ Bevy-Projekt aufsetzen, WASM-Build, WebGPU-Rendering im Browser
□ Einfache Kamera-Steuerung (Orbit + WASD)
Woche 3-4: Chunk-System + Greedy Meshing
□ Chunk-Datenstruktur (32³, u16-Voxel)
□ Greedy Meshing Algorithmus implementieren
□ 5 Basis-Materialien (Stein, Holz, Gras, Wasser, Sand)
□ Flat-World-Generator (eine Ebene Gras)
Woche 5-6: Voxel-Editing
□ Raycast: Mausklick → welcher Voxel?
□ Platzieren (Linksklick) + Loeschen (Rechtsklick)
□ Material-Palette UI (Svelte Overlay)
□ Undo/Redo Stack
Woche 7-8: Basis-Physik + Spieler
□ Spieler-Capsule mit Gravitation
□ AABB-Kollision mit Voxel-Welt
□ Springen, Laufen
□ First-Person + Third-Person Kamera
Ergebnis: Minecraft Creative Mode im Browser, 60fps, Offline-faehig
Phase 1: Item-System (6-8 Wochen)
Woche 9-10: Item Voxel-Editor
□ Separater Editor-Modus (0.0625m Grid)
□ 32x32x32 Voxel-Grid fuer Items
□ Rotieren, Spiegeln, Schicht-Editing
□ Item speichern (Dexie.js)
Woche 11-12: Property System
□ Component-basierte Properties (ECS)
□ Property-Slider-UI (Svelte)
□ 10 Standard-Properties (Damage, Element, Durability, ...)
□ Item im Inventar anzeigen
Woche 13-14: Trigger-Action System
□ Trigger-Action Editor UI (Svelte)
□ 10 Trigger-Typen + 15 Action-Typen
□ Trigger-Action → WASM Kompilierung
□ WASM-Sandbox (Wasmtime) Integration
Woche 15-16: Items in der Welt
□ Item in der Hand halten (Third Person)
□ Item benutzen (Primary/Secondary Action)
□ Items auf den Boden legen / aufheben
□ Partikel + Sound-Effekte
Ergebnis: Spieler baut Schwert im Editor, gibt ihm Feuer-Schaden,
benutzt es in der Welt → Partikel fliegen
Phase 2: Multiplayer (4-6 Wochen)
Woche 17-18: Go Game Server
□ Bevy headless Server (Rust Binary)
□ Go-Orchestrator spawnt Server-Prozesse
□ WebTransport (Quinn) Verbindung Browser ↔ Server
Woche 19-20: Voxel-Sync
□ Chunk-Sync bei Verbindung (komprimiert)
□ Delta-Sync bei Voxel-Aenderungen
□ Server-autoritatives Voxel-Editing
□ Andere Spieler sehen + sich bewegen sehen
Woche 21-22: Multiplayer Items + Polish
□ Inventar-Sync
□ Item-Interaktionen zwischen Spielern
□ Chat (Text, einfach)
□ Welt-Link teilen (mana.how/world/abc123)
Ergebnis: 2-20 Spieler in einer geteilten Voxel-Welt,
bauen zusammen, benutzen selbst-programmierte Items
Phase 3: Platform (4-6 Wochen)
Woche 23-24: Auth + Persistence
□ mana-auth Integration (Login/Register/Guest)
□ Welten in PostgreSQL speichern
□ Local-First Sync (Dexie.js ↔ mana-sync ↔ PostgreSQL)
□ Welt-Liste (eigene + oeffentliche)
Woche 25-26: Discovery + Social
□ Welt veroeffentlichen
□ Welt-Suche (Meilisearch)
□ Spieler-Profil (erstellte Welten, Items)
□ Favoriten
Woche 27-28: Polish + Performance
□ LOD fuer entfernte Chunks
□ Performance-Tiers (Desktop/Mobile)
□ Onboarding Tutorial
□ Bug Fixes, Edge Cases
Ergebnis: MVP! Browser-basierte Voxel-Plattform mit Login,
Welt-Erstellung, Item-Programmierung, Multiplayer.
Gesamtzeit: ~28 Wochen (7 Monate)
Monat 1-2: Voxel Engine im Browser (Bauen + Physik)
Monat 3-4: Item-Editor + Programmierung
Monat 5-6: Multiplayer + Sync
Monat 7: Platform-Features + Polish
Zusammenfassung: Was macht dieses MVP besonders?
1. ALLES IM SPIEL — Kein externer Editor, kein Download, kein SDK
2. PROGRAMMIERBARE — Items sind nicht nur Deko, sie haben Verhalten
ITEMS (Slider → Trigger-Actions → TypeScript → WASM)
3. ZWEI RESOLUTIONEN — Welt: 0.25m (Minecraft+), Items: 0.0625m (MagicaVoxel)
4. BROWSER-FIRST — Ein Link, sofort spielen, kein Install
5. OFFLINE-FAEHIG — Editor funktioniert ohne Internet (Local-First)
6. ADAPTIVE QUALITAET — Desktop: 256m Sichtweite, Mobile: 64m, Auto-Anpassung
7. NAHTLOSER LERNPFAD — Kind startet mit Slidern, lernt Trigger-Actions,
entdeckt irgendwann TypeScript
Der Kern-Differentiator gegenueber Minecraft: Items haben Verhalten. Der Kern-Differentiator gegenueber Roblox: Alles entsteht in-game, aus Voxeln, ohne externen Editor.
Erstellt: 28. Maerz 2026