Demon's Crest (SNES Recomp)
Demon's Crest (SNES Recomp) is a native PC recompilation of Demon's Crest for Super Nintendo Entertainment System with adaptive widescreen, save states, and rewind.
- Type: PC port
- Game: Demon's Crest
- Runs on Windows
- By rac08241988
- Latest release v1.0.3, 2026-10-29
- Source: https://github.com/rac08241988/DemonsCrestSNESRecomp
README
Demon's Crest Recompiled
This fork ships no game code, ROM data or game screenshots. The upstream screenshots were removed on this branch.
Play on Windows (no coding needed)
- Download
DemonsCrest-SNESRecomp-windows-x64-v1.0.0.zipfrom this fork's Releases page and unzip it anywhere. - Open
DemonsCrestSNESRecomp.exe. - Click Browse For ROM and pick your own Demon's Crest (USA) ROM
(
.sfc/.smc, SHA-25618d40a80...5844de). - Let it build. The first time it downloads a portable compiler and builds the game on your PC, which takes a few minutes.
- Click Play. Next time, just open the exe.
The zip has no game code and no ROM. It holds the setup exe, its DLLs, the
GPL shaders, the prebuilt snesrecomp-analyze.exe (so no Rust install is
needed) and the build tools/configs. The first run downloads a portable
toolchain (about 800 MB) into toolchain\ beside the exe and builds the game
into build\; after that, opening the setup exe hands off to
build\DemonsCrestSNESRecomp.exe. The zip root is flat with a single exe, so
launchers such as Quiver Launcher pick it up automatically. Everything is built on your machine
from your own cartridge dump. In game, press F12 or Escape (or the
pad Guide button) to open the Options menu, where you pick a CRT/RetroArch
shader and the 120 Hz motion mode. Rewind is now Shift+F12.
Native PC recompilation of Demon's Crest (USA), built on snesrecomp. The 65816 game code is translated to C and runs on the framework's authoritative interpreter, while the SNES hardware — PPU, APU/SPC700, DMA/HDMA and cartridge mapping — is emulated. Same model as N64Recomp and similar projects: recompile the CPU, emulate the silicon.
Play with adaptive widescreen, save states, rewind and the shared launcher, using your own legally dumped ROM.
Quick start | Features | Widescreen | Recording | Known issues | Build | Run
You must legally own a copy of the game. No ROM data is distributed with this project, in the repository or in any release. The recompiled C is generated locally from your own copy and is never committed.
This fork: options menu, RetroArch shaders, 120 Hz (branch shaders-120hz)
Additions on top of upstream (no game code, ROM, or generated C is committed):
- In-game Options menu - press F12 or Escape (no modifiers) or the gamepad Guide button. Arrows / D-pad move, Left/Right change, Enter or pad A accepts, Backspace or pad B goes back, Escape / F12 / Guide close it. The game pauses while it is open.
- Shader - every root-level RetroArch
.glslppreset from libretro/glsl-shaders (commit cba01a48), applied live. NeedsOutputMethod = OpenGL(now the default). Chosen only from this menu;config.ini'sShaderkey is ignored. - 120Hz motion - Off / Interpolate / Low-latency. Game logic stays at 60 Hz; on a 100 Hz+ display each in-between frame is re-rendered with interpolated scroll and sprite positions (widescreen aware). Interpolate is smoothest (blends the previous and newest frame, about half a frame of added latency); Low-latency extrapolates ahead of the newest frame instead (no added latency, may overshoot briefly when motion stops).
- Both settings persist in
dc_options.inibeside the executable. - Rebinds: Rewind moved from F12 to Shift+F12 (pad Select+R3 is unchanged). Escape had no binding in single-player play (the framework uses it only to leave a netplay session, which this target does not build, and to close its own save-state/rewind overlays, which still works).
- No console window on Windows - the game exe is a GUI-subsystem app;
its log goes to
DemonsCrest.logbeside the exe. Run it from a terminal (log prints there) or pass--consoleto open a log console.
Setup and build
git clone -b shaders-120hz https://github.com/rac08241988/DemonsCrestSNESRecomp
cd DemonsCrestSNESRecomp
scripts/setup.sh --rom "/path/to/Demon's Crest (USA).sfc" # submodules, framework patch, shaders, regen
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release && cmake --build build
# (shaders/ is staged beside the exe automatically when <repo>/shaders exists)
# Windows exe from Linux:
cmake -S . -B build-win -G Ninja -DCMAKE_TOOLCHAIN_FILE=cmake/mingw-w64.cmake -DCMAKE_BUILD_TYPE=Release
Release builder zip (no game code). Build the setup host from a tree with
an empty src/gen/, then pack it. The packager refuses ROMs and generated C,
and ships the patched sources plus shaders/, so the player's machine builds
the game with the launcher's portable cmake-clang-v1 toolchain:
scripts/setup.sh # no --rom: patch + shaders only
cmake -S . -B build-setup -G Ninja -DCMAKE_TOOLCHAIN_FILE=cmake/mingw-w64.cmake \
-DCMAKE_BUILD_TYPE=Release -DSNESRECOMP_SETUP_HOST=ON
cmake --build build-setup
scripts/package_release.sh build-setup windows-x64 # dist/demonscrest-<ver>-windows-x64.zip
setup.sh checks your ROM against rom_identity.txt (sha256
18d40a80...5844de, a 512-byte copier header is stripped) before generating
code. Fork note: upstream's snesrecomp gitlink a085bfc is not published
on magnopaz/snesrecomp, so this branch pins 88d24ef
(demons-crest/host-hooks). Test hooks: DC_SHADER_PRESET=<label>,
DC_MOTION=off|interpolate|lowlatency, DC_INTERP_HZ=<hz>. Licensing of the
additions: see NOTICE.md.
Status
The port boots and plays: the Capcom logo, intro, stage gameplay and boss
fights all run from the generated C. The native Widescreen mod is
implemented and validated through its final phase — background margins,
objects and sprites, HUD anchoring, the Mode 7 overworld, the top-band flicker
and save-state round-trips — with the engineering notes and validation summary
in docs/PORTING_NOTES.md. See Known
issues for what playtesting has since turned up, including the
save-state CPU caveat.
Playtesting continues; general gameplay bugs and broader coverage are the remaining work, so treat a full-game playthrough as not yet certified.
What has been verified by playing it
These were confirmed by actually playing (and scripting) the game, not only by frame-accuracy checks:
- Boot → play: logo, intro, title, attract and a new game all run.
- Stage gameplay and bosses: the ice cavern, mountains and castle stages run with their bosses, HUD, crest icons and forms intact.
- Widescreen: the widened field really renders stages, margins, HUD anchoring and the Mode 7 overworld as described below.
- Forms: switching gargoyle forms works and each form's sprites play.
- Scripted input: the debug server can drive the game from reset
(
set_controller,run_to_frame), which is how the boss and door tests in the companion port are run. - Recording (new): input can be recorded and replayed frame-exactly, and
frames or a rolling buffer can be written to disk — see
docs/RECORDING.md.
Known issues
Found while using the runner as a reference for a native port. None of them stop normal play, but they matter to anyone scripting or capturing the game.
- Save states do not restore the CPU. Loading a state brings back WRAM/VRAM/CGRAM/OAM, but the 65816 starts from reset: the screen shows the Capcom copyright while the memory still holds the saved scene. A state made during a boss fight therefore cannot be resumed or screenshotted — the game plays its boot sequence instead. Legacy and current states both behave this way when the ROM's own save is not part of the state.
screenshot/dump_frame_rawcapture the current frame, and frames only advance throughrun_to_frame. A paused runner that is asked for a screenshot without advancing returns the same (stale) picture, which looks like a drifting capture. Pair every capture with a frame advance.run_to_framereturns before the target frame is reached. Clients that read memory immediately after the command see the old frame; pollframeuntil it reports the target.- Widescreen edge columns can show art that was never authored for them. In the mountain stage the far-right margin can show a strip of unrelated tiles (a hazard of widening a 256-pixel game); the castle stage shows black there. Cosmetic only, and only with the widescreen mod enabled.
- Boss sprite composition is only correct in the runner. The native port built from these captures had to reassemble boss OAM parts itself and got them wrong for a while; that is a port problem, recorded here so the distinction is clear when comparing screenshots.
Features
| Available | Feature | What it adds |
|---|---|---|
| ☑ | Adaptive widescreen | Native widened field with adaptive, 16:9, 21:9 and 32:9 views. Disabled by default; with it off the game renders at the original 256-pixel width. |
| ☑ | Save states | Ten slots (F1–F10 load, Shift+F1–Shift+F10 save) plus the save-state browser (F11). States load in a fresh process, but they do not restore the CPU — see Known issues. |
| ☑ | Rewind | Rewind history (F12) over the shared framework's snapshot ring. |
| ☑ | Recording | Alt+R starts/stops a take: one BMP per presented frame plus a replayable input_log.jsonl, in captures/rec_<time>/. Needs no debug server; the protocol can additionally replay the pad stream frame-exactly or keep a rolling capture. See docs/RECORDING.md. |
| ☑ | Launcher | recomp-ui ROM picker with a verification badge, display/audio/input settings and the Mods screen. |
| ☑ | ROM verification | The ROM is checked against the project digests before anything boots; a mismatched dump is refused instead of mis-executing. |
| ☑ | Authentic 4:3 | The original 256-pixel field and layer layout remain the default when the widescreen mod is off. |
Widescreen
Enable Widescreen in the launcher's Mods screen and pick a view: Adaptive, 16:9 (342 px), 21:9 (448 px) or 32:9 (682 px). The mod is off by default.
What it does:
- renders the game directly into the widened field (
native_widescreen), so the scrolling backgrounds continue into symmetric margins; - gates widening to stage gameplay (
$8Din 1..0x7F, or the Mode 7 overworld map with its alternate-HUD variant): menus, cutscenes, password and transitional screens stay pillarboxed; - widens the object-loop cull and the OAM emitter so enemies and effects just outside the native view keep updating and appear in the margins, and widens the attack projectile's on-screen test so shots fly across the whole field;
- anchors the BG3 status bar to the widened left edge and leaves the freed columns transparent, showing the scenery where the bar used to sit; BG3 is widened only on the bar's scanlines, so a dialogue box on the same layer keeps its native columns;
- keeps the Start/status menu pillarboxed (
$00FBmarks it): it is a full-screen native UI, and widening it would show the stage tilemap in the margins; - drops the game's forced-blank upload cover from the raster replay in every scene (a field that stays blank keeps its black), which removes the black band that flickered at the top and lets HDMA tables start at the top of the field, keeping window effects aligned with their targets;
- keeps dialogue boxes and edge windows intact: the fixed-color box cannot leak a strip into the top-left corner, and a parked one-pixel layer window moves with the widened edge instead of cutting a one-pixel seam at the margin boundary;
- opens the Mode 7 overworld map to the widened field; the terrain continues into the margins with no renderer change.
The generated-code hooks are applied by
tools/dc_apply_widescreen_hooks.py, an
idempotent injector run by tools/regen.sh and by the build. At margin 0 every
injected expression evaluates to the authentic constant, so the object and
sprite hooks add nothing to the 4:3 path.
Diagnostic kill-switches for A/B captures:
SNESRECOMP_WS_OAM=0 (object/sprite widening),
SNESRECOMP_WS_HUD=0 (status-bar anchoring),
SNESRECOMP_WS_NOBLANK=0 (upload-cover policy),
SNESRECOMP_WS_CULL=<px> (cap the margin object window; 0 = authentic cull)
and SNESRECOMP_WS_EXTRA=<px> (fixed margin).
Quick start (build from source)
-
Clone with the framework and launcher submodules:
git clone --recurse-submodules https://github.com/magnopaz/DemonsCrestSNESRecomp.git cd DemonsCrestSNESRecomp -
Have your own Demon's Crest (USA) ROM available. Keeping it outside the repository is the better habit;
SNESRECOMP_ROMsets the path once for a shell. -
Generate the recompiled C from the ROM:
bash tools/regen.sh --rom "/path/to/Demon's Crest (USA).sfc" -
Configure and build:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release cmake --build build -j -
Run:
./build/DemonsCrestSNESRecompThe launcher asks for the ROM on the first run and caches the choice.
On Windows with the MinGW toolchain, tools/play.ps1 wraps regeneration,
configuration, build and launch in one step.
Build
The default desktop backend is SDL3 (fetched and built from source when no
package is installed). To build against an installed SDL2 development package
instead — for example the MinGW one at M:\SDL on Windows:
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release \
-DSNESRECOMP_SDL_BACKEND=SDL2 \
-DSDL2_DIR="M:/SDL/SDL2-2.32.6/x86_64-w64-mingw32/lib/cmake/SDL2"
tools/play.ps1 automates regen + configure + build + launch for the Windows
MinGW toolchain (CMake, Ninja, GCC, Rust GNU, SDL2 under M:\SDL). It refuses
to build while a game instance is running (a forced kill would end that
session with no exit report); pass -KillRunning to terminate it explicitly.
The ROM does not have to live in the repository — SNESRECOMP_ROM sets the
path for a shell. Without it, tools/regen.sh looks for
Demon's Crest (USA).sfc at the repo root, then for the path the setup wizard
recorded in rom.cfg; .gitignore blocks both from ever being committed.
tools/regen.sh verifies the ROM, generates src/gen/*.c, and re-syncs
recomp/funcs.h. Re-run it whenever you change anything under recomp/.
Run
./build/DemonsCrestSNESRecomp
# or name the ROM and skip the launcher
./build/DemonsCrestSNESRecomp "/path/to/Demon's Crest (USA).sfc"
With no ROM on the command line the build opens the recomp-ui launcher: a ROM
picker with a verification badge, display/audio/input settings and the Mods
screen. Your choice is cached in rom.cfg beside the executable, so the next
launch opens on it and "Skip launcher on boot" makes it immediate. If the
launcher is not built in (--no-recomp-ui), the host falls back to a native
file picker.
Either way the ROM is checked against the digests below before anything boots — a dump that could not have produced this build is refused at the door rather than mis-executing ten frames in.
During play: F11 opens the save-state browser and F12 opens rewind; both
pause gameplay while you choose. Alt+R starts/stops a recording (frames plus
a replayable input log, saved under captures/). Hotkeys, controller mappings
and pixel/aspect options live in the launcher; Alt+R can be moved with
Record = <key> in config.ini's [KeyMap].
Recording
The debug server can capture a session and reproduce it, which is how the screenshots above and the port's reference captures are made:
# keep the last ~5 seconds in memory and write them when the window closes
SNESREC_RING_DIR=captures/somulo ./build/DemonsCrestSNESRecomp "Demon's Crest (USA).sfc"
# or, with SNESRECOMP_DEBUG_PORT set, from a debug client
record_input_start
... play the fight ...
record_input_stop captures/fight.jsonl
replay_input captures/fight.jsonl # reproduce it frame-exactly
record_frames captures/somulo 600 1 # one BMP per frame
python tools/bmp_sequence.py captures/somulo --gif somulo.gif
Input is sampled where the runner reads the pad, so file frame N is the input
frame N ran with. See docs/RECORDING.md for every command
and its limits.
ROM identity
| File | Demon's Crest (USA).sfc |
| Publisher | Capcom |
| Developer | Capcom |
| Year | 1994 |
| Mapping | lorom |
| Region | USA (North America) |
| Coprocessor | none |
| CRC32 | e8236ad2 |
| SHA-256 | 18d40a807d5f88c5b6a1ad849eec7e0f189225d9a1586037c850f6680b5844de |
tools/regen.sh refuses to run against anything else, so a mismatched revision
fails immediately instead of producing subtly wrong output.
How the recompilation works
The 65816 CPU code from the ROM is statically translated to C — every function
the analysis can prove is a real generated C function in src/gen/. Execution
is LLE-first: an authoritative 65816 interpreter is the correctness floor,
and the statically compiled bodies are exact, proven materializations on top of
it — anything the static pass cannot prove keeps running through the
interpreter, loudly. The rest of the SNES is not recompiled: PPU rendering, the
APU/SPC700, DMA/HDMA, hardware register I/O and bank mapping run through
snesrecomp's runner implementations.
Rules for contributors:
- Never edit
src/gen/by hand and never synthesise a result to get past uncovered code. Fix the config or the framework and regenerate. - Name routines in
recomp/symbols.toml, then re-runtools/regen.sh. Setemit = trueto promote a routine into ahead-of-time analysis; leave it false to keep it interpreted. Only proven variants become AOT code. Seerecomp/README.md. - Deal with unresolved indirect dispatch targets before anything else — they are the reason a port diverges.
Layout
| Path | What lives there |
|---|---|
recomp/ | Analysis input: bank*.cfg, symbols.toml, generated funcs.h |
rom_identity.txt | ROM digests — read by the build, tools/regen.sh and CI |
src/ | Host code you own: main.c, game_rtl.c, widescreen policy |
src/gen/ | Generated C. Never committed — regenerate locally |
docs/ | PORTING_NOTES.md — verified state, fixes and roadmap |
mods/ | Preloaded mod catalog (the widescreen package) |
tools/ | regen.sh, play.ps1 and the widescreen code injector |
snesrecomp/ | Framework submodule (owns lib/recomp-net, lib/retcomm-rbengine) |
recomp-ui/ | Shared launcher UI submodule |
scripts/ | package_release.sh — player-facing zip |
framework_pins.txt | Exact framework commits this project was scaffolded against |
Reporting problems
Open an issue with the build, the enabled mods and the steps to reproduce the
problem. For gameplay bugs, attach the save state (build/saves/saveN.sav)
and describe the inputs that trigger it. If the game closes unexpectedly,
also attach last_run_report.prev.json (the previous run's report, preserved
on the next launch) and any crash_report_*.json / crash_minidump_*.dmp
from the build directory.
github.com/magnopaz/DemonsCrestSNESRecomp/issues
License
This project's own source is under the MIT license in LICENSE.
The framework and launcher carry their own terms — see snesrecomp/LICENSE,
snesrecomp/THIRD_PARTY_ATTRIBUTION.md and recomp-ui/LICENSE. Neither
covers the game data, which