client: preload all art, cut mobile heat, rebuild responsive layout - #31
Merged
Merged
Conversation
Three related pieces of work on the player client. No slot-math changes. 1. Preload everything before the game reveals The "You won N Free Spins" panel streamed in part-by-part mid-game because its art is a CSS background on a display:none element, which browsers never fetch until the element is shown. The boot gate only waited on 12 hand-picked symbols. Now a uiAssets map routes every non-canvas image through the same loader, the gate waits on all of it decoded (image.decode(), not just onload), and <head> carries preload hints. Verified: 23 images fetch at boot, zero image requests afterwards. The ante plate had the same bug and is fixed too. decode() is skipped while document.hidden and capped at 2s — Chrome defers decoding for hidden documents, which otherwise hung the gate for 20s for a game opened in a background tab or an iframe that starts hidden. 2. Mobile thermals detectDeviceTier() had no mobile signal at all (deviceMemory is NaN on iOS and never demotes), so phones landed on "high" — idleThrottleMs 0, meaning a full 661-line draw() at 60fps forever, even idle. Handhelds are now capped at "mid", idle is throttled on every tier (60 -> 18fps measured), busy frames cap at 30fps on phones, and visibilitychange/pagehide cancel the rAF chain and suspend the AudioContext (previously nothing paused at all). Also: art re-encoded to WebP via the new tools/optimize-assets.js (12.9MB -> 513KB, -96%), memoized the two full-canvas gradients that were reallocated every frame, added a pre-scaled symbol sprite cache, debounced the ResizeObserver, raised win_tick minGap, made soul-trail emission framerate-independent, converted the bonus badge's infinite box-shadow pulse to a composited opacity fade, and deleted ~290 lines of unreachable ambiance CSS. 3. Responsive layout The reel grid was 16% of a 375x667 phone and collapsed to 2x2px in landscape. Causes: an unscoped max-width:520px rule stacked the player's control deck into a 235px tower; .altar-top being display:none in landscape promoted .altar-core into the `auto` grid row, so container-type:size had no definite height and cqh resolved to ~0; hard 1040px/920px width caps left ~440px of dead backdrop per side at 1920px; desktop forced 3/2 while the canvas draws 6/5; and overlays were positioned in raw px against the panel, not the grid. The stack is now one scaling container: flex columns throughout (immune to rows toggling hidden, which is what broke the old grid-template-rows), a single set of clamp()/vh/vmin scale tokens on .altar, and the board as the only growing row. Overlays anchor to --board-w/h/x/y, published from ReelCanvasRenderer.publishBoardBox(). Also removed a duplicate second declaration of .altar-core/.vault-shell/.vault-window - two sources of truth for the same boxes was why the sizing kept drifting. Measured on 11 breakpoints (320x568 through 1920x1080): grid fills 98-99% of width in portrait, landscape works, no overflow or clipping anywhere, badge anchored to the grid at every size. Note: npm run test:rtp-parity currently reports 95.62% vs a 96.38% target. The 12 engine files that test loads are byte-identical to HEAD and none of this touches them; it passed at 96.34% earlier on the same math. With a ~4700x max win, one top-end hit in 1M spins moves RTP ~0.47%, so the +-0.20% tolerance looks too tight at that sample size. Not yet confirmed by a repeated-run measurement. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BBWtAHqmoaiBy6E8eSg8y9
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.
Three related pieces of work on the player client. No slot-math changes.
decode() is skipped while document.hidden and capped at 2s — Chrome defers decoding for hidden documents, which otherwise hung the gate for 20s for a game opened in a background tab or an iframe that starts hidden.
Also: art re-encoded to WebP via the new tools/optimize-assets.js (12.9MB ->
513KB, -96%), memoized the two full-canvas gradients that were reallocated every frame, added a pre-scaled symbol sprite cache, debounced the ResizeObserver, raised win_tick minGap, made soul-trail emission framerate-independent, converted the bonus badge's infinite box-shadow pulse to a composited opacity fade, and deleted ~290 lines of unreachable ambiance CSS.
autogrid row, so container-type:size had no definite height and cqh resolved to ~0; hard 1040px/920px width caps left ~440px of dead backdrop per side at 1920px; desktop forced 3/2 while the canvas draws 6/5; and overlays were positioned in raw px against the panel, not the grid.The stack is now one scaling container: flex columns throughout (immune to rows toggling hidden, which is what broke the old grid-template-rows), a single set of clamp()/vh/vmin scale tokens on .altar, and the board as the only growing row. Overlays anchor to --board-w/h/x/y, published from ReelCanvasRenderer.publishBoardBox(). Also removed a duplicate second declaration of .altar-core/.vault-shell/.vault-window - two sources of truth for the same boxes was why the sizing kept drifting.
Measured on 11 breakpoints (320x568 through 1920x1080): grid fills 98-99% of width in portrait, landscape works, no overflow or clipping anywhere, badge anchored to the grid at every size.
Note: npm run test:rtp-parity currently reports 95.62% vs a 96.38% target. The 12 engine files that test loads are byte-identical to HEAD and none of this touches them; it passed at 96.34% earlier on the same math. With a ~4700x max win, one top-end hit in 1M spins moves RTP ~0.47%, so the +-0.20% tolerance looks too tight at that sample size. Not yet confirmed by a repeated-run measurement.
Claude-Session: https://claude.ai/code/session_01BBWtAHqmoaiBy6E8eSg8y9