refactor(v2): extract a shared player shell - #4301
Merged
Merged
Conversation
Contributor
Greptile SummaryThis PR extracts duplicated v2 player presentation and hero-state logic without changing the player lifecycle.
Confidence Score: 5/5The PR appears safe to merge, with no concrete changed-code-triggered failure identified. The extraction preserves the existing ROM fetch, hero seeding, playback lifecycle, navigation, scoped slot styling, and player-specific behavior across both consumers. Reviews (1): Last reviewed commit: "refactor(v2): extract a shared player sh..." | Re-trigger Greptile |
EmulatorJS.vue and Ruffle.vue each carry their own copy of the block every v2
player opens with: the synchronous hero seeding, title, platform label and
background-art watch. Ruffle additionally hand-rolls the cover column,
settings card, back buttons and loading spinner that any simple player needs.
Extract two seams:
* usePlayerHero — the seed/hero/title/platform-label block plus the
background-art watch, adopted by both players. The caller keeps ownership
of the `rom` ref because EmulatorJS needs a deep one for the save and
state lists it mutates.
* PlayerShell — the cover column, settings card, play and back buttons, the
full-bleed running stage and the loading state, with `settings`, `stage`
and `brand` slots. Ruffle keeps only its colour picker, brand strip and
stage. EmulatorJS deliberately opts out: its hero sits inside a card with
an alt-art glow and it lays out three panels on its own breakpoints, so it
takes the composable alone.
Stream.vue is left alone: its label comes from the streaming container, its
background art clears while playing, and it has its own back route.
No intended behaviour change. Ruffle's hand-rolled loading spinner is now
RSpinner, matching the other players.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The js-dos player landed on master with its own copy of the pre-game chrome. It now takes `usePlayerHero` and `PlayerShell` and keeps only the fullscreen switch, the browser-save note and its stage. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gantoine
force-pushed
the
refactor/v2-player-shell
branch
from
August 29, 2026 19:48
2aa9ee6 to
68168f8
Compare
greptile-apps
Bot
dismissed
their stale review
August 29, 2026 19:48
Dismissed because a newer commit was pushed; Greptile will re-review the current head.
Follow-up pass over the extraction: - `usePlayerNav` gives the two back links one home. EmulatorJS's copy read `rom.value?.id`, so it pushed undefined params during the seed window the hero seeding exists to cover. - EmulatorJS drops its hand-rolled spinner for `RSpinner` and takes `heroRom` for its render guard, so `heroSeed` leaves the composable's public surface. - The shell owns the full-width brand row instead of letting a consumer reach across the seam for `grid-column`. - Ruffle's rom ref is shallow, matching the other simple players. - `PlayerShell.test.ts` covers the play/quit emits, the missing-platform guard and the loading branch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Explain the changes or enhancements you are proposing with this pull request.
The v2 player views duplicate their chrome.
EmulatorJS.vue,Ruffle.vueandJsDos.vueeach carry their own copy of the block every player opens with (synchronous hero seeding, title, platform label, background-art watch), andRuffle.vueandJsDos.vueadditionally hand-roll the cover column, settings card, back buttons and loading spinner that any simple player needs.This extracts three seams:
usePlayerHero(src/v2/composables/usePlayerHero/) — the seed / hero / title / platform-label block plus the background-art watch. Adopted by all three players. The caller keeps ownership of theromref, because EmulatorJS needs a deep one for the save and state lists it mutates.PlayerShell(src/v2/components/Player/PlayerShell.vue) — the cover column, settings card, play and back buttons, the full-bleed running stage and the loading state, withsettings,stageandbrandslots. Ruffle keeps only its colour picker, brand strip and stage; js-dos keeps only its fullscreen switch, browser-save note and stage.usePlayerNav(src/v2/composables/usePlayerNav/) — the two back links, shared by the shell and by EmulatorJS. EmulatorJS's copy navigated offrom.value?.id, so it pushedundefinedparams during exactly the seed window the hero seeding exists to cover; it now uses the route id like the shell does.EmulatorJS.vuedeliberately opts out ofPlayerShell: its hero sits inside a card with an alt-art glow and it lays out three panels on its own breakpoints. It takes the composables alone, and while it was open it also drops its hand-rolled@keyframesspinner forRSpinner.Stream.vueis left alone: its label comes from the streaming container, its background art clears while playing, and it has its own back route.Net -638 / +558 across nine files, and the duplication is gone rather than moved.
Why now: this fell out of a cleanup pass on #4061 (js-dos player), which landed as a third near-verbatim copy of the same chrome —
JsDos.vueandRuffle.vueshared ~245 lines. Now that #4061 is onmaster, this PR is rebased on it and convertsJsDos.vuetoo, soPlayerShellgains its second consumer here.Behaviour: no intended change. The one visible difference is that Ruffle's hand-rolled loading spinner is now
RSpinner, matching the other players (same 40px / 2px / brand-coloured arc, and it drops a bespoke@keyframes). The js-dos view keeps its own quit/save flow, route-leave guard andbeforeunloadwarning; only its chrome moves into the shell.Checklist
Please check all that apply.
Verified:
npm run typecheck,npm run test(838 tests / 74 files),npm run buildandtrunk fmt && trunk checkall pass.PlayerShell.test.tsis new and covers the play/quit emits, the missing-platform guard and the loading branch;JsDos.test.ts's 15 existing cases move their selectors onto the shell's classes. Not yet exercised in a browser, and since the change moves scoped CSS into a child component that is where a regression would hide: the Ruffle and js-dos pre-game panels and running stages want a look in both themes before merge.Screenshots (if applicable)
n/a
AI assistance: this PR was written with Claude Code (Opus 5). The duplication was identified by an automated review pass over #4061; the extraction, the decision on which views adopt which seam, and the verification above were carried out by the agent under my direction and reviewed by me.