Skip to content

ROMs and Emulation

60plus edited this page Jul 7, 2026 · 8 revisions

ROMs & 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.

Contents

The ROM library

Platform selection, across themes

Modern Classic
Modern Classic
Neon Horizon Vapor
Neon Horizon Vapor

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.

Placing ROMs and scanning

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 in data/games/roms/{platform}/roms/. The scanner picks up either.

Supported files and archives

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.

Metadata scraping

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.

Covers and aspect ratios

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.

In-browser emulation

A ROM detail page, across themes

Modern Classic
Modern Classic
Neon Horizon Vapor
Neon Horizon Vapor

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.

Display modes

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.

Save states and battery saves

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.

Bezels and gamepads

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

Game Saves tab and quota

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

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.

Storage layout

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

Clone this wiki locally