← back to Games Agentabrams
Trivia + Runner share payloads now link to 90210.agentabrams.com hub
b51f468f646f87b3dd69281722144194466a5cc1 · 2026-07-25 10:07:12 -0700 · Steve Abrams
Files touched
M games/flappy-sky/index.htmlM games/particle-text-starling/index.htmlM games/rodeo-runner/RodeoDriveRunner.aaM games/trivia-90210/90210Trivia.aaM index.htmlM tests/popout.mjs
Diff
commit b51f468f646f87b3dd69281722144194466a5cc1
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sat Jul 25 10:07:12 2026 -0700
Trivia + Runner share payloads now link to 90210.agentabrams.com hub
---
games/flappy-sky/index.html | 23 +----------------------
games/particle-text-starling/index.html | 2 ++
games/rodeo-runner/RodeoDriveRunner.aa | 5 +++--
games/trivia-90210/90210Trivia.aa | 9 +++++----
index.html | 7 +++++--
tests/popout.mjs | 23 +++++++++++++++++++++++
6 files changed, 39 insertions(+), 30 deletions(-)
diff --git a/games/flappy-sky/index.html b/games/flappy-sky/index.html
index 9e3f044..3350124 100644
--- a/games/flappy-sky/index.html
+++ b/games/flappy-sky/index.html
@@ -20,22 +20,8 @@
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;
@@ -185,7 +171,6 @@
</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>
@@ -217,14 +202,12 @@
<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 -------------------------------------------------------
@@ -251,12 +234,8 @@
let W, H, scale, groundH;
function resize() {
const dpr = Math.min(window.devicePixelRatio || 1, 2.5);
- // 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.
+ W = window.innerWidth;
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/games/particle-text-starling/index.html b/games/particle-text-starling/index.html
index 9752e14..a00ed8b 100644
--- a/games/particle-text-starling/index.html
+++ b/games/particle-text-starling/index.html
@@ -4,6 +4,8 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Particle Text</title>
+<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='7' fill='%2305060a'/%3E%3Ccircle cx='16' cy='16' r='6.5' fill='%238fd3ff'/%3E%3Ccircle cx='16' cy='16' r='11' fill='none' stroke='%23b7a6ff' stroke-width='1.2' opacity='.6'/%3E%3C/svg%3E">
+<link rel="apple-touch-icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%2305060a'/%3E%3Ccircle cx='16' cy='16' r='7' fill='%238fd3ff'/%3E%3C/svg%3E">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { height: 100%; overflow: hidden; background: #05060a; }
diff --git a/games/rodeo-runner/RodeoDriveRunner.aa b/games/rodeo-runner/RodeoDriveRunner.aa
index 7e003a2..d1b92ea 100644
--- a/games/rodeo-runner/RodeoDriveRunner.aa
+++ b/games/rodeo-runner/RodeoDriveRunner.aa
@@ -352,8 +352,9 @@ canvas{ display:block; width:100%; height:100%; touch-action:none; }
function share(){
var s=Math.round(score);
var text="I cruised Rodeo Drive for "+s.toLocaleString()+" points in Rodeo Drive Runner. 🏎️💎 Beat me on 90210 row!";
- if(navigator.share){ navigator.share({title:"Rodeo Drive Runner",text:text}).catch(function(){}); }
- else if(navigator.clipboard){ navigator.clipboard.writeText(text).then(function(){ document.getElementById("shareLine").textContent="📋 Score copied."; }).catch(function(){}); }
+ var url="https://90210.agentabrams.com/#rodeo-runner";
+ if(navigator.share){ navigator.share({title:"Rodeo Drive Runner",text:text,url:url}).catch(function(){}); }
+ else if(navigator.clipboard){ navigator.clipboard.writeText(text+" "+url).then(function(){ document.getElementById("shareLine").textContent="📋 Score + link copied."; }).catch(function(){}); }
}
// ---- wire ----
diff --git a/games/trivia-90210/90210Trivia.aa b/games/trivia-90210/90210Trivia.aa
index 11f8cdf..9a67ace 100644
--- a/games/trivia-90210/90210Trivia.aa
+++ b/games/trivia-90210/90210Trivia.aa
@@ -533,13 +533,14 @@ body{
var pct = Math.round(100 * correctCount / deck.length);
var rk = rankFor(pct, score);
var text = "I scored " + score + " on 90210 Trivia — " + rk.t + " (" + pct + "% right). Can you beat the Zip? 🌴💎";
+ var url = "https://90210.agentabrams.com/#trivia-90210";
if(navigator.share){
- navigator.share({ title:"90210 Trivia", text:text }).catch(function(){});
+ navigator.share({ title:"90210 Trivia", text:text, url:url }).catch(function(){});
} else if(navigator.clipboard && navigator.clipboard.writeText){
- navigator.clipboard.writeText(text).then(function(){ $("shareNote").textContent = "📋 Score copied — paste it anywhere."; })
- .catch(function(){ $("shareNote").textContent = text; });
+ navigator.clipboard.writeText(text + " " + url).then(function(){ $("shareNote").textContent = "📋 Score + link copied — paste it anywhere."; })
+ .catch(function(){ $("shareNote").textContent = text + " " + url; });
} else {
- $("shareNote").textContent = text;
+ $("shareNote").textContent = text + " " + url;
}
}
diff --git a/index.html b/index.html
index 52e5fbf..c7eb6ac 100644
--- a/index.html
+++ b/index.html
@@ -50,8 +50,11 @@
background: none; border: 1px solid transparent; border-radius: 6px; padding: 4px 6px;
transition: opacity .15s, background .15s, color .15s;
}
- .game:hover .popout, .game.active .popout { opacity: .8; }
- .game .popout:hover { opacity: 1; color: #ffd23e; background: #1b2030; border-color: #3d4763; }
+ /* reveal on hover, on the active row, AND on keyboard focus so tab users can
+ see + reach the pop-out (a11y: it was invisible to keyboard nav before). */
+ .game:hover .popout, .game.active .popout, .game:focus-within .popout { opacity: .8; }
+ .game .popout:hover, .game .popout:focus-visible { opacity: 1; color: #ffd23e; background: #1b2030; border-color: #3d4763; }
+ .game .popout:focus-visible { outline: 2px solid #ffd23e; outline-offset: 1px; }
/* stage pop-out for the current game */
#popCurrent {
position: absolute; top: 12px; right: 12px; z-index: 5; cursor: pointer; text-decoration: none;
diff --git a/tests/popout.mjs b/tests/popout.mjs
index fe2a533..96af252 100644
--- a/tests/popout.mjs
+++ b/tests/popout.mjs
@@ -66,6 +66,29 @@ if (popup) {
ok(/rope-physics/.test(popup.url()), 'new window loaded the rope-physics game: ' + popup.url());
}
+// 4. a plain click on a SIDEBAR pop-out actually opens a new window too
+// (guards against the theory that stopPropagation() on the row kills the
+// anchor's fallback navigation — it does not: stopPropagation != preventDefault)
+const [sidePopup] = await Promise.all([
+ ctx.waitForEvent('page', { timeout: 4000 }).catch(() => null),
+ page.click('.game .popout'), // first row's pop-out anchor
+]);
+ok(!!sidePopup, 'clicking a sidebar pop-out opened a new browser window');
+if (sidePopup) {
+ await sidePopup.waitForLoadState('domcontentloaded').catch(() => {});
+ ok(/\/games\/.+\//.test(sidePopup.url()), 'sidebar pop-out loaded a standalone game page: ' + sidePopup.url());
+}
+
+// 5. a11y: keyboard focus on a sidebar pop-out makes it visible (was opacity:0).
+// Wait out the .15s opacity transition before sampling (it animates 0 -> .8).
+await page.evaluate(() => { document.querySelector('.game .popout').focus(); });
+await page.waitForFunction(
+ () => parseFloat(getComputedStyle(document.querySelector('.game .popout')).opacity) > 0.5,
+ { timeout: 1000 }
+).catch(() => {});
+const focusedOpacity = await page.evaluate(() => getComputedStyle(document.querySelector('.game .popout')).opacity);
+ok(parseFloat(focusedOpacity) > 0.5, `keyboard-focused pop-out is visible (opacity ${focusedOpacity}, was 0)`);
+
await browser.close();
server.close();
console.log(fail ? `\n${fail} FAILURE(S)` : '\nALL GREEN');
← 79106c9 auto-save: 2026-07-25T10:05:29 (2 files) — games/rodeo-runne
·
back to Games Agentabrams
·
Fix: Runner had no Share button (share() was dead code) — ad 47b2f29 →