Skip to content

fix(player): keep origin save bound and surface save slots in v2 EmulatorJS#3831

Merged
gantoine merged 3 commits into
masterfrom
fix/emulatorjs-save-slot-continuity
Jul 19, 2026
Merged

fix(player): keep origin save bound and surface save slots in v2 EmulatorJS#3831
gantoine merged 3 commits into
masterfrom
fix/emulatorjs-save-slot-continuity

Conversation

@gantoine

Copy link
Copy Markdown
Member

Description

Two related fixes to the v2 EmulatorJS player, both driven by the fact that the web player writes save files without a slot and could silently orphan a named-slot save.

1. Decouple save-file and savestate selection (behavior fix)

Previously, selecting (or auto-selecting) a savestate force-deselected the save file, and vice versa. When any compatible savestate existed, the config screen defaulted to the States tab and nulled the save. The consequence: "Save & Quit" then POSTed a brand-new slot-less save file instead of PUTting back to the named-slot save the session started from, so device-sync clients filtering by a named slot never saw that session's progress.

Now save and state are independent. The visible tab still defaults to States when a compatible state exists (quick-resume preserved), but the origin save stays bound to saveRef, so "Save & Quit" updates it in place. Both :save and :state are passed to the engine, which already supports loading save-then-state, so no v1 engine change was required.

2. Surface the save slot (visibility)

Added a brand-toned slot chip (SLOT · <name>) wherever a save renders:

  • AssetList (pre-game save list + GameDetails "Save data" subtab)
  • AssetPreview (the "resume from save" preview)
  • AssetCard (the in-game SelectSaveDialog picker)

Guarded with 'slot' in asset && asset.slot, so states (no slot column) and slot-less web saves render nothing. Adds the play.slot key across all 18 locales and wires slot into the story fixtures.

v1 (frozen) is left untouched; the change is v2-only.

Checklist

  • I've tested the changes locally
  • I've updated relevant comments
  • I've assigned reviewers for this PR
  • I've added unit tests that cover the changes

Verification: vue-tsc typecheck clean; i18n parity + sorted checks pass; Storybook composeStories tests 363 passed; trunk fmt + trunk check on all changed files clean. Not verified in a live emulator session (requires a real ROM + running backend).

Screenshots (if applicable)

Slot chips are visible in the AssetList / AssetCard / AssetPreview Storybook stories (fixtures now include a mix of named-slot and slot-less saves).


AI assistance disclosure

This change was implemented with AI assistance (Claude Code). The AI investigated the save/state wiring, wrote the code, translations, and story fixtures, and ran the verification steps above. All changes were directed and reviewed by the author.

🤖 Generated with Claude Code

…atorJS

Decouple save-file and savestate selection in the v2 player so they are no
longer mutually exclusive. When a compatible savestate exists, the config
screen still opens on the States tab, but the origin save now stays bound
instead of being nulled. This keeps "Save & Quit" updating that save file in
place (PUT) rather than spawning a new slot-less save (POST) that named-slot
sync clients never see.

Surface the save slot as a chip wherever a save renders (config-screen list,
resume preview, and the in-game save picker), guarded so states and slot-less
web saves show nothing. Adds the `play.slot` key across all locales and wires
`slot` into the story fixtures.

v1 (frozen) is left untouched; the change is v2-only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 19, 2026 16:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@greptile-apps

greptile-apps Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR keeps saves bound while loading states and displays named save slots in the v2 player. The main changes are:

  • Independent save and savestate selection in EmulatorJS.
  • Slot tags in asset cards, previews, and lists.
  • Slot translations across all supported locales.
  • Updated Storybook save fixtures.

Confidence Score: 4/5

Automatic dual selection can overwrite an unrelated named-slot save.

  • The slot tags and locale additions follow the existing component contracts.
  • A state session can write its SRAM into user_saves[0] without the user selecting that save.
  • The save binding needs an explicit or reliable association before it is used for PUT updates.

frontend/src/v2/views/Player/EmulatorJS.vue

Important Files Changed

Filename Overview
frontend/src/v2/views/Player/EmulatorJS.vue Allows a save and state to remain selected together, but can bind an unrelated first save as the write target.
frontend/src/v2/components/Player/AssetCard.vue Adds a guarded slot tag to save cards.
frontend/src/v2/components/Player/AssetPreview.vue Adds slot metadata to the selected-save preview.
frontend/src/v2/components/shared/AssetList.vue Displays named slots for save assets while excluding states and slot-less saves.
frontend/src/locales/en_US/play.json Adds the slot label mirrored across the changed locale files.

Fix All in Claude Code

Reviews (1): Last reviewed commit: "fix(player): keep origin save bound and ..." | Re-trigger Greptile

Comment thread frontend/src/v2/views/Player/EmulatorJS.vue Outdated
gantoine and others added 2 commits July 19, 2026 15:29
Only auto-bind a default save as the "Save & Quit" write-back target when
the choice is unambiguous (a single save, or no compatible state armed).
With multiple saves and a state armed, loading the state injects a
different SRAM timeline, so binding an arbitrary user_saves[0] let
Save & Quit PUT over a named slot the user never selected. In that case
leave the save unbound and require an explicit slot pick.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@gantoine
gantoine merged commit adfaf30 into master Jul 19, 2026
12 checks passed
@gantoine
gantoine deleted the fix/emulatorjs-save-slot-continuity branch July 19, 2026 19:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants