-
Notifications
You must be signed in to change notification settings - Fork 0
ROMs and Emulation
GamesDownloader ships a full retro-gaming module: a per-platform ROM library with hash-based metadata scraping, an in-browser emulator powered by EmulatorJS, and Couch Mode, a controller-first, full-screen console-style interface. This page covers all three. For how metadata is matched and where artwork comes from, see Scrapers & Metadata; for browsing and views shared with the rest of the app, see Library.
- The ROM library
- Placing ROMs and scanning
- Supported files and archives
- Metadata scraping
- Covers and aspect ratios
- In-browser emulation
- Display modes
- Save states and battery saves
- Bezels and gamepads
- Game Saves tab and quota
- Couch Mode
- Storage layout
The ROM library is organised per platform (SNES, Genesis / Mega Drive, Game Boy, PS1, N64, and many more). Each platform is a directory under the ROM root; every file inside is catalogued as a ROM, scraped for artwork and details, and made playable in the browser when the platform has an emulator core.
Drop your ROM files into a per-platform folder under the ROM root inside your data volume:
data/games/roms/{platform}/
For example data/games/roms/snes/, data/games/roms/genesis/, data/games/roms/psx/. The {platform} folder name is a filesystem slug that GamesDownloader maps to the correct system, IGDB / ScreenScraper / LaunchBox identifiers, and emulator core.
Auto-created folders. On container start GamesDownloader creates a ROM subdirectory for every known platform (one folder per canonical platform, alias slugs de-duplicated), so after the first boot you will already have folders to drop files into. You do not have to create them by hand.
Once files are in place, open the ROM library in the web UI and run Scan ROMs. The scan walks the ROM root, detects platforms and files, and upserts everything into the database. It reports how many platforms and ROMs were found, how many are new, and how many were updated. A single-instance lock means only one scan runs at a time; you can poll its status while it works. ROMs that have been removed from disk are flagged as missing rather than silently deleted.
Structure note. Both layouts work: ROM files placed directly in
data/games/roms/{platform}/, or nested one level deeper indata/games/roms/{platform}/roms/. The scanner picks up either.
The scanner recognises a broad set of ROM extensions per system (for example .nes, .sfc, .smc, .z64, .gb, .gba, .nds, .md, .bin, .cue, .chd, .iso, .pbp, and more), plus compressed archives.
| Archive | Catalogued | Hashing behaviour |
|---|---|---|
.zip |
+ | Hashes the largest file inside the archive (the actual ROM), not the archive wrapper |
.7z |
+ | Same: extracts and hashes the inner ROM (requires the py7zr library, bundled in the Docker image) |
Hashing the uncompressed content is what lets a zipped ROM match the same database entry as its unzipped twin, exactly how ScreenScraper and EmulationStation identify games.
Scraping runs in a single pass across multiple providers and is primarily hash-based: the scanner computes CRC32 / MD5 / SHA1 from the ROM content (from inside the archive where applicable) and matches on those hashes first, falling back to the cleaned filename and a name search when no hash match is found.
Sources combined for the ROM library:
| Source | Cover | Hero | Screenshots | Support / Bezel / Wheel | Video | Description | Score |
|---|---|---|---|---|---|---|---|
| ScreenScraper | + | + | + | + | + | + | + |
| IGDB | + | + | + | + | |||
| LaunchBox | + | + | + | + | + | + | |
| SteamGridDB | + | + | + | ||||
| Plugins | + | + | + | + | + | + | |
| HowLongToBeat | (playtime) |
For the full matching logic, provider credentials, the 10-tab Edit Metadata editor, and per-source Apply buttons, see Scrapers & Metadata. Metadata plugins contribute to the ROM library exactly as they do for GOG and custom games; see Plugin Development.
The library grid is platform-aware: box art is displayed at the aspect ratio that matches each system's real packaging, so covers do not stretch.
| Ratio | Typical platforms |
|---|---|
3/4 (portrait, default) |
N64, GameCube, Wii, PlayStation, Xbox, DS, most modern systems |
16/11 |
SNES, Super Famicom, Famicom, PC Engine, Neo Geo |
4/3 (landscape) |
Genesis / Mega Drive (US / EU), Master System, Saturn, Dreamcast |
1/1 (square) |
Game Boy, Game Boy Color, Game Gear, Atari 2600 |
The default preferred cover is the 2D box front (box-2D) from ScreenScraper, with the region left at ScreenScraper's own preference. This can be tuned per platform through the scrape presets (cover type, region, and extra artwork), and any cover can be swapped manually in the Edit Metadata panel.
Playable ROMs run directly in the browser through EmulatorJS, with no client-side installation. EmulatorJS drives RetroArch cores compiled to WebAssembly, so a wide range of systems is supported from one interface: NES, SNES, GBA, GBC, Game Boy, Genesis / Mega Drive, N64, PS1, arcade, and many more. Platforms without a matching core are still catalogued in the library but are not launchable.
Press Play on a ROM's detail page to open the display-mode picker, then start the game.
Three display modes are offered when you launch a game, and your choice is remembered for next time:
| Mode | Behaviour |
|---|---|
| Fullscreen | Covers the entire viewport as a top-level page |
| Window | A floating, resizable panel embedded in the current page |
| New Tab | Opens the emulator in a dedicated browser tab |
Multithreading. Fullscreen and New Tab load the player at the top level and can use multithreaded cores when threads are enabled in settings (this relies on COOP / COEP headers, which the server sets). The floating Window panel runs in an iframe and is single-threaded, which keeps it lightweight for quick sessions.
The emulator supports two kinds of persistence, both stored server-side, per user, per ROM:
- Save states capture the exact machine state at any moment and can be restored later. Each save state stores a thumbnail screenshot taken at the point of saving.
- Battery saves (SRAM) are the game's own in-cartridge saves; they are uploaded automatically when the game exits, so your progress survives across sessions and devices.
A built-in load-state picker lets you browse both lists without leaving the player. It has separate tabs for save states and battery saves; with a controller you load the highlighted entry with A, delete an individual entry with X, switch tabs with the shoulder / d-pad, and close with B.
Uploaded save files are virus-scanned (ClamAV) and counted against your storage quota before being written.
- Bezel overlay. When a game has bezel artwork (a PNG with a transparent centre), you can toggle a decorative frame over the game canvas. The toggle is per game and remembered across sessions. Bezels are only offered for ROMs that actually have bezel art.
- Gamepad support. Controllers are read through the browser Gamepad API. Chromium-based browsers are recommended; Firefox has limited gamepad support in embedded contexts.
Each user manages their own save data from the Game Saves tab on the Profile page. There you can view, download, and delete your save states and battery saves across every ROM. A quota bar shows total disk usage against your allowance.
The default per-user save quota is 100 MB, configurable by an administrator (saves_quota_bytes). Uploads that would exceed the quota are rejected with a clear message, and deleting old saves frees the space immediately. Save management follows the same Users & Permissions model as the rest of the app: each user only ever sees their own saves.
Couch Mode is a full-screen, controller-first interface for browsing platforms, launching games, and managing saves entirely without a keyboard or mouse. It is reachable from the Classic theme via the user menu, and exiting returns you to /library on the Classic layout or / on the Modern layout.
Platform carousel. Systems are shown as an animated card carousel with Ken Burns photo backgrounds, platform name logos, and locale-aware scrolling descriptions (drawn from XML platform metadata in your UI language, with a fallback).
Three themes. Choose Noir, Aura, or Slick. Each restyles the cards, backgrounds, and overlays (for example Noir is a warm, cinematic, grainy look; Aura is vivid and bright; Slick is a near-dark, hard-edged treatment).
Game views. Games can be shown as a list or a grid, with configurable cover sizes (XS / S / M / L). Game trailers can play as a muted background video with a volume control.
In-game pause menu. Pressing Start + Select (or Esc) opens a custom overlay with:
| Item | Action |
|---|---|
| Resume | Return to the game |
| Save State | Write a new save state (with screenshot) |
| Load State | Open the load-state picker |
| Emulator Settings | Open the full settings system |
| Exit Game | Leave the emulator |
Full emulator settings. A 10-category settings system is driven by the live EmulatorJS API, covering Audio, Graphics (shaders, FPS, VSync, rotation), Screen Capture, Speed (fast-forward, slow-motion, rewind), Input (keyboard, mouse lock, autofire, virtual gamepad), Save States (slot, location, auto-save interval), Control Settings (per-player gamepad assignment and button remapping with live capture), Cheats, Core Options read from the core at runtime, and Restart Game. Settings persist across sessions.
Couch Menu. Pressing Start (or M) opens the couch menu for theme, view mode, launch mode, bezel toggle, cover size, and video volume.
Exit and input safety. Exiting Couch Mode goes through a controller-navigable confirmation dialog, and a short (300 ms) cooldown after any overlay closes prevents a held button from bleeding through into the view underneath.
ROM files and their generated media live under the data volume:
| Path | Contents |
|---|---|
data/games/roms/{platform} |
ROM files, per platform |
data/resources/roms/{platform}/{rom_id} |
Per-ROM media (cover, hero, bezel, wheel, video, support art) |
data/resources/roms/{platform}/{rom_id}/states/{user_id} |
Save states, per user per ROM |
data/resources/roms/{platform}/{rom_id}/saves/{user_id} |
Battery saves (SRAM), per user per ROM |
data/resources/platforms |
Platform icons, name logos, and fanart used by the carousel |
All scraped artwork is downloaded and served locally, never hot-linked from an upstream CDN.
Next: Scrapers & Metadata · Library
Getting Started
Configuration
Features
- Dashboard
- Library
- Collections
- Game Requests
- GOG Integration
- ROMs & Emulation
- Downloads & Torrents
- Users & Permissions
- Themes
Plugin Development
Reference