Skip to content

[Bug] Post-dive and game-over screens overflow the viewport with no way to scroll #120

Description

@N1k4G

The post-dive and game-over screens draw more content than fits the viewport, and because they are painted onto the canvas inside html, body { overflow: hidden }, none of the overflow is reachable. Several text runs also collide with each other and with the touch buttons.

Both symptoms share one root cause — the draw functions lay out in absolute pixels without ever consulting the viewport — so they're filed together.

Reproduction

Instrumented by wrapping CanvasRenderingContext2D.fillText / strokeText to capture the real bounding box of every text run, then driving the game to each result state. Chromium via Playwright, deviceScaleFactor: 1.

Vertical overflow

Viewport Screen Ink maxY Overflow Runs below fold
320×568 surface 485 −83 px 0
320×568 post-dive 914 +346 px 48
390×844 post-dive 1002 +158 px 42
844×390 post-dive 857 +467 px 62
320×568 game-over · narcosis 1006 +438 px 50
320×568 game-over · DCS 852 +284 px 32
320×568 game-over · shark 649 +81 px 8

All seven gameOverReason values overflow at 320×568; the surface screen is the only result state that fits. document.scrollTop stays 0 in every case — there is no scroll surface to reach the rest.

The entire tissue-compartment loading chart begins at y ≈ 756 on a 568 px viewport, so on a small phone it is drawn and never seen.

Overlap and horizontal clipping

Where Colliding pair Overlap Viewport
Post-dive stat row "1840:00""38.4m" 6 × 30 px 320×568
Post-dive header "DIVE LOG""DIVE COMPLETE" 53 × 3 px 320, 390
Post-dive advisory 3 body lines ↔ #touch-postdive-btn 243 × 12 px 320×568
Dive HUD "56"#touch-torch 33 × 34 px 844×390
Dive HUD "NDL", "N₂"#touch-torch 19 × 12 px 844×390
Dive HUD "PO2"#touch-dive-learn 13 × 10 px 844×390

Five post-dive advisory lines measure 383–416 px on a 320 px viewport and bleed off both edges. The in-dive hint "W/S control BCD buoyancy…" measures 534 px and starts at x = −107.

Root cause

Unbounded vertical layout. drawPostDive() (src/renderer.js:9268) and drawGameOver() (src/renderer.js:9557) accumulate y in fixed pixel increments — y += 30, y += cardH + 20, y += dbH + 18 — with no clamp, no scale-to-fit, and no scroll surface. Nothing in either function reads the viewport height except the H * 0.07 start offset and one H * 0.25 chart.

Fixed-width stat cells. src/renderer.js:9292:

var cardW = Math.min(560, W - 80);   // W=320 → cardW=240 → 80px per cell
cx.font = 'bold 30px ' + DCF;        // "1840:00" at 30px exceeds 80px
cx.fillText(statCells[sc][1], sccx, y + 63);   // no maxWidth, no fitting

Copy hard-wrapped for desktop. src/constants.js:588 stores safetyExpl as fixed-length lines, drawn centred at src/renderer.js:9432 with no maxWidth and never re-wrapped to the viewport:

safetyExpl: [
  'A safety stop helps off-gas dissolved nitrogen and reduces',
  // …4 more fixed-length lines…
],

Notes

  • Not a regression from feat: WP-07 site and asset pipeline #119 — that PR touches none of these files.
  • If anyone re-runs this instrumentation: read font size with a /(\d+(?:\.\d+)?)px/ match, not parseFloat(ctx.font). The latter returns the numeric weight in "500 20px Barlow Semi Condensed" and silently reports 500 px-tall text boxes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions