← 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
M games/flappy-sky/index.htmlM tests/motion.mjs
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 →