You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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:
varcardW=Math.min(560,W-80);// W=320 → cardW=240 → 80px per cellcx.font='bold 30px '+DCF;// "1840:00" at 30px exceeds 80pxcx.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…],
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.
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/strokeTextto capture the real bounding box of every text run, then driving the game to each result state. Chromium via Playwright,deviceScaleFactor: 1.Vertical overflow
All seven
gameOverReasonvalues overflow at 320×568; the surface screen is the only result state that fits.document.scrollTopstays 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
"1840:00"↔"38.4m""DIVE LOG"↔"DIVE COMPLETE"#touch-postdive-btn"56"↔#touch-torch"NDL","N₂"↔#touch-torch"PO2"↔#touch-dive-learnFive 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 atx = −107.Root cause
Unbounded vertical layout.
drawPostDive()(src/renderer.js:9268) anddrawGameOver()(src/renderer.js:9557) accumulateyin 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 theH * 0.07start offset and oneH * 0.25chart.Fixed-width stat cells.
src/renderer.js:9292:Copy hard-wrapped for desktop.
src/constants.js:588storessafetyExplas fixed-length lines, drawn centred atsrc/renderer.js:9432with nomaxWidthand never re-wrapped to the viewport:Notes
/(\d+(?:\.\d+)?)px/match, notparseFloat(ctx.font). The latter returns the numeric weight in"500 20px Barlow Semi Condensed"and silently reports 500 px-tall text boxes.