The website of OpenRAC, an unofficial hub for community decompilation projects of the Ratchet & Clank series. It shows, for every title, how far its decompilation has come.
Next.js (App Router) · TypeScript · Tailwind CSS 4 · everything is rendered on the server.
The page is a server component. On the server it reads the state of each project from GitHub, renders plain HTML and caches it; the browser gets finished HTML plus a few small scripts for the menu and animations. No visitor ever calls GitHub. The page is rebuilt in the background at most every 5 minutes, the numbers are cached for 10 minutes.
Every project is shown with one and the same measure: code matched, the bytes of code verified identical to
the retail build out of all code bytes the project counts. The percentage on each card and the line under its bar
(838 628 of 3 712 808 code bytes matched) are both this number; no card shows a project-specific extra. It is
weighted by size because small functions are matched first, and it is the figure ByteMatch shows.
Sources (see src/lib/progress/):
- Ratchet & Clank (PAL):
progress/report.json(objdiff report) ofOpenRAC/rac1-decomp. - Ratchet & Clank (NTSC-U):
report.json(objdiff report) on theprogressbranch oflombyte-project/Lombyte, which the project's own workflow publishes and ByteMatch reads. Shown beside the PAL card. - Going Commando: the committed
progress/report.jsonon themasterbranch ofOpenRAC/rac2-gc-decomp, which is also the report ByteMatch reads. The site uses its matched code and total code bytes directly, so the percentage and function counts match ByteMatch. Shared level code is counted in the report's scope, rather than once per overlay placement. - Up Your Arsenal (PAL):
progress/report.json(objdiff report) ofOpenRAC/rac3-decomp, which the project commits and refreshes with its own tooling (python3 tools/progress.py --write). It is the same figure ByteMatch shows. - Ratchet: Deadlocked (NTSC-U):
progress/report.json(objdiff report) ofOpenRAC/rac4-decomp. - Going Mobile: the verified method count in the
README.mdofClank700/going-mobile-decomp, applied to the size of the reconstructed source. - Size Matters (PS2, NTSC-U):
progress/status.jsonofOpenRAC/rac5-sm-decomp, the project's scoped progress snapshot. It has no qualified game-wide percentage yet, so the number is the one the project itself publishes: the measured boot.text, the frontend's candidate code interval and the levels' optimistic masked-shape scenario, which is the arithmetic of itstools/bytematch_estimate.pyand the figure ByteMatch shows. - Secret Agent Clank (PS2, NTSC-U):
progress/report.jsonofOpenRAC/rac-sac-decomp(objdiff report), deduplicating shared level code and matching ByteMatch. If the report is unavailable, candidate tables are read as a fallback.
If GitHub cannot be reached, the last known snapshot (FALLBACK in src/lib/progress/index.ts) is shown and labelled as such.
We use AI ourselves, so we do not block crawlers; we make the site easy to read instead. All of it is built from
the same data as the page (src/lib/machine.ts), so it never says anything the page does not:
| Address | What |
|---|---|
/progress.json |
every project and its numbers as JSON, open to any origin (CORS) |
/llms.txt |
a short Markdown map of the site for AI tools (llmstxt.org) |
/llms-full.txt |
the same, plus the FAQ in full |
/mods.json |
every listed mod as JSON, open to any origin (CORS) |
/news.xml |
the written news reports as RSS |
/robots.txt |
allows everything; Content-Signal: search=yes, ai-input=yes, ai-train=yes says so explicitly |
The home page and every mod page also carry schema.org JSON-LD (the projects as SoftwareSourceCode, mods as
SoftwareApplication), and the page head links the JSON and llms.txt versions.
/mods lists the community mods of the PC port, read on the server from the signed mod index that
openrac-mods publishes (MOD_INDEXES in .env.example). Install opens
the launcher through its openrac:// link, which installs the mod with its dependencies. Pictures are resized by
the index build and served from this site (/mods/media/...), so visitors never load anything from GitHub.
- Authors list a mod through openrac-mods' submission form on GitHub, where a bot checks it;
/mods/submitredirects there. /mods/set?m=id@1.2.0,...is a "Share my setup" link from the launcher: a friend's mods at exact versions.- Mod pages show the latest comments of the mod's GitHub Discussion (needs
GITHUB_TOKEN); commenting happens on GitHub.
/mods/docs is the mod SDK's documentation, per SDK release, generated from OpenRAC's sdk-v* tags
(mod-docs/).
Browser tests: npm run test:e2e (Playwright) builds the site against the shared fixture index and runs e2e/.
/news shows what happens across the projects, built from the news/ folder, so new news appears with the
next deploy. A GitHub job collects each finished week's facts on Monday with no AI, and people add weekly reports through
pull requests using their own AI tools (how). Every report names its author and tool and lists its
sources, and text from those files is only ever shown as plain text.
The server reads GitHub for the activity feed, the Download panel and mod
comments. It signs in as the OpenRAC GitHub App (src/lib/githubApp.ts), owned by the
organization, so nothing expires or depends on one person: its private key gets a fresh one-hour token
whenever needed. Without the app it uses GITHUB_TOKEN; if GitHub refuses a token, it goes on without
one (60 requests an hour) and logs why.
Setting the app up, once (an organization owner):
- github.com/organizations/OpenRAC/settings/apps/new: name
OpenRAC website, homepagehttps://openrac.dev, Webhook: off. Repository permissions: Contents: read, Metadata: read, Discussions: read. Nothing else. "Only on this account". - Create it, note the App ID, then Generate a private key (a
.pemdownloads). - Install App → OpenRAC → All repositories (or the public ones the site reads).
- On the server:
podman secret create openrac-github-app ~/openrac-github-app.pem, delete the.pem, putGITHUB_APP_ID=<id>in~/.config/openrac/openrac.env, uncomment the three lines indeploy/openrac.container, thensystemctl daemon-reload && systemctl restart openrac.service.
podman logs shows github_app_token_failed (with GitHub's status) if the app is refused.
src/lib/credits.ts lists the people credited on the front page and their YouTube videos (links or video ids).
The section stays hidden until a video is listed. Titles and thumbnails are fetched by the server, and a video
loads from YouTube (privacy-enhanced youtube-nocookie.com) only when a visitor presses play, so nothing
reaches Google before that.
npm install
npm run dev # http://localhost:3000
npm test # unit tests (progress parsers, mods, machine-readable files)
npm run lint
npm run buildsrc/app/ pages and routes (home, mods, /img, progress.json, mods.json, llms.txt, robots, sitemap)
src/components/layout/ the header, footer and the scroll-reveal helper, on every page
src/components/sections/ the home page's sections, one file each, in page order in src/app/page.tsx
src/components/ui/ small shared pieces (Section heading, Cards, Backdrop, Logo, icons, ...)
src/lib/projects.ts the list of titles: names, repositories, colours, maintainers
src/lib/progress/ reading each project's progress from GitHub (one parser per format, with tests)
src/lib/mods/ the mod index: loading, versions, dependencies, search (with tests)
src/lib/youtube/ video titles for Credits
src/lib/releases.ts the launcher's latest release for the Download panel, a card per system
src/lib/machine.ts progress.json, llms.txt and the structured data for search engines
src/components/mods/ the mod list and mod pages
deploy/ the Podman Quadlet unit
Copy .env.example to .env.local to change settings. GITHUB_TOKEN stays on the server and raises the GitHub API
rate limit for the activity feed and the Download panel. Set it in production: without it GitHub allows 60 requests
an hour per address, and every five-minute refresh of the home page makes about ten (one per project's commits, one
for the launcher's releases). A fine-grained token with no permissions is enough, since all the repositories are public.
The title cards can show a backdrop image named rac1-bg.webp, rac1us-bg.webp, gc-bg.webp, uya-bg.webp, deadlocked-bg.webp, going-mobile-bg.webp, size-matters-bg.webp and sac-bg.webp (WebP, about
1600 px wide). Those would be screenshots from the games, which are copyrighted, so they are not part of this
repository. Without them the cards use a colour gradient. rac1us-bg.webp (the
NTSC-U card) falls back to rac1-bg.webp mirrored until it is added.
The images are read from a folder, set by IMAGE_DIR (default public/img, which is git-ignored), on every
request. Drop a file in and it is used at once, with no rebuild or restart; a missing one leaves the card's
gradient (never a broken picture). Only those eight names are ever served. Resized copies are cached for a day, so a replaced image can take up to a day to show (or restart
the service after clearing the cache volume).
Add an entry to PROJECTS in src/lib/projects.ts. If the project publishes progress, add a loader and a
snapshot to LOADERS and FALLBACK in src/lib/progress/index.ts; a title without one is shown as "Not started". maintainers (GitHub user names) puts
"maintained by" with their pictures on the card. Another project for a game that is already listed can be named
in the FAQ without a card of its own: add it to ALSO_WORKED_ON.
phase: "research" marks a project that is still mapping its game (shown on its card and in the FAQ; its
progress is tracked as usual). contributing and guide link the project's own contributing guide and best
introduction for newcomers; they feed the "Contribute" buttons and the "Project guides" under Resources.
# 1. put this repository on the server and build the image
podman build -t localhost/openrac:latest .
# 2. install the unit (rootless shown; rootful: /etc/containers/systemd/)
mkdir -p ~/.config/containers/systemd
cp deploy/openrac.container ~/.config/containers/systemd/
# 3. start it
systemctl --user daemon-reload
systemctl --user start openrac.service
loginctl enable-linger "$USER" # once, so it starts at boot without a login
# 4. card backdrops: copy your images into the folder the unit mounts (no restart needed)
cp rac1-bg.webp rac1us-bg.webp gc-bg.webp uya-bg.webp deadlocked-bg.webp going-mobile-bg.webp size-matters-bg.webp sac-bg.webp ~/openrac-img/The container listens on 127.0.0.1:3000; put your reverse proxy in front of it. It runs as a non-root user with
a read-only filesystem and all capabilities dropped; only the page cache (/app/.next/cache) is a writable
volume. The backdrop folder ~/openrac-img (created by the unit) is mounted read-only at /data/img; change the
host path in the Volume= line if you keep the images elsewhere. A health check polls /healthz. Edit SITE_URL in the unit to match your domain.
To update: git pull && podman build -t localhost/openrac:latest . && systemctl --user restart openrac.service.
OpenRAC is an independent fan project, not affiliated with or endorsed by the owners or publishers of the games. "Ratchet & Clank" and related names are trademarks of their owners and are used only to identify the games the linked projects study. This repository contains no game assets, code or binaries.
