[object Object]

← back to Games Agentabrams

flappy-sky: restore portrait-column fix (sync reverted it) + desktop-scale regression guard

989a1b25db683d09ce0075ae63a855c02d29fdfd · 2026-07-25 10:15:29 -0700 · Steve Abrams

A parallel sync.sh re-copied the unpatched standalone source over the arcade
index.html, reverting commit 589241e's fix (the .aa kept it). Restore index.html
from the fixed .aa and add a 1440x900 canvas-width assertion to tests/motion.mjs
for the flappy family — the animation loop runs at a phone viewport where the
stretch bug can't manifest, so nothing caught the revert. Standalone source
patched in a companion commit so future syncs don't revert again.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit 989a1b25db683d09ce0075ae63a855c02d29fdfd
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sat Jul 25 10:15:29 2026 -0700

    flappy-sky: restore portrait-column fix (sync reverted it) + desktop-scale regression guard
    
    A parallel sync.sh re-copied the unpatched standalone source over the arcade
    index.html, reverting commit 589241e's fix (the .aa kept it). Restore index.html
    from the fixed .aa and add a 1440x900 canvas-width assertion to tests/motion.mjs
    for the flappy family — the animation loop runs at a phone viewport where the
    stretch bug can't manifest, so nothing caught the revert. Standalone source
    patched in a companion commit so future syncs don't revert again.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 games/flappy-sky/index.html | 23 ++++++++++++++++++++++-
 tests/motion.mjs            | 26 ++++++++++++++++++++++++--
 2 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/games/flappy-sky/index.html b/games/flappy-sky/index.html
index 3350124..9e3f044 100644
--- a/games/flappy-sky/index.html
+++ b/games/flappy-sky/index.html
@@ -20,8 +20,22 @@
     touch-action: none;
   }
 
+  /* Portrait play-column: flappy is tuned for a phone-shaped field, so cap the
+     stage to a ~2:3 column centered in the window (letterboxed on desktop,
+     full-width on phones). JS sets #stage width; everything else is inset:0
+     to it so the HUD + overlay track the play area, not the whole window. */
+  #stage {
+    position: absolute;
+    top: 0;
+    left: 50%;
+    transform: translateX(-50%);
+    height: 100%;
+    overflow: hidden;
+  }
   canvas {
     display: block;
+    width: 100%;
+    height: 100%;
     background: radial-gradient(circle at 20% 20%, #586df2 0, #243046 40%, #0e1018 100%);
     /* keeps focus outline from ever painting a box around the game */
     outline: none;
@@ -171,6 +185,7 @@
 </style>
 </head>
 <body>
+<div id="stage">
 <canvas id="game" tabindex="-1" aria-label="Flappy Sky game canvas"></canvas>
 
 <div id="scoreTop" class="hidden"><span id="scoreVal">0</span></div>
@@ -202,12 +217,14 @@
 <div id="pauseVeil">Paused</div>
 
 <div id="smallInfo">Space / Click / Tap · P pause · M mute</div>
+</div><!-- /#stage -->
 
 <script>
 (function () {
   "use strict";
 
   const canvas = document.getElementById("game");
+  const stage = document.getElementById("stage");
   const ctx = canvas.getContext("2d", { alpha: false });
 
   // ---- DOM refs -------------------------------------------------------
@@ -234,8 +251,12 @@
   let W, H, scale, groundH;
   function resize() {
     const dpr = Math.min(window.devicePixelRatio || 1, 2.5);
-    W = window.innerWidth;
+    // Cap the playfield to a ~2:3 portrait column so the phone-tuned physics
+    // stay playable on wide desktop windows (letterboxed) while phones still
+    // fill their full width. #stage is centered via CSS; the canvas fills it.
     H = window.innerHeight;
+    W = Math.min(window.innerWidth, Math.round(H * 0.66));
+    stage.style.width = W + "px";
     canvas.width  = Math.round(W * dpr);
     canvas.height = Math.round(H * dpr);
     ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
diff --git a/tests/motion.mjs b/tests/motion.mjs
index 80f16e3..900881c 100644
--- a/tests/motion.mjs
+++ b/tests/motion.mjs
@@ -104,9 +104,31 @@ for (const g of GAMES) {
   await ctx.close();
 }
 
+// Desktop-scale guard: the portrait-tuned flappy games must render as a capped
+// portrait COLUMN on a wide desktop, not stretch to fill the window (which made
+// flappy-sky an ultra-wide field with one tiny bird). The animation loop above
+// runs at a phone viewport where this bug can't manifest — this block is the
+// only thing that catches a sync/edit revert of the #stage aspect cap.
+const PORTRAIT = ['flappy-sky', 'flappy-clone', 'flappy-flight'];
+const dctx = await browser.newContext({ viewport: { width: 1440, height: 900 } });
+for (const g of PORTRAIT) {
+  const page = await dctx.newPage();
+  let w = null;
+  try {
+    await page.goto(`${base}/games/${g}/`, { waitUntil: 'networkidle', timeout: 15000 });
+    await page.waitForTimeout(200);
+    w = await page.evaluate(() => { const c = document.querySelector('canvas'); return c ? Math.round(c.getBoundingClientRect().width) : null; });
+  } catch (e) { /* leaves w null -> fails below */ }
+  const ok = w !== null && w < 800; // portrait column, not a 1440-wide stretch
+  results.push({ g: `${g}@desktop-scale`, ok, errs: [] });
+  console.log(`${ok ? 'PASS' : 'FAIL'}  ${g}@desktop-scale  (canvas ${w}px wide at 1440 viewport; want <800)`);
+  await page.close();
+}
+await dctx.close();
+
 await browser.close();
 server.close();
 const failed = results.filter(r => !r.ok);
-console.log(`\n${results.length - failed.length}/${results.length} moving games animate`);
-if (failed.length) console.log('FROZEN:', failed.map(r => r.g).join(', '));
+console.log(`\n${results.length - failed.length}/${results.length} checks passed`);
+if (failed.length) console.log('FAILED:', failed.map(r => r.g).join(', '));
 process.exit(failed.length ? 1 : 0);

← 47b2f29 Fix: Runner had no Share button (share() was dead code) — ad  ·  back to Games Agentabrams  ·  hopper + tower-stack: fix desktop scale c13d678 →