diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e85902a47..7acb100ce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -102,7 +102,7 @@ handheld launchers, `bwrap` (bubblewrap) for the probe sandbox, and a Python 3.8 with pyte (`python3.8 -m pip install "pyte==0.8.2"`) for the full screen. CI has all three. `profile_sync.py` compares the branch with this repository's `main`, and -fetches it in a fork's clone. A profile you only edit is not held to +fetches it in a fork's clone. An edited profile is not held to `--strict`: its older refs are reviewed by hand. The full pipeline is not needed for a contribution: it rebuilds every pack diff --git a/README.md b/README.md index 2001b43eb..5a5406b28 100644 --- a/README.md +++ b/README.md @@ -5,186 +5,82 @@

-

- Site -

+

The BIOS files emulators need, put in the right folder and checked.

-BIOS and firmware files for AmberELEC, Batocera, BizHawk, EmuDeck, EmuELEC, KNULLI, Lakka, MiSTer FPGA, MinUI, MyMinUI, NextUI, ROCKNIX, Recalbox, RetroArch, RetroBat, RetroDECK, RetroPie, and RomM. +

Website · Get the files · A game does not start · Questions

-A pack holds the files its emulators read, as their source code names them, and leaves out what the emulators install themselves. +Some consoles need a small program, the **BIOS**, to start their games: PlayStation 1 and 2, Saturn, Neo Geo, Dreamcast and more. RetroBIOS installs the BIOS and firmware files for AmberELEC, Batocera, BizHawk, EmuDeck, EmuELEC, KNULLI, Lakka, MiSTer FPGA, MinUI, MyMinUI, NextUI, ROCKNIX, Recalbox, RetroArch, RetroBat, RetroDECK, RetroPie, and RomM, checked the way each one checks them. -## Quick install +## Install in one line -Copy one command into your terminal: +**Windows**: open the Start menu, type **PowerShell** and open it. Paste this line (right-click in the window) and press Enter. + +```powershell +irm https://abdess.github.io/retrobios/i.ps1 | iex +``` + +**Linux, macOS, Steam Deck, Android (Termux)**: open a terminal, paste this line and press Enter. ```bash -# Linux / macOS / Steam Deck curl -fsSL https://abdess.github.io/retrobios/i | sh - -# Windows (PowerShell) -irm https://abdess.github.io/retrobios/i.ps1 | iex - -# Android (Termux: it installs Python and asks for storage access) -curl -fsSL https://abdess.github.io/retrobios/i | sh - -# SD card mounted on a PC: a muOS, KNULLI, ROCKNIX, Lakka, MiSTer, Onion, spruceOS or MinUI card -# is found by itself. For another card, --dest is its BIOS folder -# (RetroArch on Switch: retroarch/cores/system, on Android: RetroArch/system) -curl -fsSL https://abdess.github.io/retrobios/i | sh -s -- --platform retroarch --dest /path/to/sdcard/retroarch/cores/system - -# Options in PowerShell: anything after | iex goes to iex, so the script runs as a block -&([scriptblock]::Create((irm https://abdess.github.io/retrobios/i.ps1))) --check - -# With Python 3.8 or newer: the same installer as a package (or pipx run retrobios) -uvx retrobios ``` +**With Python 3.8 or newer**: `uvx retrobios` runs the same installer, and so does `pipx run retrobios`. + +**A handheld, an SD card, or not sure?** [Pick the device](https://abdess.github.io/retrobios/which-pack/): its page gives the folder and the command. A muOS, Onion, spruceOS, MinUI, KNULLI, ROCKNIX, Lakka or MiSTer SD card plugged into the computer is found by itself. + ![Recording of the one-line command in a terminal. The installer finds an ArkOS SD card with 6 games, plans 43 BIOS files (15.1 MB) for them, installs them and shows the summary.](docs_assets/demo/install.gif) -The script opens a full-screen installer, driven with the arrow keys and Enter, or with a controller on a handheld. It finds your setup and its BIOS folder, downloads only the missing files and checks each one. It can also copy the BIOS files from your old SD card. -Every option, and what the installer detects and writes, is on the [installer page](https://abdess.github.io/retrobios/wiki/installer/#passing-options). +The installer finds the setup and its BIOS folder, installs the files it needs (only what the games need when it finds them on the card) and checks each one. Its screen installs everything, or fewer under **Choose systems**. Arrow keys and Enter drive it, or a controller on a handheld. It sends nothing back ([what is counted](https://abdess.github.io/retrobios/wiki/privacy/)). Options go after the line in the form the [installer page](https://abdess.github.io/retrobios/wiki/installer/#passing-options) gives. -First time? Follow the [first install, step by step](https://abdess.github.io/retrobios/wiki/first-install/). A game does not start: [what to check](https://abdess.github.io/retrobios/wiki/troubleshooting/). Other questions: the [FAQ](https://abdess.github.io/retrobios/wiki/faq/). +First time? [The first install, step by step](https://abdess.github.io/retrobios/wiki/first-install/). A game does not start: [what to check](https://abdess.github.io/retrobios/wiki/troubleshooting/). Other questions: [FAQ](https://abdess.github.io/retrobios/wiki/faq/). -## Download BIOS packs +## Or download a ZIP -A pack holds its platform's own BIOS list plus the files its emulator cores load. What no pack carries yet is in the [gap analysis](https://abdess.github.io/retrobios/gaps/). Pick your platform, download the ZIP, extract to the BIOS path. Each Download link is a page that keeps its address from one release to the next. The installer above does the same file by file: its screen installs everything, or fewer under **Choose systems**, and `--system`, `--core`, `--region` and `--target` make the same choice without questions. For a bare minimum, build your own pack below. +The Files column counts what a pack holds once unzipped. -A pack over 2 GB comes in several parts (`Pack.part1of2.zip`, `Pack.part2of2.zip`), and every part is needed. Each part is an ordinary ZIP: extract them all into the same folder. - -Every release ships `SHA256SUMS.txt` and a detached signature of it, checkable against `allowed_signers` in this repository: [verifying a release](https://abdess.github.io/retrobios/wiki/release-process/#verifying-a-release). - -The Files column counts what a pack holds once extracted, the figure a file manager shows for the folder. It differs from one platform to the next because a pack carries only what that platform's emulators load. The size is what the files occupy once extracted, and the ZIP itself downloads smaller. - -| Platform | Files | Extracted size | Extract to | Download | -|----------|------:|---------------:|-----------|----------| -| AmberELEC | - | - | `/storage/roms/` | [Use the command](https://abdess.github.io/retrobios/get/amberelec/) | +| Setup | Files | Size | Unzip into | Download | +|-------|------:|-----:|------------|----------| | Batocera | 12,810 | 7.5 GB | `/userdata/bios/` | [Download](https://abdess.github.io/retrobios/get/batocera/) | -| BizHawk | - | - | `Firmware/` | [Use the command](https://abdess.github.io/retrobios/get/bizhawk/) | | EmuDeck | 620 | 3.2 GB | `~/Emulation/bios/` | [Download](https://abdess.github.io/retrobios/get/emudeck/) | -| EmuELEC | - | - | `/storage/roms/` | [Use the command](https://abdess.github.io/retrobios/get/emuelec/) | -| KNULLI | - | - | `/userdata/bios/` | [Use the command](https://abdess.github.io/retrobios/get/knulli/) | -| Lakka | - | - | `/storage/system/` | [Use the command](https://abdess.github.io/retrobios/get/lakka/) | | MiSTer FPGA | 83 | 29 MB | `/media/fat/games/` | [Download](https://abdess.github.io/retrobios/get/misterfpga/) | -| MinUI | - | - | `/` | [Use the command](https://abdess.github.io/retrobios/get/minui/) | -| MyMinUI | - | - | `/` | [Use the command](https://abdess.github.io/retrobios/get/myminui/) | -| NextUI | - | - | `/` | [Use the command](https://abdess.github.io/retrobios/get/nextui/) | -| ROCKNIX | - | - | `/storage/roms/bios/` | [Use the command](https://abdess.github.io/retrobios/get/rocknix/) | -| Recalbox | - | - | `/recalbox/share/bios/` | [Use the command](https://abdess.github.io/retrobios/get/recalbox/) | | RetroArch | 8,504 | 6.0 GB | `system/` | [Download](https://abdess.github.io/retrobios/get/retroarch/) | | RetroBat | 12,399 | 7.9 GB | `bios/` | [Download](https://abdess.github.io/retrobios/get/retrobat/) | -| RetroDECK | - | - | `~/retrodeck/` | [Use the command](https://abdess.github.io/retrobios/get/retrodeck/) | -| RetroPie | - | - | `~/RetroPie/BIOS/` | [Use the command](https://abdess.github.io/retrobios/get/retropie/) | | RomM | 1,087 | 1.5 GB | `library/bios/` | [Download](https://abdess.github.io/retrobios/get/romm/) | -ZIPs are made for the setups most people download. The others read "Use the command": the installer above installs every file for them and checks each one, and `--dry-run` shows what it would install ([why no ZIP](https://abdess.github.io/retrobios/wiki/faq/#why-is-there-no-zip-for-my-setup)). +ZIPs are made for the setups most people download. The others install with the line above, and each page gives the command: [AmberELEC](https://abdess.github.io/retrobios/get/amberelec/), [BizHawk](https://abdess.github.io/retrobios/get/bizhawk/), [EmuELEC](https://abdess.github.io/retrobios/get/emuelec/), [KNULLI](https://abdess.github.io/retrobios/get/knulli/), [Lakka](https://abdess.github.io/retrobios/get/lakka/), [MinUI](https://abdess.github.io/retrobios/get/minui/), [MyMinUI](https://abdess.github.io/retrobios/get/myminui/), [NextUI](https://abdess.github.io/retrobios/get/nextui/), [ROCKNIX](https://abdess.github.io/retrobios/get/rocknix/), [Recalbox](https://abdess.github.io/retrobios/get/recalbox/), [RetroDECK](https://abdess.github.io/retrobios/get/retrodeck/), [RetroPie](https://abdess.github.io/retrobios/get/retropie/). -## What's included +Unzip into the BIOS folder, files straight in it. A big pack comes in parts (`Pack.part1of2.zip`): download every part ([why some setups have no ZIP](https://abdess.github.io/retrobios/wiki/faq/#why-is-there-no-zip-for-my-setup)). Each release lists its files' SHA-256 with a signature ([verifying a release](https://abdess.github.io/retrobios/wiki/release-process/#verifying-a-release)). -BIOS, firmware, and system files for consoles from Atari to PlayStation 3. -These are the files an emulator loads from disk instead of carrying inside itself. Some are required to boot a system, others improve accuracy or unlock a feature, and the packs carry both. +## Help -Each file is checked the way your platform checks it. Most compare a checksum, the fingerprint of a file's contents, which catches a corrupt or unexpected copy. RetroArch, Lakka and RetroPie check that the file is present under its name without reading its contents (`path_is_valid` in RetroArch's `core_info.c`), and MinUI, NextUI and MyMinUI hand each core its folder without opening a file in it: the Coverage table says which applies to you. Independently of that, the collection records five fingerprints per file, and wherever an emulator's code states an expected size or hash, that value is read from its source and rechecked here. +- "BIOS missing" or a game does not start: [what to check](https://abdess.github.io/retrobios/wiki/troubleshooting/) +- Have a file? [Check it by its hash](https://abdess.github.io/retrobios/files/) +- Every console and the files it needs: [systems](https://abdess.github.io/retrobios/systems/) +- Asking an AI assistant: it reads the site best from [llms.txt](https://abdess.github.io/retrobios/llms.txt) -- **1,087 files** the platforms' emulators load are still to be found, and 138 more the collection does not hold and does not serve by name (retail data, per-user keys, user-filled slots), each with its reason. Both are named in the [gap analysis](https://abdess.github.io/retrobios/gaps/) -- **18 platforms** supported with platform-specific verification -- **623 emulators** profiled from source (RetroArch cores + standalone) -- **532 systems** handled by those emulators (NES, SNES, PlayStation, Saturn, Dreamcast, ...) -- **19,947 files in the collection**, each with its SHA1, MD5, SHA256, CRC32 and Adler-32 fingerprints: 5,744 system files, 2,975 arcade ROM sets, 11,228 game and engine data files. That is every platform and emulator together, so no pack holds them all: each carries what its own emulators load, counted in the download table -- **566 of 5,744 system files** matched to dump-preservation catalogs (No-Intro, Redump, TOSEC). Arcade sets and engine data fall outside what those catalogs index -- **15.8 GB** for the whole collection +## What makes it different -## Supported systems +- **623 emulators profiled from their source code**: each file an emulator loads, its hash and the line of code that reads it +- **18 setups**, each checked its own way: MD5 for Batocera and Recalbox, the file name for RetroArch, as their own code does +- **532 systems**, 19,947 files in the collection, [what is still missing](https://abdess.github.io/retrobios/gaps/) named file by file +- Public data: [JSON, CSV and SQLite](https://abdess.github.io/retrobios/data/), MIT licensed -NES, SNES, Nintendo 64, GameCube, Wii, Game Boy, Game Boy Advance, Nintendo DS, Nintendo 3DS, Switch, PlayStation, PlayStation 2, PlayStation 3, PSP, PS Vita, Mega Drive, Saturn, Dreamcast, Game Gear, Master System, Neo Geo, Atari 2600, Atari 7800, Atari Lynx, Atari ST, MSX, PC Engine, TurboGrafx-16, ColecoVision, Intellivision, Commodore 64, Amiga, ZX Spectrum, Arcade (MAME), and 498+ more. - -Full list with per-file details: **[https://abdess.github.io/retrobios/](https://abdess.github.io/retrobios/)** - -## Coverage - -| Platform | On its BIOS list | Files its emulators load | Checked by | -|----------|-----------------:|-------------------------:|------------| -| AmberELEC | 414/434 | 4,754/4,937 | MD5 | -| Batocera | 353/353 | 14,171/15,291 | MD5 | -| BizHawk | 118/118 | - | SHA-1 | -| EmuDeck | 168/168 | 8,426/8,528 | MD5 | -| EmuELEC | 543/572 | 4,788/10,217 | MD5 | -| KNULLI | 290/290 | 9,126/15,350 | MD5 | -| Lakka | 532/532 | 7,909/7,994 | name only | -| MiSTer FPGA | 81/81 | - | MD5 | -| MinUI | 0/0 | 78/79 | name only | -| MyMinUI | 0/0 | 356/367 | name only | -| NextUI | 0/0 | 343/350 | name only | -| ROCKNIX | 38/38 | 7,427/9,139 | MD5 | -| Recalbox | 351/351 | 3,125/3,344 | MD5 | -| RetroArch | 526/526 | 7,918/7,985 | name only | -| RetroBat | 348/348 | 5,135/9,659 | MD5 | -| RetroDECK | 2,007/2,008 | 6,705/6,992 | MD5 | -| RetroPie | 532/532 | 8,117/12,771 | name only | -| RomM | 383/383 | 83/874 | size, then any hash | - -Each fraction is what the pack has over what is needed, counting required and optional files alike since both ship. The first column is the BIOS list the platform publishes. The second counts files its emulators load that this list never mentions, found by reading their source code, and it is routinely several times larger. A short fraction means files are still missing, and they are named in the [gap analysis](https://abdess.github.io/retrobios/gaps/). -That second number is a floor, not a ceiling: an emulator that accepts any file handed to it names none in its code, so nothing there can be counted. -Checked by is the test your platform runs on its own, replicated here from its source code, so the result matches what you would see in the frontend ([how each one works](https://abdess.github.io/retrobios/wiki/verification-modes/)). - -## Build your own pack +
+For developers: build a pack Packs are built from a clone, and the clone carries the collection: its checkout alone is over 7.7 GB. `git clone --depth 1 https://github.com/Abdess/retrobios.git` leaves the history out. Files kept as release assets are downloaded when a pack needs them. Then generate packs for any platform, emulator, or system: ```bash -# The pack of a platform, as released python scripts/generate_pack.py --platform retroarch --output-dir dist/ -python scripts/generate_pack.py --platform batocera --output-dir dist/ - -# Single emulator or system python scripts/generate_pack.py --emulator dolphin -python scripts/generate_pack.py --system sony-playstation-2 - -# One region, best first, one file per system and region -python scripts/generate_pack.py --platform retroarch --region us,eu,jp -python scripts/generate_pack.py --platform retroarch --region us --one-per-slot - -# Firmware only: the game data a list or a core names is left out, each file named -python scripts/generate_pack.py --platform emuelec --no-game-data - -# The bare minimum: only the files each core needs to start python scripts/generate_pack.py --platform batocera --required-only - -# List available emulators and systems -python scripts/generate_pack.py --list-emulators -python scripts/generate_pack.py --list-systems - -# Coverage of this repository's collection per platform, emulator or system -# (it reads database.json and bios/: for your own BIOS folder, run the installer with --check) -python scripts/verify.py --all python scripts/verify.py --platform batocera -python scripts/verify.py --emulator flycast -python scripts/verify.py --platform retroarch --verbose # emulator ground truth ``` -Requires Python 3.9 or newer and `pyyaml`. The one-line installer alone runs on Python 3.8. +Requires Python 3.9 or newer and `pyyaml`. The one-line installer alone runs on Python 3.8. Every tool and option: [tools](https://abdess.github.io/retrobios/wiki/tools/). How the lists are built: [architecture](https://abdess.github.io/retrobios/wiki/architecture/). -## Documentation site - -The [documentation site](https://abdess.github.io/retrobios/) provides: - -- **Per-platform pages** with file-by-file verification status and hashes -- **Per-emulator profiles** with source code references for every file -- **Per-system pages** showing which emulators and platforms cover each console -- **Gap analysis** identifying missing files and undeclared core requirements -- **Cross-reference** mapping files across 18 platforms and 623 emulators -- **Versioned data access** through JSON, CSV and SQLite exports with published SHA-256 checksums - -## How it works - -A platform's BIOS list and an emulator's code are maintained separately. Each list is compared with the emulator source code, file by file where a profile exists, and where the two differ the code decides. - -Hashes document what emulator code loads and accepts, not dump provenance. That boundary, and how it relates to preservation catalogs such as No-Intro, is drawn in the [technical questions](https://abdess.github.io/retrobios/wiki/technical-faq/#are-these-files-verified-against-original-hardware-dumps). - -1. **Read emulator source code**: trace every file the code loads, its expected hash and size -2. **Cross-reference with platforms**: match against what each platform declares -3. **Build packs**: include baseline files plus what each platform's cores need -4. **Verify**: run platform-native checks and emulator-level validation +
## Contributors @@ -199,7 +95,7 @@ Hashes document what emulator code loads and accepts, not dump provenance. That ## Community tools -- [BIOS Preservation Tool](https://github.com/monster-penguin/BIOS-Preservation-Tool) by [monster-penguin](https://github.com/monster-penguin) - scan, verify, and stage your own BIOS collection using RetroBIOS hash metadata +- [BIOS Preservation Tool](https://github.com/monster-penguin/BIOS-Preservation-Tool) by [monster-penguin](https://github.com/monster-penguin) - scans, verifies and stages a BIOS collection using RetroBIOS hash metadata ## Contributing @@ -211,4 +107,4 @@ The scripts and tooling are released under the [MIT License](LICENSE). The BIOS and firmware files are not covered by that license: they are third-party system software, preserved and provided for personal backup, archival, and interoperability with emulation software. [NOTICE](NOTICE) sets out their status and how to ask for a file to be removed. The reasoning, and where it is weakest, is in [the project's legal position](https://abdess.github.io/retrobios/wiki/legal/). -*Auto-generated on 2026-11-06T23:09:06Z* +*Auto-generated on 2026-11-09T06:27:53Z* diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..10667993e --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,27 @@ +# Security policy + +## Scope + +- The one-line installer: `install.sh`, `install.ps1` and the `install.py` they download. +- The packs, their manifests under `install/` and the checksums each release publishes. +- The website, its scripts and the data it serves under `api/`. + +## Reporting a vulnerability + +Report it privately from the repository's **Security** tab, with **Report a vulnerability**. A public issue is the wrong place for it: the details stay private until a fix is out. + +A useful report names the file or the page, the steps that show the problem, and what an attacker gains. + +## Supported versions + +The installer and the site served from `main`, and the latest release. Older releases are removed when a new one is published. + +## How downloads are checked + +- `install.sh` and `install.ps1` download `install.py` from a fixed commit and refuse it unless its SHA-256 matches the one they carry. +- The installer checks every file against the hash its manifest records before writing it. +- Each release lists the SHA-256 of its files in `SHA256SUMS.txt`, signed with the key in `allowed_signers`: [verifying a release](https://abdess.github.io/retrobios/wiki/release-process/#verifying-a-release). + +## Not a security issue + +A file with an unexpected hash, a missing file or a takedown request: [open an issue](https://github.com/Abdess/retrobios/issues/new) with the file's path or hash. diff --git a/docs_assets/demo/demo.json b/docs_assets/demo/demo.json index 4c62cb74c..f551f79c2 100644 --- a/docs_assets/demo/demo.json +++ b/docs_assets/demo/demo.json @@ -1,9 +1,23 @@ { - "width": 800, - "height": 460, - "setup": "ArkOS", - "games": 6, - "systems": 6, - "files": 43, - "size": "15.1 MB" + "default": { + "width": 800, + "height": 460, + "setup": "ArkOS", + "games": 6, + "systems": 6, + "files": 43, + "size": "15.1 MB", + "alt": "Recording of the one-line command in a terminal. The installer finds an ArkOS SD card with 6 games, plans 43 BIOS files (15.1 MB) for them, installs them and shows the summary." + }, + "handheld": { + "width": 640, + "height": 480, + "setup": "ArkOS", + "games": 6, + "systems": 6, + "files": 43, + "size": "15.1 MB", + "pad": "gptokeyb", + "alt": "Recording of the full-screen installer on the 640 by 480 screen of a handheld, started from the Tools menu of ArkOS. It finds the 6 games on the card, plans 43 BIOS files (15.1 MB) for them, installs them and shows the summary. The A button chooses, and the bottom line names the buttons." + } } diff --git a/docs_assets/demo/install-handheld.mp4 b/docs_assets/demo/install-handheld.mp4 new file mode 100644 index 000000000..7128c36cc Binary files /dev/null and b/docs_assets/demo/install-handheld.mp4 differ diff --git a/docs_assets/demo/install-handheld.png b/docs_assets/demo/install-handheld.png new file mode 100644 index 000000000..0ed8def30 Binary files /dev/null and b/docs_assets/demo/install-handheld.png differ diff --git a/docs_assets/demo/install-handheld.tape b/docs_assets/demo/install-handheld.tape new file mode 100644 index 000000000..9bde16879 --- /dev/null +++ b/docs_assets/demo/install-handheld.tape @@ -0,0 +1,43 @@ +# The installer demo of the "On the device" tab: the full-screen interface +# on ArkOS, at the 640x480 screen of an R36S, as the Tools menu launcher +# starts it. Run scripts/make_demo.py --variant handheld, which builds the +# card and ArkOS's root, serves the repository on loopback, starts VHS on +# this file from the repository root and encodes what it writes. Enter is +# what gptokeyb sends for A (ports/shared/retrobios.gptk). + +Output tmp/demo/recorded-handheld.mp4 + +Set Shell "bash" +Set FontFamily "DejaVu Sans Mono" +Set FontSize 16 +Set LineHeight 1.15 +Set Width 640 +Set Height 480 +Set Padding 8 +Set Framerate 25 +Set TypingSpeed 35ms +Set CursorBlink false +Set Theme { "name": "RetroBIOS", "background": "#12131c", "foreground": "#e6e6f0", "cursor": "#aebcff", "selection": "#3a3d52", "black": "#12131c", "red": "#ef9a9a", "green": "#a5d6a7", "yellow": "#ffcc80", "blue": "#90caf9", "magenta": "#aebcff", "cyan": "#aebcff", "white": "#cfd8dc", "brightBlack": "#7c82a3", "brightRed": "#ef9a9a", "brightGreen": "#a5d6a7", "brightYellow": "#ffcc80", "brightBlue": "#90caf9", "brightMagenta": "#c9d2ff", "brightCyan": "#c9d2ff", "brightWhite": "#e6e6f0" } + +# ArkOS's root, the card at /roms, the interface started. +Hide +Type 'exec "$RETROBIOS_DEMO_SESSION"' +Enter +Wait+Screen@60s /A Continue/ +Sleep 300ms +Show + +# The first screen: the system found, its BIOS folder. +Sleep 300ms +Screenshot tmp/demo/poster-handheld.png +Sleep 2500ms +Enter + +# A: the plan, only the files the games on the card need. +Wait+Screen@60s /A Install/ +Sleep 4500ms +Enter + +# A: install. The progress, then the summary. +Wait+Screen@60s /RetroBIOS: Done/ +Sleep 4500ms diff --git a/docs_assets/demo/install-handheld.webm b/docs_assets/demo/install-handheld.webm new file mode 100644 index 000000000..6614dd89c Binary files /dev/null and b/docs_assets/demo/install-handheld.webm differ diff --git a/docs_assets/demo/install.gif b/docs_assets/demo/install.gif index 72894041f..6398d217d 100644 Binary files a/docs_assets/demo/install.gif and b/docs_assets/demo/install.gif differ diff --git a/docs_assets/demo/install.mp4 b/docs_assets/demo/install.mp4 index 8b17f70e6..20dd11de6 100644 Binary files a/docs_assets/demo/install.mp4 and b/docs_assets/demo/install.mp4 differ diff --git a/docs_assets/demo/install.webm b/docs_assets/demo/install.webm index 95c1bf534..f343986cc 100644 Binary files a/docs_assets/demo/install.webm and b/docs_assets/demo/install.webm differ diff --git a/docs_assets/og/setup.png b/docs_assets/og/setup.png index c7eace936..4148b13df 100644 Binary files a/docs_assets/og/setup.png and b/docs_assets/og/setup.png differ diff --git a/emulators/fmsx.yml b/emulators/fmsx.yml index ea64e6953..ab89b3dd1 100644 --- a/emulators/fmsx.yml +++ b/emulators/fmsx.yml @@ -54,8 +54,8 @@ notes: | Place all ROM files directly in the RetroArch system directory. No subdirectory needed. The core does chdir() to system_dir before loading. - The default model is MSX2+, which needs MSX2P.ROM and MSX2PEXT.ROM. If you only - play cartridge ROMs, these two files are sufficient. For disk games (.dsk), also + The default model is MSX2+, which needs MSX2P.ROM and MSX2PEXT.ROM. For cartridge + ROMs alone, these two files are sufficient. For disk games (.dsk), also add DISK.ROM and enable "Simulate DiskROM" in core options. KANJI.ROM and FMPAC.ROM are loaded automatically when present, no option needed. diff --git a/platforms/_guides.yml b/platforms/_guides.yml index 02505e831..7e7a2adb4 100644 --- a/platforms/_guides.yml +++ b/platforms/_guides.yml @@ -28,10 +28,10 @@ install_base: https://abdess.github.io/retrobios # (place_save_entries), and retrobios-backup beside the folder written to. trust_items: - It checks each file before saving it. -- It writes in your BIOS folder. For some emulators it also adds files to your save folder. +- It writes in the BIOS folder. For some emulators it also adds files to the save folder. - It never changes or deletes a game or a save. - >- - It keeps any file it replaces in a `retrobios-backup` folder, next to your BIOS folder. + It keeps any file it replaces in a `retrobios-backup` folder, next to the BIOS folder. `--restore` puts it back. # Order of the groups on the picker, in the navigation and on the home page. @@ -57,7 +57,7 @@ device_groups: anchor: game-systems handheld: label: Handhelds and TV boxes (Anbernic, Retroid, Miyoo) - description: The system your handheld or TV box starts. + description: The system a handheld or TV box starts. anchor: handhelds also_runs: - setup: Android (Retroid Pocket, AYN Odin and others) @@ -88,7 +88,7 @@ device_groups: anchor: fpga server: label: Self-hosted game library - description: A RomM server. It plays games in your web browser. + description: A RomM server. It plays games in the web browser. anchor: self-hosted # Ways to run the installer: the tab label, how to open a terminal there, and @@ -97,21 +97,25 @@ terminals: windows: label: Windows how: >- - Open the Start menu. Type **PowerShell** and open it. Paste the line. Press Enter. + Open Start. Type **PowerShell**, press Enter. Click Copy. Right-click to paste. Press + Enter. shell: powershell macos: label: macOS how: >- - Open **Terminal**, in Applications, then Utilities. Paste the line. Press Return. + Press Cmd+Space. Type **Terminal**, press Return. Click Copy. Press Cmd+V. Press + Return. shell: sh linux: label: Linux - how: Open a terminal. Paste the line. Press Enter. + how: >- + Open a terminal, often with Ctrl+Alt+T. Click Copy. Press Ctrl+Shift+V. Press Enter. shell: sh steamdeck: label: Steam Deck how: >- - Switch to Desktop Mode. Open **Konsole**. Paste with Ctrl+Shift+V. Press Enter. + Hold power, pick **Switch to Desktop**. Open **Konsole**. Click Copy. Press + Ctrl+Shift+V. Press Enter. shell: sh android: label: Android (Termux) @@ -128,7 +132,7 @@ terminals: server: label: On the server how: >- - Open a terminal on the machine that holds your RomM library. Put the path of its + Open a terminal on the machine that holds the RomM library. Put the path of its `bios` folder after `--dest`. shell: sh @@ -283,18 +287,18 @@ guides: pack_manual: | Option B: Manual (PC) --------------------- - 1. Find your RetroArch system directory: + 1. Find the RetroArch system directory: - RetroArch > Settings > Directory > System/BIOS - Default: retroarch/system/ - 2. Extract all files from this archive directly into your system directory + 2. Extract all files from this archive directly into the system directory 3. Overwrite if asked Option C: Manual (handheld / SD card) ------------------------------------- - 1. Connect your SD card to your PC + 1. Connect the SD card to a PC 2. Find the BIOS folder in the list below 3. Extract all files from this archive directly into that folder - 4. Eject SD card and reboot your device + 4. Eject the SD card and reboot the device Folders by device: {folders} @@ -314,9 +318,9 @@ guides: root@batocera.local`, password `linux`. Paste the line. Press Enter. folders: - where: On Batocera - - where: From Windows, over your home network + - where: From Windows, over the home network path: '`\\BATOCERA\share\bios\`' - - where: From a Mac or Linux, over your home network + - where: From a Mac or Linux, over the home network path: '`smb://batocera/share/bios/`' run: [device] download_hint: From a computer, use the network folder above. @@ -326,7 +330,7 @@ guides: Option B: Manual (network share) -------------------------------- - 1. On your PC, open the Batocera network share: + 1. On a PC, open the Batocera network share: - Windows: \\BATOCERA\share\bios\ - Mac/Linux: smb://batocera/share/bios/ 2. Extract all files from this archive directly into the share @@ -334,13 +338,13 @@ guides: Option C: Manual (SD card) -------------------------- - 1. Put the SD card in your PC + 1. Put the SD card in a PC 2. Open the bios folder at the root of the SHARE drive (Batocera itself names it /userdata/bios/) 3. Extract all files from this archive directly into that folder NOTE: Dreamcast flash memory is named dc_nvmem.bin - (if your setup asks for dc_flash.bin, same file). + (if the setup asks for dc_flash.bin, same file). logo_owner: Batocera logo_licence: repository licence MIT recalbox: @@ -351,24 +355,24 @@ guides: # a keyboard. SSH user root, password recalboxroot or the one set when flashing 10.0+. terminal: >- With a keyboard, press **Alt+F2**. From a computer, open a terminal over the network - with `ssh root@recalbox`, password `recalboxroot` or the one you set. Paste the line. + with `ssh root@recalbox`, password `recalboxroot` or the one set when flashing. Paste the line. Press Enter. folders: - where: On Recalbox - - where: From Windows, over your home network + - where: From Windows, over the home network path: '`\\RECALBOX\share\bios\`' run: [device] download_hint: From a computer, use the network folder above. pack_manual: | Option B: Manual (network share) -------------------------------- - 1. On your PC, open the Recalbox network share: + 1. On a PC, open the Recalbox network share: - Windows: \\RECALBOX\share\bios\ 2. Extract all files from this archive directly into the share Option C: Manual (SD card) -------------------------- - 1. Put the SD card in your PC + 1. Put the SD card in a PC 2. Open the bios folder at the root of the SHARE drive (Recalbox itself names it /recalbox/share/bios/) 3. Extract all files from this archive directly into that folder @@ -384,7 +388,7 @@ guides: path: '`C:\RetroBat\bios\`' run: [windows] notes: - - The command finds RetroBat wherever you installed it. + - The command finds RetroBat wherever it is installed. reference_notes: - >- RetroBat records its own folder each time it starts, and the installer reads it @@ -392,15 +396,15 @@ guides: pack_manual: | Option B: Manual ---------------- - 1. Open your RetroBat installation folder + 1. Open the RetroBat installation folder 2. Navigate to the bios\ subfolder (default: C:\RetroBat\bios\) - 3. Extract all files from this archive directly into your bios\ folder + 3. Extract all files from this archive directly into the bios\ folder 4. Overwrite if asked logo_owner: RetroBat logo_licence: repository states no licence emudeck: - summary: Installs your emulators and adds your games to Steam. + summary: Installs emulators and adds the games to Steam. folders: - where: Steam Deck and Linux # EmuDeck functions/helperFunctions.sh:89-99 (getSDPath, the card's mount point) @@ -414,7 +418,7 @@ guides: run: [steamdeck, linux, windows, macos] notes: - >- - The `bios` folder is inside the Emulation folder you chose in EmuDeck. + The `bios` folder is inside the Emulation folder chosen in EmuDeck. # emudeck-electron src/renderer/translations/en.json:416-418 (b06bfcf5): the # "Bios files checker". finish: >- @@ -440,7 +444,7 @@ guides: folders: - where: On Lakka # lakka.tv/doc/Accessing-Lakka-filesystem: Samba in Settings > Services, share System. - - where: From Windows, over your home network + - where: From Windows, over the home network path: '`\\LAKKA\System\`' run: [device] notes: @@ -463,7 +467,7 @@ guides: Option B: Via network share -------------------------- 1. On Lakka: Settings > Services > Samba Enable - 2. On your PC, open the System share: \\LAKKA\System\ + 2. On a PC, open the System share: \\LAKKA\System\ 3. Extract all files from this archive directly into that share Option C: Via SSH @@ -497,7 +501,7 @@ guides: logo_licence: repository licence GPL-3.0 romm: summary: >- - A game library on your own server. It plays games in the web browser. + A game library on a self-hosted server. It plays games in the web browser. folders: - where: In the RomM library path: '`bios/`, one subfolder per platform' @@ -506,7 +510,7 @@ guides: path: '`/bios/` for each platform' run: [server] notes: - - 'You can also add BIOS files in RomM''s web page.' + - 'BIOS files can also be added in RomM''s web page.' dest: /path/to/library/bios # RomM 5.4 places firmware by filesystem.structure.firmware in config.yml, # bios/{platform} by default, and suggests {platform}/bios for a library @@ -539,7 +543,7 @@ guides: run: [device] notes: - >- - You can also reach the folder from a computer, over your home network. + The folder is also reachable from a computer, over the home network. # rocknix.org/faqs and rocknix.org/play/add-games: SSH off by default, turned on in # Network Settings, user root, the password shown in System Settings > Security. terminal: >- @@ -561,7 +565,7 @@ guides: # AmberELEC 5a3882cb packages/network/samba/config/smb.conf:59-60 shares # /storage/roms as "roms". smbd runs unless samba.disabled exists # (system.d.opt/smbd.service:5). - - where: From Windows, over your home network + - where: From Windows, over the home network path: '`\\AmberELEC\roms\`' run: [device] # amberelec.org/guides/getting-to-know-amberelec.html: host AmberELEC, root, amberelec. @@ -584,7 +588,7 @@ guides: - where: On EmuELEC # EmuELEC wiki (35b92c78) Backup-and-Recovery-options.md:4 (\\EMUELEC, roms share) # and Bios.md (/storage/roms/bios). - - where: From Windows, over your home network + - where: From Windows, over the home network path: '`\\EMUELEC\roms\`' run: [device] # EmuELEC wiki How-to-SSH-into-EmuELEC.md:38-44: root, password emuelec. @@ -606,7 +610,7 @@ guides: - where: On KNULLI # knulli.org/play/add-games/network-transfer: \\KNULLI, its share folder, Samba # off by default. The share is /userdata, so bios is under it. - - where: From Windows, over your home network + - where: From Windows, over the home network path: '`\\KNULLI\share\bios\`' run: [device] notes: @@ -632,7 +636,7 @@ guides: - where: On the Raspberry Pi # RetroPie-Setup scriptmodules/supplementary/samba.sh:49-52 (46128cd2) shares # $home/RetroPie/BIOS as "bios", and docs/Transferring-Roms.md:29 names \\RETROPIE. - - where: From Windows, over your home network + - where: From Windows, over the home network path: '`\\RETROPIE\bios\`' run: [device] # RetroPie docs/FAQ.md:193 (F4 in EmulationStation, its game menu), 175f5b15. The computer route @@ -653,12 +657,12 @@ guides: pack_manual: | Option B: Via network share -------------------------- - 1. On your PC, open: \\RETROPIE\bios\ + 1. On a PC, open: \\RETROPIE\bios\ 2. Extract all files from this archive directly into that folder Option C: Via SSH ----------------- - 1. SSH into your Pi: ssh pi@retropie + 1. SSH into the Pi: ssh pi@retropie 2. Copy files to ~/RetroPie/BIOS/ NOTE: the BIOS folder is on the card's Linux partition, @@ -680,10 +684,10 @@ guides: pack_manual: | Option B: Manual ---------------- - 1. Open the folder you extracted BizHawk to, the one holding + 1. Open the folder BizHawk was extracted to, the one holding EmuHawk.exe (Windows) or EmuHawkMono.sh (Linux) 2. Navigate to its Firmware subfolder - 3. Extract all files from this archive directly into your Firmware folder + 3. Extract all files from this archive directly into the Firmware folder 4. In BizHawk: Config > Paths > Firmware should point to this folder logo_owner: TASVideos @@ -698,7 +702,7 @@ guides: path: '`/media/fat/games/`, one subfolder per core' # mister-devel.github.io/MkDocs_MiSTer/setup/games: run samba_on from the Scripts # menu, then \\MiSTer\sdcard\. - - where: From Windows, over your home network + - where: From Windows, over the home network path: '`\\MiSTer\sdcard\games\`' run: [device] # mister-devel.github.io/MkDocs_MiSTer/advanced/network: F9 for a Linux terminal, @@ -730,7 +734,7 @@ guides: - >- Each console has its own folder, named after the tag in its Roms folder. `Roms/Sony PlayStation (PS)/` uses `Bios/PS/`. - - The command makes each console's folder for you. + - The command makes each console's folder. on_card: true reference_notes: - >- @@ -755,7 +759,7 @@ guides: - >- Each console has its own folder, named after the tag in its Roms folder. `Roms/Sony PlayStation (PS)/` uses `Bios/PS/`. - - The command makes each console's folder for you. + - The command makes each console's folder. on_card: true reference_notes: - >- @@ -775,7 +779,7 @@ guides: - >- Each console has its own folder, named after the tag in its Roms folder. `Roms/Sony PlayStation (PS)/` uses `Bios/PS/`. - - The command makes each console's folder for you. + - The command makes each console's folder. on_card: true reference_notes: - >- diff --git a/scripts/generate_readme.py b/scripts/generate_readme.py index 80c380910..1bc61945b 100644 --- a/scripts/generate_readme.py +++ b/scripts/generate_readme.py @@ -476,17 +476,17 @@ def clone_line(db: dict) -> str: ) -def demo_facts() -> dict: - """What the installer demo shows, as make_demo.py measured it.""" - return json.loads((DEMO_DIR / "demo.json").read_text(encoding="utf-8")) +def demo_facts(variant: str = "default") -> dict: + """What an installer demo shows, as make_demo.py measured it: one entry + per variant (default, handheld).""" + facts = json.loads((DEMO_DIR / "demo.json").read_text(encoding="utf-8")) + return facts[variant] def demo_description(facts: dict | None = None) -> str: - """The demo in words, for a reader who cannot see it.""" - facts = facts or demo_facts() - return (f"Recording of the one-line command in a terminal. The installer finds an " - f"{facts['setup']} SD card with {facts['games']} games, plans {facts['files']} " - f"BIOS files ({facts['size']}) for them, installs them and shows the summary.") + """The demo in words, for a reader who cannot see it: the alt text + make_demo.py wrote from what it measured.""" + return str((facts or demo_facts())["alt"]) def _existing_contributor_block(readme_path: str = "README.md") -> list[str]: @@ -594,6 +594,15 @@ def generate_readme(db: dict, platforms_dir: str, db_path: str = "database.json" system_ids = system_index(profiles) + # The README is the repository's front page and its most read page: a + # visitor from a search lands here, often new to terminals. It says what + # the project does, gives the one line that installs, shows it, and leads + # on to the site, where every detail lives. The figures and the lists it + # once carried (coverage, collection, build commands) are the site's. + record = release_record.load_advertised(platforms_dir=platforms_dir) + extract_paths = _extract_cells(platforms_dir) + released = [name for name in sorted(coverages, key=lambda n: coverages[n]["platform"]) + if release_totals(name, record)[0]] lines = [ '

', " ", @@ -602,284 +611,121 @@ def generate_readme(db: dict, platforms_dir: str, db_path: str = "database.json" " ", "

", "", - '

', - ' ' - 'Site', + '

The BIOS files emulators need, put in the right folder and checked.

', + "", + '

' + f'Website · ' + f'Get the files · ' + f'A game does not start · ' + f'Questions' "

", "", - f"BIOS and firmware files for {_names_list(coverages)}.", + "Some consoles need a small program, the **BIOS**, to start their games: PlayStation 1" + " and 2, Saturn, Neo Geo, Dreamcast and more. RetroBIOS installs the BIOS and firmware" + f" files for {_names_list(coverages)}, checked the way each one checks them.", "", - "A pack holds the files its emulators read, as their source code names" - " them, and leaves out what the emulators install themselves.", + "## Install in one line", "", - "## Quick install", + "**Windows**: open the Start menu, type **PowerShell** and open it. Paste this line" + " (right-click in the window) and press Enter.", "", - "Copy one command into your terminal:", + "```powershell", + install_command("powershell"), + "```", + "", + "**Linux, macOS, Steam Deck, Android (Termux)**: open a terminal, paste this line" + " and press Enter.", "", "```bash", - "# Linux / macOS / Steam Deck", install_command("sh"), - "", - "# Windows (PowerShell)", - install_command("powershell"), - "", - "# Android (Termux: it installs Python and asks for storage access)", - install_command("sh"), - "", - "# SD card mounted on a PC: a muOS, KNULLI, ROCKNIX, Lakka, MiSTer, Onion, spruceOS or MinUI card", - "# is found by itself. For another card, --dest is its BIOS folder", - "# (RetroArch on Switch: retroarch/cores/system, on Android: RetroArch/system)", - install_command("sh", "--platform retroarch --dest /path/to/sdcard/retroarch/cores/system"), - "", - "# Options in PowerShell: anything after | iex goes to iex, so the script runs as a block", - install_command("powershell", "--check"), - "", - "# With Python 3.8 or newer: the same installer as a package (or pipx run retrobios)", - PACKAGE_COMMAND, "```", "", + f"**With Python 3.8 or newer**: `{PACKAGE_COMMAND}` runs the same installer, and so" + " does `pipx run retrobios`.", + "", + f"**A handheld, an SD card, or not sure?** [Pick the device]({SITE_URL}which-pack/):" + " its page gives the folder and the command. A muOS, Onion, spruceOS, MinUI, KNULLI," + " ROCKNIX, Lakka or MiSTer SD card plugged into the computer is found by itself.", + "", f"![{demo_description()}]({DEMO_GIF})", "", - "The script opens a full-screen installer, driven with the arrow keys and Enter, or with a" - " controller on a handheld. It finds your setup and its BIOS folder, downloads only the missing" - " files and checks each one. It can also copy the BIOS files from your old SD card.", - f"Every option, and what the installer detects and writes, is on the [installer page]({SITE_URL}wiki/installer/#passing-options).", + "The installer finds the setup and its BIOS folder, installs the files it needs (only" + " what the games need when it finds them on the card) and checks each one. Its screen" + " installs everything, or fewer under **" + _installer_words().TUI_SYSTEMS_ROW + "**." + " Arrow keys and Enter drive it, or a controller on a handheld. It sends nothing back" + f" ([what is counted]({SITE_URL}wiki/privacy/)). Options go after the line in the" + f" form the [installer page]({SITE_URL}wiki/installer/#passing-options) gives.", "", - f"First time? Follow the [first install, step by step]({SITE_URL}wiki/first-install/)." + f"First time? [The first install, step by step]({SITE_URL}wiki/first-install/)." f" A game does not start: [what to check]({SITE_URL}wiki/troubleshooting/)." - f" Other questions: the [FAQ]({SITE_URL}wiki/faq/).", + f" Other questions: [FAQ]({SITE_URL}wiki/faq/).", "", - "## Download BIOS packs", + "## Or download a ZIP", "", - f"A pack holds its platform's own BIOS list plus the files its emulator cores load. What no pack carries yet is in the [gap analysis]({SITE_URL}gaps/). Pick your platform, download the ZIP, extract to the BIOS path. Each Download link is a page that keeps its address from one release to the next. The installer above does the same file by file: its screen installs everything, or fewer under **" + _installer_words().TUI_SYSTEMS_ROW + "**, and `--system`, `--core`, `--region` and `--target` make the same choice without questions. For a bare minimum, build your own pack below.", - "", - "A pack over 2 GB comes in several parts (`Pack.part1of2.zip`," - " `Pack.part2of2.zip`), and every part is needed. Each part is an" - " ordinary ZIP: extract them all into the same folder.", - "", - "Every release ships `SHA256SUMS.txt` and a detached signature of it," - " checkable against `allowed_signers` in this repository:" - " [verifying a release]" - "(https://abdess.github.io/retrobios/wiki/release-process/" - "#verifying-a-release).", - "", - "The Files column counts what a pack holds once extracted, the figure a" - " file manager shows for the folder. It differs from one platform to" - " the next because a pack carries only what that platform's emulators" - " load. The size is what the files occupy once extracted, and the ZIP" - " itself downloads smaller.", + "The Files column counts what a pack holds once unzipped.", "", + "| Setup | Files | Size | Unzip into | Download |", + "|-------|------:|-----:|------------|----------|", ] - - # Where the pack itself is extracted, which is not always the BIOS folder: - # a pack whose entries already carry their own root (RetroDECK) extracts - # one level above it. - extract_paths = _extract_cells(platforms_dir) - - lines.extend( - download_table( - coverages, extract_paths, - release_record.load_advertised(platforms_dir=platforms_dir), - ) - ) - lines.extend(["", no_pack_line()]) - - lines.extend(_paragraphs(extract_notes(platforms_dir, released_only=True))) - - lines.extend( - [ - "", - "## What's included", - "", - "BIOS, firmware, and system files for consoles from Atari to PlayStation 3.", - "These are the files an emulator loads from disk instead of" - " carrying inside itself. Some are required to boot a system," - " others improve accuracy or unlock a feature, and the packs carry" - " both.", - "", - "Each file is checked the way your platform checks it. Most compare" - " a checksum, the fingerprint of a file's contents, which catches a" - " corrupt or unexpected copy. RetroArch, Lakka and RetroPie check" - " that the file is present under its name without reading its" - " contents (`path_is_valid` in RetroArch's `core_info.c`), and" - " MinUI, NextUI and MyMinUI hand each core its folder without" - " opening a file in it: the" - " Coverage table says which applies to you. Independently of that," - " the collection records five fingerprints per file, and wherever" - " an emulator's code states an expected size or hash, that value is" - " read from its source and rechecked here.", - "", - ( - f"- **{acquirable_total:,} files** the platforms' emulators load" - f" are still to be found, and {unsourceable_total:,} more the" - f" collection does not hold and does not serve by name (retail" - f" data, per-user keys, user-filled slots), each with its reason." - f" Both are named in the" - f" [gap analysis]({SITE_URL}gaps/)" - if missing_total - else "- **Nothing missing**: every file the platforms'" - " emulators load is in the collection" - ), - f"- **{len(coverages)} platforms** supported with platform-specific verification", - f"- **{emulator_count} emulators** profiled from source (RetroArch cores + standalone)", - f"- **{len(system_ids)} systems** handled by those emulators (NES, SNES, PlayStation, Saturn, Dreamcast, ...)", - collection_line(total_files, comp), - *_catalog_matched_line(db), - f"- **{format_size(total_size)}** for the whole collection", - "", - "## Supported systems", - "", - ] - ) - - # Show well-known systems for SEO, link to full list - well_known = [ - "NES", - "SNES", - "Nintendo 64", - "GameCube", - "Wii", - "Game Boy", - "Game Boy Advance", - "Nintendo DS", - "Nintendo 3DS", - "Switch", - "PlayStation", - "PlayStation 2", - "PlayStation 3", - "PSP", - "PS Vita", - "Mega Drive", - "Saturn", - "Dreamcast", - "Game Gear", - "Master System", - "Neo Geo", - "Atari 2600", - "Atari 7800", - "Atari Lynx", - "Atari ST", - "MSX", - "PC Engine", - "TurboGrafx-16", - "ColecoVision", - "Intellivision", - "Commodore 64", - "Amiga", - "ZX Spectrum", - "Arcade (MAME)", - ] - lines.extend( - [ - ", ".join(well_known) + f", and {len(system_ids) - len(well_known)}+ more.", - "", - f"Full list with per-file details: **[{SITE_URL}]({SITE_URL})**", - "", - "## Coverage", - "", - "| Platform | On its BIOS list | Files its emulators load | Checked by |", - "|----------|-----------------:|-------------------------:|------------|", - ] - ) - - for name, cov in sorted(coverages.items(), key=lambda x: x[1]["platform"]): - display = cov["platform"] - checked = check_label(cov["mode"], cov["config"].get("hash_rule")) - core_total = ( - cov["core_present"] + cov["core_missing"] + cov["core_unsourceable"] - ) - core_cell = f"{cov['core_present']:,}/{core_total:,}" if core_total else "-" + for name in released: + files, size = release_totals(name, record) + display = coverages[name]["platform"] lines.append( - f"| {display} | {cov['present']:,}/{cov['total']:,} |" - f" {core_cell} | {checked} |" + f"| {display} | {files:,} | {format_size(size) if size else '-'} |" + f" {extract_paths.get(display, '')} |" + f" {download_links(name, record, 'Download', site=SITE_URL)} |" ) - - lines.extend( - [ - "", - "Each fraction is what the pack has over what is needed, counting" - " required and optional files alike since both ship. The first" - " column is the BIOS list the platform publishes. The second counts" - " files its emulators load that this list never mentions, found by" - " reading their source code, and it is routinely several times" - " larger. A short fraction means files are still missing, and they" - " are named in the" - f" [gap analysis]({SITE_URL}gaps/).", - "That second number is a floor, not a ceiling: an emulator that" - " accepts any file handed to it names none in its code, so nothing" - " there can be counted.", - "Checked by is the test your platform runs on its own, replicated" - " here from its source code, so the result matches what you would" - f" see in the frontend ([how each one works]({SITE_URL}wiki/verification-modes/)).", - "", - "## Build your own pack", - "", - clone_line(db), - "", - "```bash", - "# The pack of a platform, as released", - "python scripts/generate_pack.py --platform retroarch --output-dir dist/", - "python scripts/generate_pack.py --platform batocera --output-dir dist/", - "", - "# Single emulator or system", - "python scripts/generate_pack.py --emulator dolphin", - "python scripts/generate_pack.py --system sony-playstation-2", - "", - "# One region, best first, one file per system and region", - "python scripts/generate_pack.py --platform retroarch --region us,eu,jp", - "python scripts/generate_pack.py --platform retroarch --region us --one-per-slot", - "", - "# Firmware only: the game data a list or a core names is left out, each file named", - "python scripts/generate_pack.py --platform emuelec --no-game-data", - "", - "# The bare minimum: only the files each core needs to start", - "python scripts/generate_pack.py --platform batocera --required-only", - "", - "# List available emulators and systems", - "python scripts/generate_pack.py --list-emulators", - "python scripts/generate_pack.py --list-systems", - "", - "# Coverage of this repository's collection per platform, emulator or system", - "# (it reads database.json and bios/: for your own BIOS folder, run the installer with --check)", - "python scripts/verify.py --all", - "python scripts/verify.py --platform batocera", - "python scripts/verify.py --emulator flycast", - "python scripts/verify.py --platform retroarch --verbose # emulator ground truth", - "```", - "", - "Requires Python 3.9 or newer and `pyyaml`. The one-line installer alone runs on Python 3.8.", - "", - "## Documentation site", - "", - f"The [documentation site]({SITE_URL}) provides:", - "", - "- **Per-platform pages** with file-by-file verification status and hashes", - "- **Per-emulator profiles** with source code references for every file", - "- **Per-system pages** showing which emulators and platforms cover each console", - "- **Gap analysis** identifying missing files and undeclared core requirements", - f"- **Cross-reference** mapping files across {len(coverages)} platforms and {emulator_count} emulators", - "- **Versioned data access** through JSON, CSV and SQLite exports with published SHA-256 checksums", - "", - "## How it works", - "", - "A platform's BIOS list and an emulator's code are maintained" - " separately. Each list is compared with the emulator source code," - " file by file where a profile exists, and where the two differ the" - " code decides.", - "", - "Hashes document what emulator code loads and accepts, not dump" - " provenance. That boundary, and how it relates to preservation" - " catalogs such as No-Intro, is drawn in the" - f" [technical questions]({SITE_URL}wiki/technical-faq/" - "#are-these-files-verified-against-original-hardware-dumps).", - "", - "1. **Read emulator source code**: trace every file the code loads, its expected hash and size", - "2. **Cross-reference with platforms**: match against what each platform declares", - "3. **Build packs**: include baseline files plus what each platform's cores need", - "4. **Verify**: run platform-native checks and emulator-level validation", - "", - ] - ) + others = [name for name in sorted(coverages, key=lambda n: coverages[n]["platform"]) + if name not in released] + lines.extend([ + "", + "ZIPs are made for the setups most people download. The others install with the line" + " above, and each page gives the command: " + + ", ".join(f"[{coverages[name]['platform']}]({SITE_URL}get/{name}/)" for name in others) + + ".", + "", + "Unzip into the BIOS folder, files straight in it. A big pack comes in parts" + " (`Pack.part1of2.zip`): download every part" + f" ([why some setups have no ZIP]({SITE_URL}wiki/faq/#why-is-there-no-zip-for-my-setup))." + " Each release lists its files' SHA-256 with a signature" + f" ([verifying a release]({SITE_URL}wiki/release-process/#verifying-a-release)).", + "", + "## Help", + "", + f"- \"BIOS missing\" or a game does not start: [what to check]({SITE_URL}wiki/troubleshooting/)", + f"- Have a file? [Check it by its hash]({SITE_URL}files/)", + f"- Every console and the files it needs: [systems]({SITE_URL}systems/)", + f"- Asking an AI assistant: it reads the site best from [llms.txt]({SITE_URL}llms.txt)", + "", + "## What makes it different", + "", + f"- **{emulator_count} emulators profiled from their source code**: each file an emulator" + " loads, its hash and the line of code that reads it", + f"- **{len(coverages)} setups**, each checked its own way: MD5 for Batocera and Recalbox," + " the file name for RetroArch, as their own code does", + f"- **{len(system_ids)} systems**, {total_files:,} files in the collection," + f" [what is still missing]({SITE_URL}gaps/) named file by file", + f"- Public data: [JSON, CSV and SQLite]({SITE_URL}data/), MIT licensed", + "", + "
", + "For developers: build a pack", + "", + clone_line(db), + "", + "```bash", + "python scripts/generate_pack.py --platform retroarch --output-dir dist/", + "python scripts/generate_pack.py --emulator dolphin", + "python scripts/generate_pack.py --platform batocera --required-only", + "python scripts/verify.py --platform batocera", + "```", + "", + "Requires Python 3.9 or newer and `pyyaml`. The one-line installer alone runs on Python 3.8." + f" Every tool and option: [tools]({SITE_URL}wiki/tools/). How the lists are built:" + f" [architecture]({SITE_URL}wiki/architecture/).", + "", + "
", + "", + ]) contributors = fetch_contributors() if not contributors: @@ -913,7 +759,7 @@ def generate_readme(db: dict, platforms_dir: str, db_path: str = "database.json" "", "- [BIOS Preservation Tool](https://github.com/monster-penguin/BIOS-Preservation-Tool)" " by [monster-penguin](https://github.com/monster-penguin)" - " - scan, verify, and stage your own BIOS collection" + " - scans, verifies and stages a BIOS collection" " using RetroBIOS hash metadata", "", "## Contributing", @@ -1056,7 +902,7 @@ handheld launchers, `bwrap` (bubblewrap) for the probe sandbox, and a Python 3.8 with pyte (`{floor_line}`) for the full screen. CI has all three. `profile_sync.py` compares the branch with this repository's `main`, and -fetches it in a fork's clone. A profile you only edit is not held to +fetches it in a fork's clone. An edited profile is not held to `--strict`: its older refs are reviewed by hand. The full pipeline is not needed for a contribution: it rebuilds every pack diff --git a/scripts/generate_site.py b/scripts/generate_site.py index dd023a06e..e2cf34562 100644 --- a/scripts/generate_site.py +++ b/scripts/generate_site.py @@ -96,6 +96,7 @@ import siteinputs import retired_files import siteagents import sitestarlight +import sitesteps from siteexports import generate_exports_page, load_export_reports from siteguides import ( ALSO_RUNS, @@ -488,13 +489,13 @@ def generate_home( works_with = ", ".join(named) + (f" and {others} more" if others else "") lines = [ - "# BIOS files for your emulators", + "# BIOS files for emulators", "", "Some consoles need a small program to start their games. It is called " - "the **BIOS**. Your emulator needs a copy of it. We put the right copy " + "the **BIOS**. The emulator needs a copy of it. RetroBIOS puts the right copy " "in the right folder.", "", - markup.button("Get your files", "which-pack.md", primary=True) + " " + markup.button("Get the files", "which-pack.md", primary=True) + " " + markup.button("What is a BIOS?", "wiki/what-are-bios-files.md"), "", f"Free. No account. Works with {works_with}.", @@ -503,9 +504,9 @@ def generate_home( "[When a game does not start](wiki/troubleshooting.md)", "- Have a file? [Check it](files/index.md)", "", - "## Do I need it?", + "## Is it needed? { #do-i-need-it }", "", - "- **Yes**, if your emulator says a BIOS is missing.", + "- **Yes**, if the emulator says a BIOS is missing.", "- **Yes** for PlayStation 1 and 2, Saturn and Neo Geo.", "- **Better with it** for Dreamcast: some games need it.", "- **Usually not** for NES, Super Nintendo, Mega Drive and Game Boy.", @@ -515,12 +516,12 @@ def generate_home( "## Three steps", "", *markup.steps([ - "**Pick your device.** Its page shows your BIOS folder.", + "**Pick the device.** Its page shows the BIOS folder.", "**Run one command.** Some setups have a ZIP.", "**Start a game.**", ]), *install_demo(), - "## Pick your device", + "## Pick the device { #pick-your-device }", "", *setup_picker(registry, display), "## Is it safe?", @@ -574,7 +575,7 @@ def generate_explore_index(db: dict, coverages: dict, profiles: dict) -> str: "", "## Help the project", "", - "A file you hold, an emulator profile or a correction fills a gap for " + "A file sent in, an emulator profile or a correction fills a gap for " "every setup at once. For contributors: [How to contribute](contributing.md).", "", ] @@ -752,7 +753,7 @@ def _folder_words(display: str, extract_to: str | None) -> str: """The folder a pack or a copy goes into, in words: the device's path, or a folder of the setup named as the setup's.""" if not extract_to: - return "your BIOS folder" + return "the BIOS folder" if _setup_relative(extract_to): return f"{display}'s `{extract_to.rstrip('/')}` folder" return f"`{extract_to}`" @@ -824,7 +825,7 @@ def generate_get_page(platform_name: str) -> str: "", f"- {_fmt_size(pack['download_size'])} to download, " f"{_fmt_size(pack['extracted_size'])} once unzipped.", - *(["- You need both parts." if parts == 2 else f"- You need all {parts} parts."] + *(["- Both parts are needed." if parts == 2 else f"- All {parts} parts are needed."] if parts > 1 else []), *_unzip_into(platform_name, display, extract_to, parts), *(line for text in release for line in (text, "")), @@ -2349,7 +2350,7 @@ def generate_data_page(exports: list[dict], measurements_sqlite: Path | None = N "per `bios///` folder of the collection, named " "`Manufacturer\\Console` so the tools look in that subfolder, each file a " "rom named by its path below that folder. It audits a copy of the " - "collection's `bios/` tree, or rebuilds that layout from your own dumps.", + "collection's `bios/` tree, or rebuilds that layout from a reader's own dumps.", "", "A setup's DAT, `downloads/dat/.dat`, describes its BIOS folder " "once installed: one game named after the folder (`bios`, `system`), each " @@ -2449,7 +2450,7 @@ def _browser_title(relative: Path, title: str) -> str: # Material appends " - RetroBIOS": the home title says what the site # is, instead of "RetroBIOS - RetroBIOS". "index.md": "BIOS and firmware packs for RetroArch, Batocera and more", - "platforms/index.md": "Your setup", + "platforms/index.md": "Setups", "systems/index.md": "Systems", "emulators/index.md": "Emulators", "wiki/index.md": "Reference", @@ -2510,7 +2511,7 @@ def _shorten(plain: str, limit: int = 157) -> str: def _page_description(markdown: str, relative: Path, title: str) -> str: key = relative.as_posix() specific = { - "index.md": "The BIOS files your emulators need, for RetroArch, Batocera, EmuDeck and more: the folder they go in, one command that installs and checks them, and packs to download.", + "index.md": "The BIOS files emulators need, for RetroArch, Batocera, EmuDeck and more: the folder they go in, one command that installs and checks them, and packs to download.", "data.md": "Versioned RetroBIOS JSON API, CSV exports, SQLite snapshot, schemas, checksums and data interpretation guidance.", "cross-reference.md": "Every emulator core each retrogaming platform runs, the systems it emulates and the upstream project it comes from.", "gaps.md": "Current RetroBIOS verification gaps, platform-to-emulator divergences, missing files and documented source limitations.", @@ -2518,7 +2519,7 @@ def _page_description(markdown: str, relative: Path, title: str) -> str: sitemeasurements.EXPLORER_PAGE: "The records of emulator cores run headless on demand, each with its claim, verdict, the BIOS it ran, method, computer and full record, filterable, and as SQLite.", "provenance.md": "Hash-based comparison of RetroBIOS metadata with No-Intro, Redump and TOSEC catalog snapshots.", "explore.md": "Systems, emulators and installer options to explore, with the figures of the BIOS collection.", - "which-pack.md": "Pick your device or setup and get its BIOS files: the folder they go in, one command that installs and checks them, or a ZIP pack to extract.", + "which-pack.md": "Pick a device or setup and get its BIOS files: the folder they go in, one command that installs and checks them, or a ZIP pack to extract.", "contributing.md": "Add a BIOS file the collection lacks from the browser, checked on arrival, or add a platform or an emulator profile.", } if key in specific: @@ -2571,7 +2572,7 @@ def _lead(markdown: str) -> str: def _emulator_description(markdown: str, key: str, title: str, intro: str) -> str: """An emulator page by its intro sentence ("DuckStation emulates Sony - PlayStation. It picks the BIOS for your game's region: ..."), or by + PlayStation. It picks the BIOS for the game's region: ..."), or by its profile table when the profile names no system.""" notes = re.search(r"Technical notes\s*\n\n(.+?)(?:\n\n|$)", markdown, re.S) if not intro and notes: @@ -3357,12 +3358,12 @@ def decorate_markdown_pages(docs: Path) -> dict[str, str]: def generate_platform_index(coverages: dict, registry: dict | None = None) -> str: - """The Your setup tab: every platform by the device it runs on, and one + """The Setups tab: every platform by the device it runs on, and one line to the table that sets them side by side (setup_table), which is reference matter and sits with how each setup checks its files.""" registry = registry or {} lines = [ - "# Your setup", + "# Setups", "", "Each setup's page gives the folder and the command.", "", @@ -4181,16 +4182,19 @@ def first_screen_words() -> list[str]: # The demo files the site serves (docs_assets/demo/, scripts/make_demo.py): # the GIF is the README's, the tape and demo.json are inputs. -DEMO_ASSETS = ("install.webm", "install.mp4", "install.png") +DEMO_ASSETS = tuple(f"{stem}.{ext}" for stem in ("install", "install-handheld") + for ext in ("webm", "mp4", "png")) -def install_demo() -> list[str]: - """The installer demo: a video that loads once it is on screen, its - description for screen readers.""" - facts = demo_facts() +def install_demo(variant: str = "default", name: str = "") -> list[str]: + """An installer demo (default, or handheld): a video that loads once it + is on screen, its description for screen readers. *name* tells two + demos of one page apart (the tab each sits in).""" + facts = demo_facts(variant) text = html.escape(demo_description(facts), quote=True) + own = f' variant="{variant}" name="{name}"' if name else "" return [f'', ""] + f'height="{facts["height"]}"{own} />', ""] def check_pass_line() -> str: @@ -4238,7 +4242,7 @@ def _share_tabs(name: str, share: str) -> tuple[dict[str, str], dict[str, str]]: how = { "macos": (f"In Finder, Go > Connect to Server: `{url}`. Then paste the line in " "**Terminal**."), - "linux": (f"Open `{url}` in your file manager. Paste the line in a terminal, " + "linux": (f"Open `{url}` in the file manager. Paste the line in a terminal, " f"with the folder it opened for `/path/to/{volume}`."), } return args, how @@ -4279,7 +4283,7 @@ def _card_route(name: str, display: str, guide: Guide) -> list[str]: return [lead, "", *terminal_tabs(tabs, args, steps=False)] # A folder on the card's Linux partition: Windows and macOS show the # small boot partition alone, and no folder there fits --dest. - put = ("Put the device's card in your computer." if "windows" in tabs + put = ("Put the device's card in a computer." if "windows" in tabs else "Only a Linux computer opens the card.") lead = (f"No network? {put} After `--dest`, " f"name the folder the device calls `{extract_to}`.") @@ -4306,14 +4310,14 @@ def _setup_routes(name: str, display: str, page_link: bool = False) -> list[str] card = _card_route(name, display, guide) shared = _get_page_line(name, display) if page_link else [] if share or (card and guide.run == ("device",)): - computer = ["## From your computer { #from-your-computer }", ""] + computer = ["## From a computer { #from-your-computer }", ""] if share: args, how = _share_tabs(name, share) # The setup page stays in its word budget: its Mac and Linux # lines are on the get/ page, the one the command is shared from. tabs = ("windows",) if page_link else ("windows", "macos", "linux") computer += [ - "Needs the device on your network.", + "Needs the device on the same network.", "", *terminal_tabs(tabs, args, how=how), *([f"[Mac or Linux](../{get_page_link(name)}#from-your-computer)", ""] @@ -4327,7 +4331,7 @@ def _setup_routes(name: str, display: str, page_link: bool = False) -> list[str] # Shown in the "On the device" tab of a guide that has no `terminal:` of its own. -DEVICE_TERMINAL_FALLBACK = "Or fill the folder from your computer, with the ZIP." +DEVICE_TERMINAL_FALLBACK = "Or fill the folder from a computer, with the ZIP." def _computer_first(name: str, guide: Guide) -> bool: @@ -4362,11 +4366,11 @@ def _guide_download(name: str, display: str, guide: Guide, extract_to: str | Non f"{_fmt_size(pack['extracted_size'])} once unzipped." ] if parts > 1: - bullets.append("You need both parts." if parts == 2 else f"You need all {parts} parts.") + bullets.append("Both parts are needed." if parts == 2 else f"All {parts} parts are needed.") if _computer_first(name, guide) and network: target = "the network folder above" else: - target = f"`{extract_to}`" if extract_to else "your BIOS folder" + target = f"`{extract_to}`" if extract_to else "the BIOS folder" bullets.append(f"Unzip {'them all' if parts > 1 else 'it'} into {target}." + (" Files like `neogeo.zip` stay zipped." if _ships_neogeo(name) else "")) if guide.download_hint and not _computer_first(name, guide): @@ -4392,7 +4396,7 @@ def _guide_download(name: str, display: str, guide: Guide, extract_to: str | Non def only_some_consoles(name: str, prefix: str = "") -> list[str]: - """The way to a smaller download, in the words Get your files uses.""" + """The way to a smaller download, in the words Get the files uses.""" return [ f"Only some consoles? [Pick them]({prefix}which-pack.md?platform={name}" f"#only-some-consoles), or the command's **{_installer().TUI_SYSTEMS_ROW}**.", @@ -4483,7 +4487,7 @@ def generate_handheld_guide(guide: HandheldGuide) -> str: "", "## Where the files go { #where-the-files-go }", "", - "Put the SD card in a computer. Find your system below.", + "Put the SD card in a computer. Find the system below.", "", "| System | Devices | BIOS folder on the card |", "|--------|---------|-------------------------|", @@ -4539,7 +4543,7 @@ def _platform_guide(name: str, display: str, cov: dict, registry: dict, no_list: if _computer_first(name, guide): lines += [ *_guide_download(name, display, guide, extract_to, - "## From your computer { #download }"), + "## From a computer { #download }"), *_offline_line(name), *_guide_install(name, guide, "## On the device { #install }"), ] @@ -5502,7 +5506,7 @@ def generate_provenance_page( "", *([f'

Catalogs as of: {as_of}.

', ""] if as_of else []), "Provenance says whether a file is, byte for byte, a dump that Redump, " - "No-Intro or TOSEC catalogues. It tells you where a dump is known from, " + "No-Intro or TOSEC catalogues. It says where a dump is known from, " "not whether an emulator accepts it: that is the emulator's code, read " "in its profile. Example: `scph5501.bin` is Redump's `ps-30a.bin`.", "", @@ -5539,7 +5543,7 @@ def generate_provenance_page( "arcade sets tracked by MAME driver source instead.", "", "When the two views disagree, this project follows the code, because " - "that is what decides whether your emulator boots. The reasoning is in " + "that is what decides whether the emulator boots. The reasoning is in " "the [technical questions](wiki/technical-faq.md#are-these-files-verified-against-original-" "hardware-dumps).", "", @@ -6993,7 +6997,7 @@ def _group_lines( lines += [f"- **{key}**: {text.lstrip(': ')}" for key, block in blocks.items() for _lead, text in block] return [*lines, ""] - lines = ["**Start with** the files of your machine:", ""] + lines = ["**Start with** the files of the machine:", ""] for key, block in blocks.items(): for lead, text in block: if lead == "*": @@ -7205,7 +7209,7 @@ def _start_lines(block: list[tuple[str, str]], console: str = "") -> list[str]: below = " They come first below." if _sep else "" return [" ".join(filter(None, [f"**Start with**: {named}.{below}", instead])), ""] bios = f"the {console} BIOS" if console else "the BIOS" - lines = [f"**Start with** {bios} for the region of your games:", ""] + lines = [f"**Start with** {bios} for the region of the games:", ""] for lead, text in block: lines.append(f"- **{lead or 'Some emulators also require'}**: {text}") if instead: @@ -7262,7 +7266,7 @@ def _romset_note(consoles: dict[str, list]) -> list[str]: _NEXT_FROM_SYSTEMS = [ - "[Get your files](../which-pack.md), for the setup you play on", + "[Get the files](../which-pack.md), for the setup in use", "[When a game does not start](../wiki/troubleshooting.md)", "[Every emulator](../emulators/index.md), and the files each one reads", ] @@ -8976,7 +8980,7 @@ def _install_block(name: str, profile: dict) -> list[str]: f"BIOS folder, then downloads only the files {emu} reads there and checks " "each one.") else: - lead = ("The installer finds your setup and its BIOS folder, then downloads " + lead = ("The installer finds the setup and its BIOS folder, then downloads " "only the files this emulator reads there and checks each one.") if profile.get("type") == "standalone + libretro": # The command fills a setup, never the app's own folder. @@ -9242,7 +9246,7 @@ def _install_picker(declared: list[tuple[str, str]]) -> list[str]: "", '