20dd6bc502d23859d9914330edd984c64f8a2ee6
ci / verify (push) Successful in 46s
The packs total 3.9GB, almost all of it Helton Yan's SFX shipped as 24-bit / 96kHz studio masters -- ~2MB for a single gunshot. Two guards, because they solve different problems: - .gitignore excludes the contents. The directory and its guard files stay tracked, so a fresh clone has the .gdignore in place before anyone drops packs back in. - assetpacks/.gdignore stops Godot descending into the tree at all. This is the urgent half: tools/check.sh runs --import, which walks all of res://, so the next check would have imported several thousand PNGs and 2,100 of those WAVs, and every run after it. Verified by controlled test rather than assumed -- an unguarded PNG under res:// imports and gets a .import file beside it; with .gdignore neither happens. check.sh stays at 3.3s and .godot/imported at 1.2MB. The trade the .gdignore buys is that nothing in assetpacks/ can be referenced from a scene or script. That is the intended shape: raw source on one side, game-ready files copied into res://assets/ on the other, so adding a huge pack costs the repo and the import step nothing. docs/ASSETS.md records attribution, because gitignoring the packs also gitignores their licence files. Worth flagging: four of the six packs shipped with no licence text at all, and two of the undecided ones are demo versions, which are often more restricted than the paid packs. Only RF Catacombs has explicit terms (public domain, no resale). Those rows need a source URL before anything ships. Also removed __MACOSX and .DS_Store extraction artefacts, and left considering_dont_use_yet/ untouched as the user's own "not chosen" marker.
Transcience
Top-down twin-stick bullet-hell with a dedicated, server-authoritative backend. Godot 4.7, GDScript, no external runtime dependencies.
Play
tools/server.sh # dedicated server on :27015
tools/client.sh --join --name ada # connect a client
Or run one client and press Host and play for a listen server.
Controls — WASD move, mouse aim, LMB fire, E on the ring in the hub to enter a dungeon, hold F for three seconds to escape back to the hub.
Develop
tools/check.sh # parse-check every script ~5s
tools/test.sh # GUT suite, headless ~2s
tools/smoke.sh # server + 2 bot clients, ENet ~35s
godot --headless --path . --script tools/bench.gd
Read CLAUDE.md first — it is short, and the Godot CLI gotchas in it will otherwise cost an afternoon.
What is here
| Twin-stick bullet hell | Server-simulated bullet field, ~350 concurrent bullets at 0.24 ms/tick. |
| Authoritative multiplayer | Clients send input only. Hits, damage, death and instance transfers are server decisions. Prediction + reconciliation for the local player. |
| Enemies | Four readable behaviours (static, drift, orbit, approach, strafe) composed with bullet emitters. |
| Boss | The Warden of the Fold: stationary, four phases, each adding one idea. Defined entirely as data. |
| Lobby hub | Shared persistent instance with a portal into dungeon runs. |
| Emergency escape | Three-second channel back to the hub, cancelled by damage. |
Docs
- docs/ROADMAP.md — what is built, what is next, where each feature lives
- docs/DECISIONS.md — settled design decisions and their reasoning
- CLAUDE.md — commands, invariants, Godot CLI gotchas
- docs/WORKFLOW.md — agent-assisted Godot development, and why the setup looks like this
- docs/ARCHITECTURE.md — code map and the node-free simulation
- docs/NETCODE.md — replication model, hit validation, known gaps
- docs/ROADMAP.md — what is built and what is next
Description
Languages
GDScript
98.6%
Shell
1.1%
Python
0.3%