No project description provided
Project description
Crimsonland 1.9.93 — reverse engineering + rewrite
A high-fidelity reimplementation of Crimsonland v1.9.93 (2003, GOG "Crimsonland Classic") in Python + raylib, paired with deep reverse engineering of the original Windows binary.
The aim of the project is behavioral parity: timings, RNG sequences, float32 math, UI layout quirks, asset decoding, and gameplay rules should match the original as closely as practical.
We go great lengths to achieve this goal, including a headless differential testing harness to verify runs recorded in the original game versus our reimplementation.
Read the full story — reverse engineering workflow, custom asset formats, AI-assisted decompilation, and game preservation philosophy.
Browse the docs — 100+ pages of analysis, struct layouts, format specs, and parity tracking.
Current state
The rewrite is a playable full game: boot, menus, Survival, Rush, Quests (5 tiers), Tutorial, and Typ-o-Shooter, with full weapon/creature/perk content, terrain/sprite/decal rendering, music, gameplay SFX, and even secrets. The simulation is fully deterministic, supporting seeded runs and headless verifiable replays.
Quick start
Install uv, then:
uvx crimsonland@latest
# or run from source
gh repo clone banteg/crimson && cd crimson
uv run crimson
Wayland on Linux: current PyPI raylib wheels are X11-oriented on x86_64, so you may need xwayland + libX11. See electronstudio/raylib-python-cffi#199.
Runtime files
By default, saves, config, logs, and replays live in your per-user data directory. To keep everything local to the checkout:
export CRIMSON_RUNTIME_DIR="$PWD/artifacts/runtime"
uv run crimson
Assets
The rewrite can load the assets from original PAQ archives (crimson.paq et al). No original assets or binaries are included in this repository.
Point to them explicitly if needed:
uv run crimson --assets-dir path/to/game_dir
Extract PAQs into a filesystem tree for inspection. JAZ textures are automatically converted to PNG with alpha:
uv run crimson extract path/to/game_dir artifacts/assets
CLI
Everything is exposed via the crimson CLI (alias: crimsonland):
crimson run the game (default)
crimson view <name> debug views / sandboxes
crimson quests <level> print quest spawn script
crimson config inspect crimson.cfg
crimson extract <src> <dst> extract PAQ archives
crimson replay play <file> play back a recorded demo
crimson replay verify <file> headlessly verify score from a replay
crimson oracle [--seed N] headless simulation for differential testing
Useful flags: --seed N (deterministic runs), --demo (shareware teaser), --no-intro (skip logos), --base-dir PATH / CRIMSON_RUNTIME_DIR (runtime file location), --assets-dir PATH (PAQ / extracted asset location).
Project layout
src/
crimson/ game logic — modes, weapons, perks, creatures, UI, replay
grim/ engine layer — raylib wrapper, PAQ/JAZ decoders, audio, fonts
analysis/
ghidra/ name/type maps (source of truth) and raw decompile exports
frida/ runtime capture evidence (state snapshots, RNG traces)
windbg/ debugger session logs
docs/ 100+ pages: formats, structs, algorithms, parity tracking
scripts/ 40+ analysis and utility tools
tests/ 200+ tests: gameplay, perks, physics, replay, parity
Reverse engineering
Static analysis is the source of truth. Names and types live in analysis/ghidra/maps/; raw decompiles in analysis/ghidra/raw/ are regenerated output.
Runtime tooling (Frida, WinDbg) validates ambiguous behavior and captures ground truth. Evidence summaries live under analysis/frida/.
Differential testing captures original execution via Frida, replays the same inputs through the rewrite's headless oracle, and compares state checkpoints field-by-field.
See docs/provenance.md for exact binary hashes of the target build.
Development
uv run pytest # test suite
uv run ruff check . # lint
uv run ty check src # type check
just check # all of the above
Docs
Docs are authored in docs/ and built as a static site with zensical:
uv tool install zensical
zensical serve
Parity workflow
- Recover structure and intent from static analysis (
analysis/ghidra/maps/as source-of-truth maps). - Validate ambiguous behavior with runtime evidence (Frida/WinDbg captures under
analysis/frida/). - Port behavior into
src/with deterministic simulation contracts. - Verify against captures/replays with headless differential tools.
For deterministic gameplay code, float behavior is part of the contract.
See docs/rewrite/float-parity-policy.md.
Contributing
- Keep changes small and reviewable — one subsystem at a time.
- Prefer measured parity (captures, logs, deterministic tests) over "looks right".
- Preserve native float32 math behavior in deterministic simulation paths. See float parity policy.
- Run
just checkbefore committing.
Tech stack
Python 3.13+ · raylib (pyray) · Construct · msgspec · Typer · Ghidra · Frida · WinDbg · pytest · uv
Legal
This project is an independent reverse engineering and reimplementation effort for preservation, research, and compatibility. No original assets or binaries are included. Use your own legally obtained copy.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file crimsonland-0.1.0.dev25.tar.gz.
File metadata
- Download URL: crimsonland-0.1.0.dev25.tar.gz
- Upload date:
- Size: 471.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
50c8a28f7bd17f84a44fae45f30868d34e67f56a0d0fa30d1f32463f76199445
|
|
| MD5 |
c8f7272f8e3ef2636cf47ff21a5d166e
|
|
| BLAKE2b-256 |
4ef9772e8dbfdc7994661217f476549c41510594444bceb0d2bd84d8dac9b6c4
|
Provenance
The following attestation bundles were made for crimsonland-0.1.0.dev25.tar.gz:
Publisher:
release.yml on banteg/crimson
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
crimsonland-0.1.0.dev25.tar.gz -
Subject digest:
50c8a28f7bd17f84a44fae45f30868d34e67f56a0d0fa30d1f32463f76199445 - Sigstore transparency entry: 938143570
- Sigstore integration time:
-
Permalink:
banteg/crimson@293654ea965a103d1f7f5cbc45b713dfe31779e7 -
Branch / Tag:
refs/tags/v0.1.0.dev25 - Owner: https://github.com/banteg
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@293654ea965a103d1f7f5cbc45b713dfe31779e7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file crimsonland-0.1.0.dev25-py3-none-any.whl.
File metadata
- Download URL: crimsonland-0.1.0.dev25-py3-none-any.whl
- Upload date:
- Size: 583.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
51bff41491a6a55178fab0d7b82a5f9766e34625704efed24ad35164eb642f14
|
|
| MD5 |
afd17c8203d9a49966c1c4d13cf1617e
|
|
| BLAKE2b-256 |
8a19e9896f943ed2dab2648a22b87482313617fec50a01dce1686f5d16ac2ef1
|
Provenance
The following attestation bundles were made for crimsonland-0.1.0.dev25-py3-none-any.whl:
Publisher:
release.yml on banteg/crimson
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
crimsonland-0.1.0.dev25-py3-none-any.whl -
Subject digest:
51bff41491a6a55178fab0d7b82a5f9766e34625704efed24ad35164eb642f14 - Sigstore transparency entry: 938143574
- Sigstore integration time:
-
Permalink:
banteg/crimson@293654ea965a103d1f7f5cbc45b713dfe31779e7 -
Branch / Tag:
refs/tags/v0.1.0.dev25 - Owner: https://github.com/banteg
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@293654ea965a103d1f7f5cbc45b713dfe31779e7 -
Trigger Event:
push
-
Statement type: