# SHRIKE top-down 3D space survival roguelike. ```{raw} html ▶ Run in browser ``` **Tags:** `3d` `game` `roguelike` `survival` `procedural` # SHRIKE A top-down 3D space survival roguelike on the SimVX engine. Strip-mine dying sectors under a signature meter that your own greed fills, juggle fuel, oxygen, ammo and a starving capacitor, bank your haul or smelt it aboard a Refinery that lights you up like a flare, and flee the Shrike when the klaxon sounds; behind you a red front swallows the star chart, and ahead lie richer sectors, louder deaths, and eventually the night your build is strong enough to turn around and hunt it back to its roost. Every tuning number that shapes the game is in `shrike/balance.py`. ## Run ```bash uv run python examples/demos/shrike/main.py # play uv run python examples/demos/shrike/main.py --test # headless self-check, exits on its own ``` `--test` mounts the entry scene, flies a fixed-seed slice of a whole run (mine a deposit, provoke the signature lock, survive a wave and an arrival, flee through the star chart, extract at the Deep Gate) and prints `SELFTEST: PASS` before exiting. It writes its saves to a throwaway directory, so it never touches a real profile. ## Controls The nose aims independently of the thrust vector: you fly one way and shoot another. On a pad the shield arc mirrors the right stick by default; on a keyboard Q and E rotate it continuously. | Action | Keyboard and mouse | Gamepad | |---|---|---| | Thrust | W A S D | Left stick | | Aim | Mouse | Right stick | | Fire primary | Left mouse | Right trigger | | Mining beam | Right mouse | Left trigger | | Rotate shield arc | Q / E | Left / right bumper (60 degree nudge; both re-centres on aim) | | Afterburner | Shift (hold) | A (hold) | | Interact | F | X | | Jettison scrap | G | B | | Silent running | C (toggle) | Y (toggle) | | Solar wings | X | D-pad up | | Generator | Z | D-pad down | | Warp spool | R (toggle) | Left stick click (toggle) | | Tractor scoop | Tab (toggle) | Right stick click (toggle) | | Star chart | M | Back | | Show or hide the controls bar | H | D-pad left | | Pause menu | Esc | Start | Warp spool is a toggle rather than a hold: press once to start the channel, press again to cancel it. Loose salvage is scooped by flying through it, so a mote you touch is a mote you keep. Interact is one button with three lengths, and the ship draws the hold as a radial fill: | Hold | Effect | |---|---| | Tap | Dock at a depot, grab salvage, trigger a signal event | | 1 second | Patch the nearest hull breach (costs scrap) | | 3 seconds | Start a Refinery batch, or sell your scrap while docked | ## Saves Two files, both under the XDG data directory: | Path | Contents | |---|---| | `$XDG_DATA_HOME/simvx/shrike/profile.sav` | Cores, Fleet Doctrine, quills, fletchings, lure fragments, hulls, Hunt Rank, codex, milestones, per-hull bests | | `$XDG_DATA_HOME/simvx/shrike/suspend.sav` | The single suspend slot, deleted as it is loaded | `XDG_DATA_HOME` falls back to `~/.local/share` when unset or not absolute, so the usual location is `~/.local/share/simvx/shrike/`. Setting `SHRIKE_DATA_DIR` overrides both, which is what the self-check and portable installs use. Nothing is ever written into the game directory. ## Tests ```bash uv run --package simvx-core pytest examples/demos/shrike/tests/test_foundation.py ``` Each module has its own test file under `examples/demos/shrike/tests/`; run one file at a time. They are headless logic tests: scenes run under `SceneRunner` and every player verb goes through `InputSimulator`, so the real action map and input pipeline are exercised rather than handlers called directly. No GPU, no windows. `tests/test_balance_bands.py` is the tuning contract: it measures the design's time-to-kill bands (mite under 0.5 s, lancer about 2 s, warden about 45 s, one Shrike fin about 15 s) by feeding each reference loadout's DPS through the real damage router. A balance change that moves a band fails there first. ## Source files | File | Summary | Lines | | --- | --- | --- | | [`main.py`](#source) | SHRIKE: top-down 3D space survival roguelike. | 441 | | [`shrike/__init__.py`](demos_shrike--shrike-__init__-py.md) | SHRIKE: a top-down 3D space survival roguelike on the SimVX engine. | 20 | | [`shrike/artkit.py`](demos_shrike--shrike-artkit-py.md) | Procedural art kit for SHRIKE: every mesh, material, sky and grade is generated. | 2168 | | [`shrike/audio.py`](demos_shrike--shrike-audio-py.md) | SHRIKE's audio: every sound synthesised at load, and the mix the power state drives. | 893 | | [`shrike/balance.py`](demos_shrike--shrike-balance-py.md) | Every tuning number in SHRIKE, as named constants and small specs. | 780 | | [`shrike/bounty.py`](demos_shrike--shrike-bounty-py.md) | Notoriety, the run-level reputation dial, and the two set pieces it buys. | 1018 | | [`shrike/chart.py`](demos_shrike--shrike-chart-py.md) | The star chart: a branching route eaten from behind, and the warp that pays for it. | 1664 | | [`shrike/combat.py`](demos_shrike--shrike-combat-py.md) | The damage router and the collision-layer contract. | 452 | | [`shrike/enemies/__init__.py`](demos_shrike--shrike-enemies-__init__-py.md) | SHRIKE's hostiles: shared steering, the enemy base, and the archetypes. | 53 | | [`shrike/enemies/advanced.py`](demos_shrike--shrike-enemies-advanced-py.md) | The advanced half of the enemy roster: support, siege, alarm, emplacement and herald. | 1474 | | [`shrike/enemies/basic.py`](demos_shrike--shrike-enemies-basic-py.md) | The four common hostiles: Mites, Skimmers, Lancers and Mag-mines. | 781 | | [`shrike/enemies/steering.py`](demos_shrike--shrike-enemies-steering-py.md) | Flow-field steering and the shared enemy base. | 815 | | [`shrike/events.py`](demos_shrike--shrike-events-py.md) | The signal-event deck: twelve cards a sector can deal you on arrival. | 185 | | [`shrike/flow.py`](demos_shrike--shrike-flow-py.md) | The run lifecycle: the menu, the run, the Gate, the collapse and the ledger. | 7469 | | [`shrike/hud.py`](demos_shrike--shrike-hud-py.md) | SHRIKE's heads-up display: foveal arcs, a warming border and diegetic rings. | 4500 | | [`shrike/hunter.py`](demos_shrike--shrike-hunter-py.md) | The Shrike: the segmented hunter the whole economy is priced against. | 977 | | [`shrike/juice.py`](demos_shrike--shrike-juice-py.md) | The feel layer: hit-stop, trauma-budgeted shake, punches and the scoop magnet. | 690 | | [`shrike/meta.py`](demos_shrike--shrike-meta-py.md) | Fleet Doctrine, the milestone bounties, the hull trophies and the Hunt Ranks. | 1500 | | [`shrike/modules.py`](demos_shrike--shrike-modules-py.md) | Hull sockets, the thirty-module catalogue, and the modules that act. | 1292 | | [`shrike/onboarding.py`](demos_shrike--shrike-onboarding-py.md) | The staged first three runs: the HUD subtraction schedule and the safe arrival. | 934 | | [`shrike/power.py`](demos_shrike--shrike-power-py.md) | Power generation, life support, and the silent-running posture. | 1064 | | [`shrike/roost.py`](demos_shrike--shrike-roost-py.md) | The endgame campaign: Lure fragments, Fletching pity, and the Roost duel. | 653 | | [`shrike/runtime.py`](demos_shrike--shrike-runtime-py.md) | The shared runtime spine of SHRIKE. | 541 | | [`shrike/save.py`](demos_shrike--shrike-save-py.md) | Persistence: the permanent meta profile and the one-slot suspend save. | 528 | | [`shrike/sector.py`](demos_shrike--shrike-sector-py.md) | What a warp-in drops you into: one sector's harvestable content. | 1736 | | [`shrike/ship.py`](demos_shrike--shrike-ship-py.md) | The player ship: drift flight, the shield arc, hull breaches and the warp spool. | 1104 | | [`shrike/signature.py`](demos_shrike--shrike-signature-py.md) | The signature meter: the bill this sector charges for everything you do. | 203 | | [`shrike/trading.py`](demos_shrike--shrike-trading-py.md) | The scrap ledger, the drift depots, and the Broker barge. | 1121 | | [`shrike/vfx.py`](demos_shrike--shrike-vfx-py.md) | SHRIKE's effects library: pooled bursts, the two live emitters and the dust. | 1509 | | [`shrike/waves.py`](demos_shrike--shrike-waves-py.md) | The wave composer: what arrives every 35 to 55 seconds, and from where. | 1105 | | [`shrike/weapons.py`](demos_shrike--shrike-weapons-py.md) | Hardpoints, the ten-weapon roster, and everything they put in the air. | 1315 | ```{toctree} :hidden: demos_shrike--shrike-__init__-py demos_shrike--shrike-artkit-py demos_shrike--shrike-audio-py demos_shrike--shrike-balance-py demos_shrike--shrike-bounty-py demos_shrike--shrike-chart-py demos_shrike--shrike-combat-py demos_shrike--shrike-enemies-__init__-py demos_shrike--shrike-enemies-advanced-py demos_shrike--shrike-enemies-basic-py demos_shrike--shrike-enemies-steering-py demos_shrike--shrike-events-py demos_shrike--shrike-flow-py demos_shrike--shrike-hud-py demos_shrike--shrike-hunter-py demos_shrike--shrike-juice-py demos_shrike--shrike-meta-py demos_shrike--shrike-modules-py demos_shrike--shrike-onboarding-py demos_shrike--shrike-power-py demos_shrike--shrike-roost-py demos_shrike--shrike-runtime-py demos_shrike--shrike-save-py demos_shrike--shrike-sector-py demos_shrike--shrike-ship-py demos_shrike--shrike-signature-py demos_shrike--shrike-trading-py demos_shrike--shrike-vfx-py demos_shrike--shrike-waves-py demos_shrike--shrike-weapons-py ``` ## Source ```{literalinclude} ../../examples/demos/shrike/main.py :language: python :linenos: ```