Fog Demo
App: apps/fog_demo/
Demonstrates the on-screen fog of war (engine PLM-210 / Block LSV). A top-down 3D scene where the
player wanders; the game only configures the grid and calls FogOfWar.reveal
each frame, and the engine renders it — a depth-based post-process darkens the lit world by the
3-state field:
- Unknown (never seen) → near-black
- Explored (seen before, not now) → dim + desaturated (a remembered-but-dark room)
- Visible (in view now) → full colour
No render code lives in the game. Because the world position is reconstructed from the depth buffer, the mask is pixel-exact at any camera angle — the demo blends from a top-down camera to an oblique orbit to show there is no smear on tall geometry (walls, the player).
Run from root
Section titled “Run from root”% ./plume3d fog_demoWrites fog_topdown.png and fog_oblique.png.
Darkness shrinks your view
Section titled “Darkness shrinks your view”The demo’s headline is the LSV stealth loop, rendered: one warm lamp lights a pool with darkness beyond.
Each frame the game reads Illumination.illuminanceAt(player) (0..1,
the engine samples it, respecting shadows) and passes a reveal radius scaled by it — near the lamp the
on-screen visible circle is wide (~85% exposure → radius ~10), out in the dark it collapses to a tight circle
(0% → 2.5). That single number is the whole “visible space” control. It composes with the on-screen fog
render, so the bright area literally breathes with the light — the game owns the policy, the engine samples
and renders.
What it does
Section titled “What it does”- On
init, builds a floor + wall boxes + a player node + a warm point light, andFogOfWar.configure(scene, …)— a world-XZ grid over the floor. It also callsGraphics.fogSoftnessfor a soft, feathered edge. - Each frame:
FogOfWar.beginFrame(scene)greys stale Visible → Explored, thenFogOfWar.reveal(scene, playerX, playerZ, 2.5 + exposure * 8.5)re-lights an illuminance-scaled radius around the player. A trail of Explored forms behind the moving Visible circle. - The engine renders the fog automatically for the scene whose camera drives the view — the game issues no fog draw calls.
Key pattern
Section titled “Key pattern”import "engine" for Scene, FogOfWar, Graphics, Cam
var scene = Scene.new()FogOfWar.configure(scene, -20, -20, 1, 40, 40) // world-XZ gridGraphics.fogSoftness(0.75) // 0 = crisp cells, 1 = smooth fadeCam.topDown(scene, player, 30) // (or any camera; the engine derives the inverse VP)
// each frame:FogOfWar.beginFrame(scene)FogOfWar.reveal(scene, player.x, player.z, 6) // the engine darkens the world by the fieldVerify headless
Section titled “Verify headless”% ./plume3d --test apps/fog_demoVerifies the fog surface (configure → reveal → state, Explored persistence). The on-screen render is
verified by the windowed screenshots (there is no headless render harness).