11 KiB
11 KiB
Verbatim — Development Plan
ASCII physics RPG. Noita's cellular automaton + Caves of Qud's RPG depth. Every symbol is a material with physics. Every entity is a body with mass.
Current State (June 2026)
What Works
| System | Status | Details |
|---|---|---|
| Cellular automaton | Working | 14 materials: sand, water, stone, lava, wood, flesh, bone, steam, fire, acid, smoke, grass, dirt, empty |
| Rigid entities | Working | AABB collider, sliding on surfaces, 27 sub-bodies (5x5 + arm), player + goblins |
| Ragdoll corpses | Working | Verlet constraints, death = rigid→ragdoll transition with inherited velocity |
| Terminal renderer | Working | Full terminal size, ANSI truecolor, diff-based rendering |
| AI pipe protocol | Working | JSON stdin/stdout, 16 commands, full state export |
| Test framework | Working | 28 Rust tests + 8 JSON scenarios, all passing |
| Replay system | Working | Seeded determinism, record/playback, play_until_tick |
| World generation | Basic | Sinusoidal terrain, water/lava/acid pools, wood structure, sand dune, stone wall |
Architecture
Source of truth: text grid (250x250, char + material + temp)
Three entity types:
1. Cellular — materials in grid, per-cell CA rules
2. Rigid — alive entities, AABB collider, single velocity
3. Ragdoll — corpses, loose Verlet bodies, independent physics
Game loop: fixed 60Hz timestep
Physics tick: CA step → rigid update → ragdoll update → damage
Render: terminal (ANSI) or pipe (JSON) or headless (file dump)
Numbers
- ~4600 lines Rust
- 28 integration tests, 8 JSON scenarios
- 11 git commits
- 0 compiler warnings
Roadmap
Phase 1: Combat & Interaction (next)
Goal: entities can fight and affect each other
- Melee combat: rigid entity AABB overlap → damage exchange
- Health bars in terminal render (colored indicator above entity)
- Death → ragdoll → corpse decomposition (flesh cells drop into grid over time)
- Projectile system: thrown objects (arrows, fireballs) as lightweight rigid bodies
- Material interaction with entities: entity walks through fire → ignites, acid → dissolves
- Knockback: damage applies velocity impulse to rigid body center
- Goblin AI: move toward player, attack when adjacent, flee when low HP
Tests needed:
- Melee damage between two entities
- Knockback direction correctness
- Corpse decomposition produces flesh cells in grid
- Projectile travels and deals damage on hit
- Goblin AI moves toward player
Phase 2: World & Exploration
Goal: explorable world with depth and variety
- Chunk system: world divided into chunks (64x64), only active chunks simulated
- Chunk persistence: save/load chunks to disk
- Vertical descent: stairs/holes between depth levels
- Biomes: grassland, cave, lava cavern, ice, fungus forest — each with material palette
- Procedural dungeon generation: rooms, corridors, traps
- Camera zoom: +/- keys to change viewport scale (more or fewer cells visible)
- Minimap: ASCII overview of explored area
- Day/night cycle: ambient light affects rendering (dimmer at night)
Tests needed:
- Chunk save/load roundtrip preserves state
- Entity crossing chunk boundary continues correctly
- Dungeon generation produces connected rooms
- Biome materials match expected palette
Phase 3: RPG Layer
Goal: character progression, inventory, abilities
- Stats: strength, agility, toughness, willpower — affect damage, speed, HP, etc.
- Inventory system: items as data structs, pick up by walking over, drop with key
- Equipment: weapon affects melee damage/range, armor affects damage reduction
- Items in world: weapons, potions, scrolls, food — rendered as distinct ASCII chars
- Mutations (Caves of Qud style): modify entity properties
- "Silicon skin" → entity material becomes Stone, immune to acid
- "Flame body" → entity emits fire cells, immune to fire
- "Liquid form" → entity can squeeze through 1-cell gaps
- "Multiple arms" → extra attack, can hold more items
- XP and leveling: kill entities → gain XP → level up → choose mutation
- Skills: active abilities on cooldown (dash, stomp, material blast)
- Status effects: burning, poisoned, frozen, bleeding — each with tick effect
- Dialogue: talk to NPCs, simple text tree
Tests needed:
- Stat modifiers affect combat correctly
- Item pickup/drop maintains inventory integrity
- Mutation changes entity material/properties
- XP accumulation triggers level up
- Status effect ticks deal correct damage
Phase 4: Vulkan Renderer
Goal: 60+ FPS windowed rendering with GPU
- ash (Vulkan) bootstrap: instance, device, swapchain, render pass
- Glyph atlas: DejaVu Sans Mono rasterized at startup via fontdue
- Instanced rendering: one draw call for all visible cells
- Persistent mapped buffer for instance data
- Dirty cell tracking: only update changed cells in instance buffer
- Camera: smooth follow, zoom levels
- Post-processing: subtle bloom for lava/fire, vignette
--mode auto: try Vulkan, fallback to terminal- Single binary: font embedded via include_bytes!
Tests needed:
- Vulkan init doesn't crash on supported hardware
- Render output matches terminal render for same state
- Frame time < 16ms with full viewport
Phase 5: Content & Polish
Goal: playable vertical slice
- Factions: goblins, skeletons, slimes, trolls — each with AI behavior
- Boss entity: large rigid body (10x10), multiple attack patterns
- Books/readable items: lore text displayed in terminal
- Crafting: combine materials to create new ones (water + dirt = mud)
- Sound: procedural audio via terminal bell or optional ALSA
- Save/load: full game state to file (grid + entities + player + inventory)
- Death screen: stats summary, cause of death
- Tutorial: first-time controls overlay
- Difficulty scaling: deeper levels = stronger enemies
Phase 6: Advanced Physics
Goal: deeper Noita-style material simulation
- Pressure: liquids have pressure, flow through pipes and U-bends
- Temperature gradient: heat radiates, materials melt/freeze at thresholds
- Electricity: conductive materials carry current, shocks entities
- Explosions: rapid gas expansion, creates fire + destroys terrain
- Structural integrity: stone/wood can collapse under load
- GPU compute: cellular automaton on Vulkan compute shader for large worlds
- Fluid simulation: proper Navier-Stokes for water instead of CA approximation
Tests needed:
- Pressure equalizes in connected containers
- Heat propagates through conductive materials
- Electricity follows conductive path
- Explosion destroys terrain in radius
- Collapse triggers when support removed
Architecture Decisions
Locked
| Decision | Rationale |
|---|---|
| Text grid as source of truth | AI-observable, dual renderer, single state |
| Rust + crossterm + ash | Zero-cost, memory safety, explicit GPU control |
| Fixed 60Hz timestep | Deterministic replay, consistent physics |
| AABB for rigid, Verlet for ragdoll | Simple, no tunneling for rigid; expressive for ragdoll |
| Seeded RNG for determinism | Replay system, reproducible tests |
| JSON pipe protocol | Any AI agent can connect, no vision needed |
| Single binary with embedded font | Portable, no external assets |
Open Questions
| Question | Options | When to decide |
|---|---|---|
| Turn-based vs real-time | Currently real-time 60Hz. Qud is turn-based. Hybrid? | Phase 3 |
| World topology | Single deep shaft vs branching dungeon vs open world | Phase 2 |
| Save format | Binary (compact) vs JSON (debuggable) vs RON | Phase 5 |
| Multiplayer | No. But pipe protocol could enable AI vs AI | Never (single-player) |
| Modding | Data-driven materials from JSON/TOML? | Phase 3 |
File Structure (current + planned)
src/
main.rs # CLI entry point
lib.rs # Library root
game.rs # Game loop, world gen, entity management
input.rs # Keyboard input → Action enum
world/
cell.rs # Cell struct, MaterialId enum
material.rs # Material properties registry
grid.rs # Grid (250x250), cell access
cellular.rs # Cellular automaton rules
chunk.rs # [Phase 2] chunk system
worldgen.rs # [Phase 2] procedural generation
physics/
verlet.rs # Verlet integrator, constraints
collision.rs # AABB-vs-grid collision (used by ragdoll)
projectile.rs # [Phase 1] lightweight projectiles
entity/
entity.rs # Entity struct, rigid/ragdoll, build_humanoid
player.rs # Player controller
ai.rs # [Phase 1] goblin AI
inventory.rs # [Phase 3] items and equipment
stats.rs # [Phase 3] character stats
mutations.rs # [Phase 3] mutation system
render/
mod.rs # Renderer trait
terminal.rs # Terminal renderer (ANSI)
vulkan.rs # [Phase 4] Vulkan renderer
ai/
session.rs # GameSession wrapper for AI/testing
state.rs # JSON state export
action.rs # AiAction enum
protocol.rs # JSON pipe protocol
replay.rs # Record/playback
scenario.rs # JSON test scenarios
tests/ # 28 integration tests
scenarios/ # 8 JSON scenarios
assets/
DejaVuSansMono.ttf # Embedded font for Vulkan renderer
Performance Targets
| Metric | Target | Current |
|---|---|---|
| CA step (250x250) | < 1ms | ~0.5ms |
| Rigid entity update | < 0.5ms per entity | ~0.2ms |
| Terminal render frame | < 5ms | ~2ms (diff-based) |
| Vulkan render frame | < 16ms (60 FPS) | N/A |
| Pipe protocol latency | < 1ms per command | ~0.1ms |
| Binary size (release) | < 10MB | ~6MB (debug, no Vulkan) |
Testing Strategy
| Layer | Method | Count |
|---|---|---|
| Material physics | Rust integration tests | 15 |
| Entity physics | Rust integration tests | 8 |
| AI/replay | Rust integration tests | 4 |
| JSON scenarios | Declarative test files | 8 |
| Manual playtest | Terminal mode | As needed |
| AI playtest | Pipe protocol + agent | Future |
Priority: every new feature gets tests before merge.
Release Milestones
| Milestone | Content | Target |
|---|---|---|
| 0.1 (done) | Core engine: CA, rigid, ragdoll, terminal, AI pipe | June 2026 |
| 0.2 | Combat, goblin AI, projectiles, corpse decomposition | July 2026 |
| 0.3 | Chunks, biomes, dungeon gen, camera zoom | August 2026 |
| 0.4 | RPG layer: stats, inventory, mutations, XP | October 2026 |
| 0.5 | Vulkan renderer, save/load, polish | December 2026 |
| 1.0 | Full vertical slice: content, balance, death screen | Q1 2027 |