A self-contained space-combat tech demo: cockpit flight, lead-computing laser cannons, pursuing enemy fighters, a procedural starfield with a lens-flare sun, a textured planet backdrop, a drifting asteroid field, and a full combat HUD — all built on the engine’s deferred render-graph preset. No external model or texture assets; every ship, rock, and planet is generated at startup.
| Input | Mouse + Keyboard | Gamepad | Touch |
|---|---|---|---|
| Steer (pitch/yaw) | Mouse | Left stick | Left joystick |
| Roll | A / D |
LB / RB | ⟲ / ⟳ buttons |
| Throttle | W / S |
D-pad ↑ / ↓ | THR+ / THR- |
| Afterburner | Shift |
LT | BURN |
| Fire | LMB / Space |
RT | FIRE |
| Engage | click canvas (pointer lock) | any input | any touch |
Touch and gamepad are self-installing — a desktop session never sees the touch
overlay, and the gamepad wakes on first input. All three input methods drive the
same PlayerFlight simultaneously (see flight_model.ts + controls.ts).
Press G for the render-graph visualization overlay.
Built on the high-level Engine + deferredPreset API; features are
added/removed and the engine rebuilds the graph each frame. The tail is
re-ordered so every bright element blooms:
…sky → deferred lighting → TAA → stars → lens-flare → explosions → bloom → tonemap
Stars, the sun flare, and explosion sparks are all added before bloom; ship
engine glow and laser bolts emit via emissiveFactor (see Emissive glow
below), so all of them streak through the bloom pass.
StarsFeature (new engine feature)src/renderer/features/stars_feature.ts wraps the existing StarsPass: a
full-screen pass that adds procedural stars on sky pixels (depth == 1). The
feature defaults to a downward sun vector (perpetual night) and full-sphere
coverage so stars are always visible in any direction — the right behavior for
space. Reads frame.hdr + frame.depth, writes frame.hdr.
LensFlareFeature (new engine feature + pass)A screen-space lens flare is the sun. LensFlareFeature
(src/renderer/features/lens_flare_feature.ts) projects the sun direction to
screen space each frame using the render camera, zeroes the flare when the sun
is behind the camera, and hands the pass a screen UV + intensity + color. The
pass (lens_flare_pass.ts + lens_flare.wgsl) draws:
and occludes the whole flare by sampling a 3×3 neighborhood of scene depth at the sun’s pixel — so a ship, asteroid, or the planet eclipsing the sun makes the flare vanish, and it fades smoothly as the sun leaves frame. Because it reads the same depth the rest of the scene wrote, no separate occlusion query is needed.
The deferred geometry shader computes emission as
albedo*mer.g + emissiveMap.rgb * emissiveFactor, and the default emissive
map is black — so emissiveFactor alone emits nothing. emissive.ts binds a
shared 1×1 white emissive map to every emissive material (laser bolts, engine
pods, cannon accents), turning emission into 1 * emissiveFactor so they glow
and bloom.
flight_model.ts)Arcade, not Newtonian: velocity is locked to the facing direction, so the ship goes where the nose points. Mouse movement feeds a virtual stick that decays back to center; touch/gamepad feed absolute steer/roll/throttle inputs that fold into the same integration. Rotation is integrated in the ship’s local frame (pitch about local X, yaw about local Y, roll about local −Z) by post-multiplying the orientation quaternion. The player ship’s transform is the camera transform — a true cockpit view.
enemy.ts)Each enemy pursues the player, adds a per-craft sine jink so a wing doesn’t
fly in lockstep, breaks off when it gets too close, banks toward its heading
via slerp, and leads its shots with a first-order intercept (leadPoint
in math_util.ts), only firing when its nose is on that point. Speeds are tuned
slower than the player so dogfights stay readable.
lasers.ts)Pooled emissive bolts oriented along their velocity. Collision is a swept segment-vs-sphere test between the bolt’s previous and current position, so a 240 m/s bolt can’t tunnel through a fighter between frames. Bolts inherit the shooter’s velocity so shots from a moving ship fly true.
planet.ts)A distant globe textured entirely on the CPU: an equirectangular albedo built by sampling 3D Perlin fBM on the sphere direction (no date-line seam) — oceans, beaches, vegetation, rock, and polar ice by elevation/latitude — plus a separate slowly-rotating semi-transparent cloud shell. Both are locked to the camera at a fixed world offset so the planet stays an un-reachable backdrop while spinning on its own axis.
asteroids.ts)A handful of base meshes, each a low-res UV sphere whose vertices are displaced by 3D Perlin fBM and emitted flat-shaded (per-face normals) for a chunky, faceted look, are generated once and reused across instances with random scale / spin / drift. The field is world-fixed, so you fly among the rocks; they tumble, drift, and gently bounce back when they wander too far.
hud.ts)A 2D overlay canvas. The main loop projects the world into screen-space figures
(resolveScreen clamps off-screen/behind targets to the viewport edge for
direction arrows); the HUD draws the center reticle + lead pipper, target
brackets with range and a shield bar on the locked target, a top-down radar
dish, and the throttle / shield / hull gauges with the wave / kills / hostiles
readout.