diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..86c6752
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,2 @@
+# Who reviews what (https://docs.github.com/articles/about-code-owners). The owner reviews and merges every pull request.
+* @gascarcella
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1e432fd..d049b82 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -6,8 +6,8 @@
# 24.04 (SDL3 and Dear ImGui at their pins through scripts/setup.sh; the built tools cached on the pins,
# scripts/setup.sh --pins, not on the script's text), and the Windows cross-build with its self-test under Wine. On pull
# requests, pushes to main and by hand; a newer push to a pull request cancels the older run. Not on changes that touch
-# only documentation (paths-ignore: Markdown and LICENSE; no step reads them, and main's ruleset requires no check, so
-# such a pull request merges without a run). A change with any other file runs everything.
+# only documentation (paths-ignore: Markdown, LICENSE and .github/CODEOWNERS; no step reads them, and main's ruleset
+# requires no check, so such a pull request merges without a run). A change with any other file runs everything.
name: CI
on:
push:
@@ -16,11 +16,13 @@ on:
- "docs/**"
- "**/*.md"
- "LICENSE"
+ - ".github/CODEOWNERS"
pull_request:
paths-ignore:
- "docs/**"
- "**/*.md"
- "LICENSE"
+ - ".github/CODEOWNERS"
workflow_dispatch:
permissions:
diff --git a/CLAUDE.md b/CLAUDE.md
index 7944582..b342f7c 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -55,7 +55,7 @@ The first consumer is [dw2003recomp](https://github.com/gascarcella/dw2003recomp
| `examples/` | `dw2003.game.json` (the first game's description, a copy; the game's own is the source), `hello/` (a disc-free Psy-Q program built through the stack; `steam/` its Steam artwork, drawn by `make_art.py`), `tasks/` (the same with its work in tasks on the stack's fibers, preempted by a root counter 3 event) |
| `tests/` | `hello_test.py`, `tasks_test.py` (the fibers, with save states), `shim_test.py` and `shim/` (the shim's deterministic pieces, no runtime), `game_gen_test.py`, `sha256_test.py` (runtime/sha256.c against FIPS 180-4 and hashlib), `fixtures/` (the launcher self-test's mod manifests and GitHub's release answers; `mods/multipliers`, the menu test's large page; `steam/`, a `shortcuts.vdf` and a `loginusers.vdf` from its `make_fixtures.py`) |
| `docs/` | See below |
-| `.github/workflows/ci.yml` | Jobs: `game-gen`, `hello` (hello and tasks, the latter also under the sanitizers; SHA-256, tests/sha256_test.py), `mcp`, `launcher` (build + self-test; hello with the in-game menu, its input self-test; hello's own launcher, its Steam artwork embedded), `windows` (cross-build + self-test under Wine, hello and tasks too); no disc, no game; not run for a change to Markdown or LICENSE alone |
+| `.github/workflows/ci.yml` | Jobs: `game-gen`, `hello` (hello and tasks, the latter also under the sanitizers; SHA-256, tests/sha256_test.py), `mcp`, `launcher` (build + self-test; hello with the in-game menu, its input self-test; hello's own launcher, its Steam artwork embedded), `windows` (cross-build + self-test under Wine, hello and tasks too); no disc, no game; not run for a change to Markdown, LICENSE or CODEOWNERS alone |
## Commands
```sh
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..1e0ab2b
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,85 @@
+# Contributing to psxstack
+
+psxstack is a reusable stack for PC ports of decompiled PlayStation games. A change here reaches every game that
+builds on it, so the rules below keep the stack generic, legal and reviewable. Read `README.md` first, then
+`docs/GAME_CONTRACT.md`: what a game provides and what the stack provides.
+
+## Ground rules
+
+### No game code, no game data, no Psy-Q SDK
+Nothing from a game's `src/`, its disc or its extracted files comes here. The Psy-Q declarations the shim compiles
+against are the stack's own (`include/psxstack/psyq/`), written from the games' use of the API under Sony's names,
+with no SDK file (docs/DECISIONS.md "Psy-Q declarations: the stack's"). The shim never decompiles Sony's code; it
+reimplements the libraries' behavior over the hardware models. Anything borrowed is recorded in
+`docs/THIRD_PARTY.md`.
+
+### No fact about a game in the stack
+No address, file ID, overlay name, disc hash, serial, title or directory name. They come from the game's `game.json`
+(generated into `psxstack_game_gen.h` at configure time by `tools/game_gen.py`) or from the game's adapter behind
+`include/psxstack/game.h`.
+
+### The contract first
+A change to what a game must supply, or to a hook macro's meaning, is a change to `docs/GAME_CONTRACT.md` first. An
+incompatible one bumps `PSXSTACK_API` (`include/psxstack/game.h`). The hook macro names (`PLATFORM_WAIT`,
+`OVERLAY_COPY`, `SLOT_FUNC`, …) are stable API: games have hundreds of sites.
+
+### Reproducible
+Setup steps go in `scripts/` or `docs/`, never only in shell history. A new pinned tool is a `scripts/setup.sh` step
+into `tools/
`, a `.gitignore` line (without a trailing slash) and a line in `docs/THIRD_PARTY.md`. Nothing
+installs system-wide or needs sudo.
+
+## Getting set up
+```sh
+git clone https://github.com/gascarcella/psxstack && cd psxstack
+scripts/setup.sh # SDL3 and Dear ImGui into tools/, no sudo
+python3 tests/hello_test.py # the smoke test
+```
+`README.md` "Setup" lists the other tools (DXC for the hardware renderer, llvm-mingw for Windows) and "Tests" every
+test the stack runs on its own.
+
+## Making a change
+
+### Branch and pull request
+1. Open or pick an [issue](https://github.com/gascarcella/psxstack/issues): problems and plans live there.
+2. Branch from `main`; a large change goes in phases, each one reviewable on its own.
+3. Open a pull request to `main`. Its description says what was done and lists the gates that ran.
+4. CI must be green (`.github/workflows/ci.yml`; a change to Markdown, `LICENSE` or `.github/CODEOWNERS` alone runs nothing). A code owner
+ (`.github/CODEOWNERS`) reviews and merges.
+
+### Gates
+- **Always:** the tests in `README.md` "Tests" that touch what changed; `python3 -m py_compile tools/*.py
+ tools/mcp/*.py tools/replay/*.py tests/*.py` for Python.
+- **`runtime/`, `psyq/`, `cmake/` or the contract:** also a real game. `examples/hello` exercises little; the gate
+ is the first game: in a [dw2003recomp](https://github.com/gascarcella/dw2003recomp) checkout,
+ `cmake -S port -B build/port -G Ninja -DPSXSTACK_DIR=/path/to/psxstack` and its `scripts/test.sh` (it needs the
+ game's disc; its README says how). A contributor without one says so in the pull request, and the owner runs it.
+- **The launcher:** its self-test (`launcher/README.md`).
+- **Windows:** the cross-build and the tests under Wine when the change touches platform code
+ (`runtime/platform.c`, `cmake/windows-x86_64.cmake`, `windows/`).
+
+Don't claim something works until it has run; when unsure, say so in the pull request.
+
+### Docs
+- Update the docs that describe how things are (`docs/`, `README.md`) when the state changes.
+- Record a decision in `docs/DECISIONS.md` only when it changes how the stack works: a few lines, what and why.
+- Docs cite each other as `docs/X.md "Heading"`, so keep headings stable. They are lean: how things are and why, no
+ logs. Leftover work becomes an issue, not a doc.
+
+### Code style
+Write code that reads like the code around it. The naming:
+- the runtime's API the game's C calls is `port_*` (`include/psxstack/hooks.h`);
+- the adapter functions a game implements are `game_*` (`include/psxstack/game.h`);
+- CMake is `psxstack_*` functions and `PSXSTACK_*` options;
+- the generated description macros are `PSXSTACK_GAME_*` and `PORT_SLOT_*`;
+- environment variables derive from the game's `env_prefix` (`_PORT_*`, `_CONFIG_DIR`);
+- Psy-Q names stay Sony's.
+
+### Commits
+Commit messages say what and why in plain words. One topic per commit.
+
+## Releases
+Releases are semver tags (`vMAJOR.MINOR.PATCH`), cut by the owner. A game pins a tag, so a change here reaches it as
+a reviewable pin bump (docs/GAME_CONTRACT.md "Compatibility and versions").
+
+## License
+By contributing you agree that your contribution is licensed under the MIT license (`LICENSE`).
diff --git a/README.md b/README.md
index 017c3dd..ebca364 100644
--- a/README.md
+++ b/README.md
@@ -5,26 +5,164 @@ interrupt pump, software and hardware rendering, SPU, input, memory cards, setti
save states), a Psy-Q shim, a launcher (SDL3, Dear ImGui) with mod manifests, and the build and packaging scripts. A
game repo (a matching decompilation) adds a small adapter and gets a Linux and Windows port, a launcher and a release.
-It grew out of the [Digimon World 2003 decompilation](https://github.com/gascarcella/dw2003recomp)'s `port/` and
-`launcher/`, which consume it as a git submodule since `v0.1.0`.
+The stack contains no game code and no game data; `docs/GAME_CONTRACT.md` is the line between the two. The first
+consumer is [dw2003recomp](https://github.com/gascarcella/dw2003recomp), the Digimon World 2003 decompilation.
+
+## Features
+
+### Runtime
+- **Memory and overlays:** an arena that keeps the PS1's distances between the game's memory slots, an N-slot overlay
+ manager with data reset and address tables, an optional heap (docs/PORT.md "Memory arena", "Overlays").
+- **Timing:** the interrupt pump at the game's nominal rate (50 PAL, 60 NTSC), root counters, vblank handlers
+ (docs/PORT.md "Interrupts, the pump and timing").
+- **Fibers:** a game's own tasks on host stacks of the runtime's, switched where its scheduler says and preempted at
+ the end of a vsync tick (docs/PORT.md "Fibers").
+- **Disc, memory cards and movies:** the disc image with a SHA-1 check against the game's known discs, memory cards
+ as files, MDEC movies and XA audio at the drive's rate (docs/PORT.md "Disc, memory cards and movies").
+- **Save states:** save and load anywhere, F5/F9 in the window, `--save-state`/`--load-state` on the command line
+ (docs/RUNTIME.md "Save states").
+- **Crash reports:** the build, the overlays, the game's state, the log's last lines and the stack, a minidump on
+ Windows (docs/PORT.md "Crash report").
+- **Debug channel** and an MCP server over it, for driving and inspecting a running game (`tools/mcp/README.md`).
+
+### Rendering
+- **The software GPU:** the PS1's picture pixel for pixel, headless or in a window.
+- **The hardware renderer** on SDL_GPU (Vulkan; Direct3D 12 on Windows): internal resolution up to 8x, sub-pixel
+ precision from the GTE's fractions, optional perspective-correct texturing (docs/PORT.md "Rendering",
+ "Sub-pixel precision").
+- **Present filters:** sharp bilinear, scanlines, CRT, xBR (docs/RUNTIME.md "The window").
+- **Screen fit:** fit, integer or stretch scaling; a wide 16:9 canvas a game's mod can turn on for the scenes that
+ widen.
+- **Texture dumps and texture packs**, keyed by content (docs/RUNTIME.md "Texture dump", "Texture packs").
+
+### Sound and input
+- **The SPU core** and the audio device over SDL3, a WAV dump for tests (docs/RUNTIME.md "The SPU core", "Audio").
+- **Input:** keyboard and gamepads with rebindable buttons and hotkeys, a second player on a second gamepad
+ (docs/LAUNCHER.md "Input bindings").
+- **Input scripts:** replays a script drives frame by frame, the same grammar in the emulator and on the port
+ (docs/RUNTIME.md "The replay runners").
+
+### The Psy-Q shim
+- Sony's libraries reimplemented over hardware models (`gpu.c`, `gte.c`, `mdec.c`, `xa.c`), never decompiled:
+ LIBAPI, LIBC2, LIBCARD, LIBCD, LIBETC, LIBGPU, LIBGS, LIBGTE, LIBMCRD, LIBPAD, LIBPRESS, LIBSND, LIBSPU (docs/PORT.md "The Psy-Q shim").
+- The stack's own Psy-Q declarations (`include/psxstack/psyq/`), checked against a game's (`tools/psyq_decls.py`).
+
+### Launcher and in-game menu
+- **The launcher:** disc check, video, audio, memory card, controls and mods settings, the game's crash report; every
+ string from the game's description (docs/LAUNCHER.md, `launcher/README.md`).
+- **Updates:** a check against the game's GitHub releases, Update now and the launcher's own update
+ (docs/LAUNCHER.md "Updates").
+- **Add to Steam:** the game as a non-Steam shortcut with its artwork, for Steam's library, Game Mode on the Steam
+ Deck and its controller configuration (docs/LAUNCHER.md "Steam").
+- **The in-game menu:** the launcher's Settings, Controls and Mods inside the game's window on Escape or Back+Start,
+ applied live (docs/LAUNCHER.md "In-game menu").
+
+### Mods
+- Mod manifests with generated settings pages, code mods in the game, data mods from a mods directory, a load order
+ (docs/LAUNCHER.md "Mod manifest", "Data mods", "Mod runtime").
+- The stack's own mods, which every game has: `fast_forward` (hold Tab) and `fast_loading`.
+
+### Build, platforms and tools
+- **One CMake call:** `psxstack_add_game()` (`cmake/psxstack.cmake`) builds the game's C for a 64-bit host, with
+ section renaming, post-link checks and a version stamp from the game's tags.
+- **Platforms:** Linux, and Windows cross-built from Linux with llvm-mingw (tested under Wine); release packages an
+ AppImage and a Windows zip.
+- **Gates:** the host-compile inventory (`tools/port_inventory.py`), sanitizer and `-m32` builds, the replay runners
+ against PCSX-Redux (`tools/replay/`), the launcher's self-test.
+- **Reproducible tools:** `scripts/setup.sh` pins SDL3, Dear ImGui, DXC, llvm-mingw and CMake into `tools/`, no sudo.
+
+## Contents
+- [Features](#features): [Runtime](#runtime) · [Rendering](#rendering) · [Sound and input](#sound-and-input) ·
+ [The Psy-Q shim](#the-psy-q-shim) · [Launcher and in-game menu](#launcher-and-in-game-menu) · [Mods](#mods) ·
+ [Build, platforms and tools](#build-platforms-and-tools)
+- [Using it from a game](#using-it-from-a-game): [What a game provides](#what-a-game-provides) ·
+ [Adding the stack](#adding-the-stack) · [Building the port](#building-the-port) ·
+ [Building the launcher](#building-the-launcher) · [Versions and releases](#versions-and-releases)
+- [Developing](#developing): [Setup](#setup) · [Tests](#tests) · [Layout](#layout) · [Docs](#docs) ·
+ [Contributing](#contributing)
+- [Background](#background): [Status](#status) · [How it got here](#how-it-got-here)
+- [License](#license)
-**Status: `v0.3.13`** (Add to Steam: the launcher puts the game in the player's Steam library as a non-Steam shortcut and takes it out again, `launcher.steam`, the optional artwork `launcher.steam_art` in game.json; v0.3.12 the in-game menu fitted to the screen, its Menu size, a Mods page that fits 640x480; v0.3.11 the launcher checks the game's GitHub releases and updates itself: `launcher.updates` in game.json, Update now, `--no-update-check`; v0.3.10 the mods' `stop` callback and `applies` in force, for the in-game menu's live switch; v0.3.9 the in-game menu: the launcher's Settings, Controls and Mods inside the game's window on Escape or Back+Start, applied live, `PSXSTACK_MENU`; v0.3.8 faster loading: the `fast_loading` mod, movies at the drive's rate; v0.3.7 quick save and load hotkeys, F5/F9; v0.3.6 a `write_mem` script step, a clean fiber stack under ASan; v0.3.5 a game that needs its disc says so in game.json; v0.3.4 the launcher self-test's rate, the GPU's known differences; v0.3.3 LIBC2's rand and the nominal rates; v0.3.2 a checkpoint without an image; v0.3.1 brought the second game's shim: LIBGTE, LIBGPU, LIBGS, LIBAPI, LIBCD, LIBSND, LIBCARD; v0.3.0 brought
-an optional heap, the stack's own Psy-Q declarations, fibers for a game's tasks, the replay runners; v0.2.0 brought the hardware renderer on D3D12, sub-pixel precision, filters,
-texture packs, a wide canvas and save states). Everything a game needs is here: the contract (`docs/GAME_CONTRACT.md`), the game description
-and its generator (`schema/game.schema.json`, `tools/game_gen.py`), the runtime and the Psy-Q shim (`runtime/`,
-`psyq/`), the build (`cmake/psxstack.cmake`), the launcher (`launcher/`), the tools and the docs. One game builds on
-it so far; the second will widen the shim and the contract (releases follow semver, `PSXSTACK_API` counts
-incompatible contract changes).
+## Using it from a game
+
+### What a game provides
+A matching decompilation whose C also compiles for a 64-bit host, plus a small adapter (`docs/GAME_CONTRACT.md`
+"What the game provides"):
+1. **`game.json`**, the game description (`schema/game.schema.json`): its id, title, discs, rate, memory slots,
+ optional updates repository and Steam artwork. It is generated into a header at configure time; nothing reads it
+ at run time.
+2. **A hook header** holding the PS1 side of every hook macro and including `` under `PC_PORT`, so
+ the matching build never depends on the stack.
+3. **The hooks in its C** (`PLATFORM_WAIT`, `OVERLAY_COPY`, `SLOT_FUNC`, …).
+4. **Adapter units** implementing ``, and its own mods.
+5. **The build inputs:** the unit list, the overlay list, its symbol files.
+6. **Its tests:** the goldens, the replay scripts and the emulator's probes.
+### Adding the stack
+The stack is a git submodule pinned at a release tag:
```sh
-scripts/setup.sh sdl3 imgui # or scripts/dev_link_tools.sh ../dw2003recomp/tools to reuse built tools
-cmake -S launcher -B build/launcher -G Ninja [-DPSXSTACK_GAME_JSON=path/to/game.json] && cmake --build build/launcher
+git submodule add https://github.com/gascarcella/psxstack psxstack
+git -C psxstack checkout v0.3.16
+```
+
+### Building the port
+```cmake
+include(psxstack/cmake/psxstack.cmake) # the submodule, pinned at a tag
+psxstack_add_game(mygame GAME_JSON port/game/game.json UNITS build/gen/units.txt MAIN_UNIT src/main.c
+ OVERLAYS build/gen/overlays.txt INCLUDE_DIRS include . ADAPTER port/game/state.c ...)
+```
+`cmake/psxstack.cmake` documents every argument and docs/RUNTIME.md "Build and run" the options and the command line.
+The consumers to copy from:
+- `examples/hello`, the smallest: one unit, no overlays, no disc;
+- `examples/tasks`, the same with its work in tasks on the stack's fibers;
+- dw2003recomp's `port/CMakeLists.txt`, the first real one.
+
+### Building the launcher
+The launcher is its own CMake project, branded from the game's description:
+```sh
+cmake -S psxstack/launcher -B build/launcher -G Ninja -DPSXSTACK_GAME_JSON=... -DPSXSTACK_VERSION_ROOT=...
+cmake --build build/launcher
+```
+`launcher/README.md` has the rest, the Windows build and the self-test among it.
+
+### Versions and releases
+Releases are semver tags; a game pins one, so a change here reaches it as a reviewable pin bump. `PSXSTACK_API`
+(`include/psxstack/game.h`) counts incompatible contract changes. A game's release packages are named so the
+launcher's update check finds them (docs/GAME_CONTRACT.md "Compatibility and versions", "Releases").
+
+## Developing
+
+### Setup
+`scripts/setup.sh` builds the pinned tools into `tools/` (gitignored, no sudo, idempotent):
+```sh
+scripts/setup.sh # sdl3 imgui link: enough for the launcher and the tests
+scripts/setup.sh dxc llvm-mingw sdl3-windows # the hardware renderer's shaders, the Windows cross-build
+scripts/dev_link_tools.sh ../dw2003recomp/tools # or reuse a game checkout's built tools
+scripts/setup.sh link # in a git worktree: link the main checkout's
+```
+A desktop window needs SDL3 built with the X11/Wayland `-dev` headers present (docs/RUNTIME.md "The window").
+
+### Tests
+None needs a disc or a game:
+```sh
+python3 tests/hello_test.py [--menu] [--gpu] # the smoke test: examples/hello built through psxstack_add_game()
+python3 tests/tasks_test.py [--sanitize|--m32] # the fibers, with save states
+python3 tests/shim_test.py [--sanitize|--m32] # the shim's deterministic pieces on their own
+python3 tests/psyq_test.py [--sanitize] # the shim's LIBGTE and LIBGPU
+python3 tests/game_gen_test.py # the description generator
+python3 tests/sha256_test.py # runtime/sha256.c
+python3 tests/replay_test.py # the replay runners against a fake emulator
+python3 tools/mcp/selftest.py # the MCP server against a fake game
+psyq/check.sh --compile # the shim with -Werror against the stack's declarations
+cmake -S launcher -B build/launcher -G Ninja && cmake --build build/launcher
SDL_VIDEO_DRIVER=offscreen build/launcher/dw2003-launcher --self-test build/selftest
-python3 tests/game_gen_test.py # the description generator's test
-python3 tests/psyq_test.py [--sanitize] # the shim's LIBGTE and LIBGPU functions on their own
```
+CI (`.github/workflows/ci.yml`) runs these on Linux and the Windows cross-build under Wine. A change to `runtime/`,
+`psyq/`, `cmake/` or the contract is also tested against a real game: in a dw2003recomp checkout,
+`cmake -S port -B build/port -G Ninja -DPSXSTACK_DIR=/path/to/psxstack` and its `scripts/test.sh` (it needs the
+game's disc).
-## Layout
+### Layout
| Path | Contents |
|---|---|
@@ -41,25 +179,59 @@ python3 tests/psyq_test.py [--sanitize] # the shim's LIBGTE and LIBGPU function
| `schema/` | `game.schema.json`: the game description |
| `examples/` | `dw2003.game.json` (the first game's description); `hello/`, a disc-free Psy-Q program built through the stack: its smoke test; `tasks/`, the same with its work in tasks on the stack's fibers |
| `docs/` | `GAME_CONTRACT.md`, `PORT.md`, `RUNTIME.md`, `LAUNCHER.md`, `DECISIONS.md`, `THIRD_PARTY.md` |
-| `tests/` | The stack's own tests: `hello_test.py`, `tasks_test.py` (the fibers, with save states), `game_gen_test.py`, `psyq_test.py` (the shim's LIBGTE and LIBGPU, its C in `tests/psyq/`), `shim_test.py` (the shim's deterministic pieces on their own: events, the memory card's BIOS calls, `CdSearchFile`; its C in `tests/shim/`), the launcher's fixtures (`launcher --self-test`, `tools/mcp/selftest.py`) |
+| `tests/` | The stack's own tests: `hello_test.py`, `tasks_test.py` (the fibers, with save states), `game_gen_test.py`, `psyq_test.py` (the shim's LIBGTE and LIBGPU, its C in `tests/psyq/`), `shim_test.py` (the shim's deterministic pieces on their own: events, the memory card's BIOS calls, `CdSearchFile`; its C in `tests/shim/`), `sha256_test.py`, `replay_test.py`, the launcher's fixtures (`launcher --self-test`, `tools/mcp/selftest.py`) |
-## Using it from a game
-```cmake
-include(psxstack/cmake/psxstack.cmake) # the submodule, pinned at a tag
-psxstack_add_game(mygame GAME_JSON port/game/game.json UNITS build/gen/units.txt MAIN_UNIT src/main.c
- OVERLAYS build/gen/overlays.txt INCLUDE_DIRS include . ADAPTER port/game/state.c ...)
-```
-`cmake/psxstack.cmake` documents every argument; `docs/GAME_CONTRACT.md` what the game provides; `examples/hello` is
-the smallest consumer (`examples/tasks` the same with its work in tasks on the stack's fibers), dw2003recomp's
-`port/CMakeLists.txt` the first real one. The launcher is its own project:
-`cmake -S psxstack/launcher -B build/launcher -DPSXSTACK_GAME_JSON=... -DPSXSTACK_VERSION_ROOT=...`.
+### Docs
+| Doc | What it covers |
+|---|---|
+| `docs/GAME_CONTRACT.md` | What a game provides and what the stack provides |
+| `docs/PORT.md` | The runtime's design: hook macros, arena, overlays, pump, shim, rendering, sound, crash report |
+| `docs/RUNTIME.md` | Building, running, options and formats |
+| `docs/LAUNCHER.md` | The launcher/game contract, the settings file, mod manifests, updates, Steam, the in-game menu |
+| `docs/DECISIONS.md` | The decisions and why |
+| `docs/THIRD_PARTY.md` | Borrowings and pinned tools |
+| `tools/mcp/README.md` | The MCP server |
+| `launcher/README.md` | Building the launcher and its self-test |
+
+### Contributing
+`CONTRIBUTING.md` has the ground rules (no game code, no game data, no Psy-Q SDK; no fact about a game in the stack;
+the contract first), the gates a change runs and how a pull request is made. Problems and plans are
+[GitHub issues](https://github.com/gascarcella/psxstack/issues); `.github/CODEOWNERS` names who reviews.
-## How it got here
+## Background
-Built in five phases out of dw2003recomp's port (its `docs/DECISIONS.md` "The port stack lives in psxstack"): the
-contract first, the port split in place behind it, the runtime and the launcher moved here against a scratch copy
-of the game, the game converged on the submodule, then `v0.1.0`. `docs/DECISIONS.md` has the decisions.
+### Status
+**`v0.3.16`.** One game builds on it so far; the second will widen the shim and the contract. The recent releases:
+- **v0.3.16:** the picture fits the screen (`video.scaling`, fit by default), the wide canvas at the window's aspect.
+- **v0.3.15:** the in-game menu on the hardware renderer; unmuting a game started muted opens the audio device.
+- **v0.3.14:** the launcher's self-test inside an AppImage.
+- **v0.3.13:** Add to Steam (`launcher.steam`, the optional artwork `launcher.steam_art`).
+- **v0.3.12:** the in-game menu fitted to the screen, its Menu size, a Mods page that fits 640x480.
+- **v0.3.11:** the launcher checks the game's GitHub releases and updates itself (`launcher.updates`, Update now,
+ `--no-update-check`).
+- **v0.3.10:** the mods' `stop` callback and `applies`, for the in-game menu's live switch.
+- **v0.3.9:** the in-game menu: the launcher's Settings, Controls and Mods inside the game's window, applied live
+ (`PSXSTACK_MENU`).
+- **v0.3.8:** faster loading: the `fast_loading` mod, movies at the drive's rate.
+- **v0.3.7:** quick save and load hotkeys, F5/F9.
+- **v0.3.6:** a `write_mem` script step, a clean fiber stack under ASan.
+- **v0.3.5:** a game that needs its disc says so in game.json.
+- **v0.3.4:** the launcher self-test's rate, the GPU's known differences.
+- **v0.3.3:** LIBC2's rand and the nominal rates.
+- **v0.3.2:** a checkpoint without an image.
+- **v0.3.1:** the second game's shim: LIBGTE, LIBGPU, LIBGS, LIBAPI, LIBCD, LIBSND, LIBCARD.
+- **v0.3.0:** an optional heap, the stack's own Psy-Q declarations, fibers for a game's tasks, the replay runners.
+- **v0.2.0:** the hardware renderer on D3D12, sub-pixel precision, filters, texture packs, a wide canvas and save
+ states.
+
+### How it got here
+It grew out of the [Digimon World 2003 decompilation](https://github.com/gascarcella/dw2003recomp)'s `port/` and
+`launcher/`, which consume it as a git submodule since `v0.1.0`. It was built in five phases out of dw2003recomp's
+port (its `docs/DECISIONS.md` "The port stack lives in psxstack"): the contract first, the port split in place behind
+it, the runtime and the launcher moved here against a scratch copy of the game, the game converged on the submodule,
+then `v0.1.0`. `docs/DECISIONS.md` has the decisions.
## License
-MIT (`LICENSE`). The stack contains no game code and no game data.
+MIT (`LICENSE`). The stack contains no game code and no game data; `docs/THIRD_PARTY.md` lists what it borrows and the
+tools it pins.