From 0e488f54d6200100bae669aef8154cbcecd79598 Mon Sep 17 00:00:00 2001 From: Georges-Antoine Assi Date: Sat, 19 Sep 2026 09:54:17 -0400 Subject: [PATCH 1/2] docs: document save slots and auto-sync being on by default `emulatorjs.auto_save_sync` defaults to true since 5.3.0, and the player now polls the emulator's save memory rather than waiting for save-and-quit, so the opt-in framing was backwards. Save slots and the in-emulator "Load save or state" picker were undocumented. Bumps the pinned romm ref to 5.3.0-beta.1 so the generated env-var table picks up MAX_SAVES_PER_SLOT. The other generated snippets are unchanged. Co-Authored-By: Claude Opus 5 (1M context) --- docs/reference/configuration-file.md | 6 +++--- docs/resources/snippets/env-vars.md | 29 ++++++++++++++-------------- docs/using/saves-and-states.md | 28 +++++++++++++++++++++++---- scripts/sources.toml | 2 +- 4 files changed, 43 insertions(+), 22 deletions(-) diff --git a/docs/reference/configuration-file.md b/docs/reference/configuration-file.md index 27d71229..989ebc82 100644 --- a/docs/reference/configuration-file.md +++ b/docs/reference/configuration-file.md @@ -437,13 +437,13 @@ Core names have to be exact, and anything you don't list keeps EmulatorJS's own ### `emulatorjs.auto_save_sync` -Upload a save every time the emulator writes one, rather than only on save-and-quit. Closing the tab or suffering a crash mid-game then loses nothing. +Upload a save seconds after the emulator writes one, rather than only on save-and-quit. Closing the tab or suffering a crash mid-game then loses nothing. Set it to `false` and the emulator's save button comes back as **Sync save**, for uploading on demand. See [Automatic save sync](../using/saves-and-states.md#automatic-save-sync). -**Default:** `false` +**Default:** `true` ```yaml emulatorjs: - auto_save_sync: true + auto_save_sync: false ``` ### `emulatorjs.disable_auto_unload` diff --git a/docs/resources/snippets/env-vars.md b/docs/resources/snippets/env-vars.md index e2864883..d06e702b 100644 --- a/docs/resources/snippets/env-vars.md +++ b/docs/resources/snippets/env-vars.md @@ -161,10 +161,11 @@ ### Assets -| Variable | Default | Required | Description | -| ----------------------------- | ----------- | :------: | ---------------------------------------------------------------------------------- | -| `MAX_ASSET_UPLOAD_SIZE_BYTES` | `536870912` | | Max size of a save/state/screenshot upload request in bytes (0 disables the limit) | -| `MAX_AUTOCLEANUP_LIMIT` | `100` | | Max number of saves a client can keep per slot when autocleanup is on (minimum 1) | +| Variable | Default | Required | Description | +| ----------------------------- | ----------- | :------: | ------------------------------------------------------------------------------------------- | +| `MAX_ASSET_UPLOAD_SIZE_BYTES` | `536870912` | | Max size of a save/state/screenshot upload request in bytes (0 disables the limit) | +| `MAX_AUTOCLEANUP_LIMIT` | `100` | | Max number of saves a client can keep per slot when autocleanup is on (minimum 1) | +| `MAX_SAVES_PER_SLOT` | `50` | | Versions the server keeps per save slot, newest first, on every slotted upload (0 disables) | ### Logging @@ -176,16 +177,16 @@ ### Web Server -| Variable | Default | Required | Description | -| ---------------------------------- | ------- | :------: | ------------------------------------------------------------------ | -| `WEB_SERVER_CONCURRENCY` | `4` | | Number of API worker processes, raise for several concurrent users | -| `WEB_SERVER_TIMEOUT` | `300` | | Timeout for web server requests in seconds | -| `WEB_SERVER_KEEPALIVE` | `2` | | Keep-Alive connection wait time in seconds | -| `WEB_SERVER_MAX_REQUESTS` | `1000` | | Maximum requests a worker processes before restarting | -| `WEB_SERVER_MAX_REQUESTS_JITTER` | `100` | | Random jitter added to max requests value | -| `WEB_SERVER_WORKER_CONNECTIONS` | `1000` | | Maximum simultaneous clients per worker process | -| `WEB_SERVER_GUNICORN_WAIT_SECONDS` | `30` | | Seconds to wait for Gunicorn to start before giving up | -| `IPV4_ONLY` | `false` | | Bind only to IPv4 | +| Variable | Default | Required | Description | +| ---------------------------------- | ------- | :------: | ---------------------------------------------------------------------------------------- | +| `WEB_SERVER_CONCURRENCY` | `4` | | Number of API worker processes, raise for several concurrent users | +| `WEB_SERVER_TIMEOUT` | `300` | | Timeout for web server requests in seconds | +| `WEB_SERVER_KEEPALIVE` | `65` | | Keep-Alive connection wait time in seconds, keep above nginx's 60s upstream idle timeout | +| `WEB_SERVER_MAX_REQUESTS` | `1000` | | Maximum requests a worker processes before restarting | +| `WEB_SERVER_MAX_REQUESTS_JITTER` | `100` | | Random jitter added to max requests value | +| `WEB_SERVER_WORKER_CONNECTIONS` | `1000` | | Maximum simultaneous clients per worker process | +| `WEB_SERVER_GUNICORN_WAIT_SECONDS` | `30` | | Seconds to wait for Gunicorn to start before giving up | +| `IPV4_ONLY` | `false` | | Bind only to IPv4 | ### Proxy diff --git a/docs/using/saves-and-states.md b/docs/using/saves-and-states.md index 95d88e34..551e10d6 100644 --- a/docs/using/saves-and-states.md +++ b/docs/using/saves-and-states.md @@ -22,19 +22,39 @@ If a ROM has multiple saves or states, RomM presents a picker before the emulato ## In-emulator behaviour -In-game save/save-state/load-state actions are written straight back to the server, so there's no "forgot to upload" step. The player will also ask you to confirm before navigating away from a running game, which prevents losing any unsaved progress. +Saves and states you create in the emulator are written straight back to the server, so there's no "forgot to upload" step. The player also asks you to confirm before navigating away from a running game, so you don't lose unsaved progress. + +EmulatorJS' own "Export save file" and "Import save file" buttons are hidden, because RomM handles both for you. In their place: + +- **Load save or state** opens a picker with the same Saves and States tabs as the launch screen. A state applies on the fly; picking a save writes it and restarts the game so it boots from it. Either one replaces what's running, so you're asked to confirm first. +- **Sync save** appears only when [automatic save sync](#automatic-save-sync) is off, and uploads the current save on demand. ## Automatic save sync -Normally your save gets uploaded when you **save and quit**. Close the tab instead, or crash the browser, or shut the laptop, and the save never leaves the device. Enable [`emulatorjs.auto_save_sync`](../reference/configuration-file.md#emulatorjsauto_save_sync) and the player uploads every time the emulator writes a save, so it doesn't matter how the session ends: +The player watches the emulator's save memory while you play and uploads a new version seconds after the game writes one. A closed tab, a browser crash or a laptop going to sleep costs you nothing, and leaving the player uploads anything the server doesn't have yet. + +This is on by default. Set [`emulatorjs.auto_save_sync`](../reference/configuration-file.md#emulatorjsauto_save_sync) to `false` to go back to uploading only on **save and quit**: ```yaml emulatorjs: - auto_save_sync: true + auto_save_sync: false ``` Each upload is the entire save file, and some games save constantly. On a small instance you won't notice, but you might with a lot of users and large saves. This is instance-wide, set by the server owner, and only affects in-browser play. Save **states** already upload as you create them and aren't affected either way. +An upload the server doesn't take (it's down, the connection dropped) is held in your browser with the screenshot taken when the game wrote it, and retried later. The player tells you whether it was kept, so a "kept for later" message means the progress is safe even though the save isn't on the server yet. Held saves belong to the account that made them, so a shared browser won't hand your progress to whoever signs in next. + +## Save slots + +A save belongs to a **slot**, the same model the [sync clients](#device-sync) use, so the same slots show up whether you played in the browser or on a device. + +- **`autosave`** is where ordinary play goes. It keeps a capped history, so it prunes itself as you play. +- **Named slots** are yours to create from the launch screen, and keep every version. Use one when you want a checkpoint you can always come back to. + +Each slot lists its newest version first, tagged **Latest**, with older versions folded behind a toggle. A version made in the browser carries a screenshot of the moment it was written, shown as its thumbnail. + +Server owners can cap how many versions a slot keeps with `MAX_SAVES_PER_SLOT` (50 by default, `0` to disable the cap). A client that asks for a tighter limit of its own gets the tighter of the two. Saves uploaded without a slot, such as one you imported by hand, are never pruned. + ## Device sync Saves and states can sync to/from registered devices (Grout on muOS, DeckRommSync on a Deck, etc.). Covered in depth in the ecosystem section: @@ -77,7 +97,7 @@ If you use [RetroAchievements](retroachievements.md) in hardcore mode, loading a - **Save uploaded but the game doesn't see it**: wrong format for the core. Check the compatibility table above, then re-upload or switch cores. - **State loads a corrupted frame**: state was saved by a different build of the core. If the emulator bundle updated, old states may not load cleanly. Re-create or start a fresh save. -- **Save disappears after play**: the emulator didn't flush on quit. Use the in-game save feature instead of just closing the browser. +- **Save disappears after play**: the emulator didn't write a save at all. Use the in-game save feature rather than relying on the emulator flushing on its own, and check that [automatic save sync](#automatic-save-sync) is on. - **Can't upload, "file too large"**: reverse proxy limit. Raise `client_max_body_size`/`proxy-body-size` (see [Reverse Proxy](../install/reverse-proxy.md)). More in [Troubleshooting](../troubleshooting/index.md). diff --git a/scripts/sources.toml b/scripts/sources.toml index 6436743b..07104db7 100644 --- a/scripts/sources.toml +++ b/scripts/sources.toml @@ -12,4 +12,4 @@ repo = "rommapp/romm" # Set to a tag (e.g. "v5.0.0") or a full SHA. Generators fetch raw files # from raw.githubusercontent.com/${repo}/${ref}/... -ref = "839605e679bad7a6b552c4219627f68c32e41e29" +ref = "5.3.0-beta.1" From 1242d44d99f2c8a9f015c761cd626461efa34b1f Mon Sep 17 00:00:00 2001 From: Georges-Antoine Assi Date: Sat, 19 Sep 2026 09:58:39 -0400 Subject: [PATCH 2/2] docs: match the release notes wording for save sync and slots Co-Authored-By: Claude Opus 5 (1M context) --- docs/reference/configuration-file.md | 2 +- docs/using/saves-and-states.md | 17 ++++++++--------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/docs/reference/configuration-file.md b/docs/reference/configuration-file.md index 989ebc82..54970326 100644 --- a/docs/reference/configuration-file.md +++ b/docs/reference/configuration-file.md @@ -437,7 +437,7 @@ Core names have to be exact, and anything you don't list keeps EmulatorJS's own ### `emulatorjs.auto_save_sync` -Upload a save seconds after the emulator writes one, rather than only on save-and-quit. Closing the tab or suffering a crash mid-game then loses nothing. Set it to `false` and the emulator's save button comes back as **Sync save**, for uploading on demand. See [Automatic save sync](../using/saves-and-states.md#automatic-save-sync). +Sync a save with the server seconds after it's stored in the browser, rather than only on save-and-quit, so progress is kept even if the tab is closed or the browser crashes. Set it to `false` and the emulator's save button comes back as **Sync save**, for uploading on demand. See [Automatic save sync](../using/saves-and-states.md#automatic-save-sync). **Default:** `true` diff --git a/docs/using/saves-and-states.md b/docs/using/saves-and-states.md index 551e10d6..d581fa97 100644 --- a/docs/using/saves-and-states.md +++ b/docs/using/saves-and-states.md @@ -24,14 +24,13 @@ If a ROM has multiple saves or states, RomM presents a picker before the emulato Saves and states you create in the emulator are written straight back to the server, so there's no "forgot to upload" step. The player also asks you to confirm before navigating away from a running game, so you don't lose unsaved progress. -EmulatorJS' own "Export save file" and "Import save file" buttons are hidden, because RomM handles both for you. In their place: +In-game, the Export and Import save buttons are replaced by a single **Load save or state** picker, which opens with the same Saves and States tabs as the launch screen. A state applies on the fly; picking a save restarts the game from that save. Either one replaces what's running, so you're asked to confirm first. -- **Load save or state** opens a picker with the same Saves and States tabs as the launch screen. A state applies on the fly; picking a save writes it and restarts the game so it boots from it. Either one replaces what's running, so you're asked to confirm first. -- **Sync save** appears only when [automatic save sync](#automatic-save-sync) is off, and uploads the current save on demand. +A **Sync save** button appears alongside it when [automatic save sync](#automatic-save-sync) is off, to upload the current save on demand. ## Automatic save sync -The player watches the emulator's save memory while you play and uploads a new version seconds after the game writes one. A closed tab, a browser crash or a laptop going to sleep costs you nothing, and leaving the player uploads anything the server doesn't have yet. +A save syncs automatically with the server seconds after it's stored in the browser. The player watches the emulator's SRAM while you play and uploads a new version as soon as one appears, so your progress is saved even if the tab is closed or the browser crashes. Leaving the player uploads anything the server doesn't have yet. This is on by default. Set [`emulatorjs.auto_save_sync`](../reference/configuration-file.md#emulatorjsauto_save_sync) to `false` to go back to uploading only on **save and quit**: @@ -46,14 +45,14 @@ An upload the server doesn't take (it's down, the connection dropped) is held in ## Save slots -A save belongs to a **slot**, the same model the [sync clients](#device-sync) use, so the same slots show up whether you played in the browser or on a device. +Saves are organized into slots, the same model used by the [sync clients](#device-sync), so the same slots show up whether you played in the browser or on a device. -- **`autosave`** is where ordinary play goes. It keeps a capped history, so it prunes itself as you play. -- **Named slots** are yours to create from the launch screen, and keep every version. Use one when you want a checkpoint you can always come back to. +- **`autosave`** is where ordinary play goes, and it keeps a capped history, so it prunes itself as you play. +- **A named slot**, created on launch, keeps every version. Use one when you want a checkpoint you can always come back to. -Each slot lists its newest version first, tagged **Latest**, with older versions folded behind a toggle. A version made in the browser carries a screenshot of the moment it was written, shown as its thumbnail. +Each slot lists its newest version first, tagged **Latest**, with older versions folded behind a toggle. A version written in the browser carries a screenshot from the moment it was written, shown as its thumbnail. -Server owners can cap how many versions a slot keeps with `MAX_SAVES_PER_SLOT` (50 by default, `0` to disable the cap). A client that asks for a tighter limit of its own gets the tighter of the two. Saves uploaded without a slot, such as one you imported by hand, are never pruned. +The server prunes a slot to `MAX_SAVES_PER_SLOT` (50 by default, `0` to disable the cap). A client that asks for a tighter limit of its own gets the tighter of the two. Saves uploaded without a slot, such as one you imported by hand, are never pruned. ## Device sync