Skip to content

Repository files navigation

OpenRAC: community decompilation projects of the Ratchet & Clank series

OpenRAC website

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.

How it works

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.

How progress is counted

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) of OpenRAC/rac1-decomp.
  • Ratchet & Clank (NTSC-U): report.json (objdiff report) on the progress branch of lombyte-project/Lombyte, which the project's own workflow publishes and ByteMatch reads. Shown beside the PAL card.
  • Going Commando: the committed progress/report.json on the master branch of OpenRAC/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) of OpenRAC/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) of OpenRAC/rac4-decomp.
  • Going Mobile: the verified method count in the README.md of Clank700/going-mobile-decomp, applied to the size of the reconstructed source.
  • Size Matters (PS2, NTSC-U): progress/status.json of OpenRAC/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 its tools/bytematch_estimate.py and the figure ByteMatch shows.
  • Secret Agent Clank (PS2, NTSC-U): progress/report.json of OpenRAC/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.

For scripts, search engines and AI

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

/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/submit redirects 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

/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.

GitHub access

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):

  1. github.com/organizations/OpenRAC/settings/apps/new: name OpenRAC website, homepage https://openrac.dev, Webhook: off. Repository permissions: Contents: read, Metadata: read, Discussions: read. Nothing else. "Only on this account".
  2. Create it, note the App ID, then Generate a private key (a .pem downloads).
  3. Install App → OpenRAC → All repositories (or the public ones the site reads).
  4. On the server: podman secret create openrac-github-app ~/openrac-github-app.pem, delete the .pem, put GITHUB_APP_ID=<id> in ~/.config/openrac/openrac.env, uncomment the three lines in deploy/openrac.container, then systemctl daemon-reload && systemctl restart openrac.service.

podman logs shows github_app_token_failed (with GitHub's status) if the app is refused.

Credits

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.

Develop

npm install
npm run dev        # http://localhost:3000
npm test           # unit tests (progress parsers, mods, machine-readable files)
npm run lint
npm run build

Where things are

src/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.

Card backdrops

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).

Adding a title

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.

Deploy with Podman and Quadlet

# 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.

Legal

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.

Releases

Packages

Contributors

Languages