← back to Games Agentabrams
auto-save: 2026-07-24T07:56:29 (1 files) — index.html
3e43c0fc46465bd5637f581cb14763fe81a40883 · 2026-07-24 07:56:40 -0700 · Steve Abrams
Files touched
Diff
commit 3e43c0fc46465bd5637f581cb14763fe81a40883
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Fri Jul 24 07:56:40 2026 -0700
auto-save: 2026-07-24T07:56:29 (1 files) — index.html
---
index.html | 196 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 196 insertions(+)
diff --git a/index.html b/index.html
index 717be6b..55a7e43 100644
--- a/index.html
+++ b/index.html
@@ -58,9 +58,68 @@
#panel { width: 100%; min-width: 0; height: auto; max-height: 45%; }
#panel footer { display: none; }
}
+ /* ---- onload hero: fireworks motion-graphics splash ---- */
+ #hero {
+ position: fixed; inset: 0; z-index: 9999; background: #06070c;
+ display: flex; flex-direction: column; align-items: center; justify-content: center;
+ overflow: hidden; cursor: pointer; transition: opacity .55s ease;
+ }
+ #hero.hide { opacity: 0; pointer-events: none; }
+ #herofx { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
+ #hero .wrap {
+ position: relative; z-index: 2; text-align: center; pointer-events: none; padding: 20px;
+ animation: heroin 1s cubic-bezier(.2,.9,.2,1) both;
+ }
+ @keyframes heroin {
+ 0% { transform: scale(.55); opacity: 0; filter: blur(10px); }
+ 60% { opacity: 1; }
+ 100% { transform: scale(1); opacity: 1; filter: blur(0); }
+ }
+ #hero h1 {
+ margin: 0; font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
+ font-weight: 800; letter-spacing: 6px; color: #fff; line-height: 1.04;
+ font-size: clamp(30px, 7.5vw, 76px);
+ text-shadow: 0 0 18px rgba(124,92,255,.9), 0 0 44px rgba(124,92,255,.5);
+ }
+ #hero h1 .a { color: #7c5cff; }
+ #hero .tag {
+ margin-top: 16px; font-family: ui-monospace, Menlo, monospace;
+ font-size: clamp(11px, 2vw, 15px); letter-spacing: 4px; color: #aeb7c7; opacity: .85;
+ }
+ #hero .enter {
+ margin-top: 34px; pointer-events: auto; cursor: pointer;
+ font-family: ui-monospace, Menlo, monospace; font-weight: 700; letter-spacing: 2px;
+ font-size: 15px; color: #06070c; background: #ffd23e; border: 0; border-radius: 999px;
+ padding: 13px 32px; opacity: 0; transition: opacity .5s ease;
+ animation: heropulse 1.15s ease-in-out infinite;
+ }
+ #hero .enter.show { opacity: 1; } /* reveal driven by JS, not animation-fill */
+ @keyframes heropulse {
+ 0%,100% { transform: scale(1); box-shadow: 0 0 24px rgba(255,210,62,.55); }
+ 50% { transform: scale(1.06); box-shadow: 0 0 42px rgba(255,210,62,.9); }
+ }
+ #hero .skip {
+ position: absolute; bottom: 16px; right: 18px; z-index: 3; pointer-events: auto;
+ cursor: pointer; font-family: ui-monospace, monospace; font-size: 11px; letter-spacing: 1px;
+ color: #8ea; opacity: .45; background: none; border: 0;
+ }
+ #hero .skip:hover { opacity: .9; }
+ @media (prefers-reduced-motion: reduce) {
+ #hero .wrap { animation: none; }
+ #hero .enter { animation: none; opacity: 1; }
+ }
</style>
</head>
<body>
+<div id="hero">
+ <canvas id="herofx"></canvas>
+ <div class="wrap">
+ <h1>AGENT <span class="a">ABRAMS</span><br>ARCADE</h1>
+ <div class="tag">▶ PRESS START</div>
+ <button class="enter" id="heroEnter">ENTER ARCADE</button>
+ </div>
+ <button class="skip" id="heroSkip">skip ✕</button>
+</div>
<aside id="panel">
<div id="brand">
<h1><span class="dot">●</span> AGENT ABRAMS ARCADE</h1>
@@ -121,5 +180,142 @@
});
})();
</script>
+<script>
+/* ---- Onload hero: canvas fireworks / explosion motion graphics ---- */
+(function () {
+ var hero = document.getElementById('hero');
+ if (!hero) return;
+ var cv = document.getElementById('herofx');
+ var ctx = cv.getContext('2d');
+ var W = 0, H = 0, dpr = 1;
+ var COLORS = ['#7c5cff', '#ff4d9d', '#ffd23e', '#3ddc97', '#37c7ff', '#ff7847', '#ffffff'];
+ var rockets = [], parts = [], flash = 0;
+ var running = true, dismissed = false, t0 = performance.now(), spawnAt = 0;
+
+ function resize() {
+ dpr = Math.min(window.devicePixelRatio || 1, 2);
+ W = cv.clientWidth; H = cv.clientHeight;
+ cv.width = Math.floor(W * dpr); cv.height = Math.floor(H * dpr);
+ ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
+ }
+ window.addEventListener('resize', resize);
+
+ function rand(a, b) { return a + Math.random() * (b - a); }
+ function pick(a) { return a[(Math.random() * a.length) | 0]; }
+
+ function launchRocket(tx, ty) {
+ var sx = tx != null ? tx : rand(W * 0.15, W * 0.85);
+ var targetY = ty != null ? ty : rand(H * 0.15, H * 0.5);
+ var sy = H + 8;
+ var dur = rand(38, 58); // frames to apex
+ rockets.push({
+ x: sx, y: sy, vy: (targetY - sy) / dur, targetY: targetY,
+ col: pick(COLORS), trail: []
+ });
+ }
+
+ function explode(x, y, col, big) {
+ var n = big ? 90 : (34 + (Math.random() * 40 | 0));
+ var base = rand(2.2, 4.6) * (big ? 1.5 : 1);
+ var hueSpread = Math.random() < 0.4; // some bursts are multi-color
+ for (var i = 0; i < n; i++) {
+ var a = (Math.PI * 2 * i) / n + rand(-0.12, 0.12);
+ var sp = base * rand(0.35, 1);
+ parts.push({
+ x: x, y: y,
+ vx: Math.cos(a) * sp, vy: Math.sin(a) * sp,
+ col: hueSpread ? pick(COLORS) : col,
+ life: 1, decay: rand(0.008, 0.02) * (big ? 0.7 : 1),
+ r: rand(1.4, 2.8), tw: rand(0, Math.PI * 2)
+ });
+ }
+ flash = Math.min(1, flash + (big ? 0.5 : 0.22));
+ }
+
+ function step() {
+ // motion-blur trail: translucent fill instead of clear
+ ctx.globalCompositeOperation = 'source-over';
+ ctx.fillStyle = 'rgba(6,7,12,0.28)';
+ ctx.fillRect(0, 0, W, H);
+ ctx.globalCompositeOperation = 'lighter';
+
+ // rockets
+ for (var i = rockets.length - 1; i >= 0; i--) {
+ var r = rockets[i];
+ r.x += 0; r.y += r.vy; r.vy += 0.02; // slight decel
+ r.trail.push({ x: r.x, y: r.y }); if (r.trail.length > 6) r.trail.shift();
+ ctx.strokeStyle = r.col; ctx.lineWidth = 2; ctx.beginPath();
+ for (var k = 0; k < r.trail.length; k++) {
+ var p = r.trail[k]; if (k === 0) ctx.moveTo(p.x, p.y); else ctx.lineTo(p.x, p.y);
+ }
+ ctx.stroke();
+ ctx.fillStyle = '#fff'; ctx.beginPath(); ctx.arc(r.x, r.y, 2.2, 0, 7); ctx.fill();
+ if (r.y <= r.targetY || r.vy >= 0) { explode(r.x, r.y, r.col, Math.random() < 0.18); rockets.splice(i, 1); }
+ }
+
+ // particles
+ for (var j = parts.length - 1; j >= 0; j--) {
+ var q = parts[j];
+ q.vx *= 0.985; q.vy = q.vy * 0.985 + 0.045; // drag + gravity
+ q.x += q.vx; q.y += q.vy; q.life -= q.decay; q.tw += 0.3;
+ if (q.life <= 0) { parts.splice(j, 1); continue; }
+ var tw = 0.6 + 0.4 * Math.sin(q.tw);
+ ctx.globalAlpha = Math.max(0, q.life) * tw;
+ ctx.fillStyle = q.col;
+ ctx.beginPath(); ctx.arc(q.x, q.y, q.r, 0, 7); ctx.fill();
+ }
+ ctx.globalAlpha = 1;
+
+ // screen flash
+ if (flash > 0) {
+ ctx.globalCompositeOperation = 'source-over';
+ ctx.fillStyle = 'rgba(255,255,255,' + (flash * 0.10) + ')';
+ ctx.fillRect(0, 0, W, H);
+ flash *= 0.9; if (flash < 0.01) flash = 0;
+ }
+ }
+
+ function loop(now) {
+ if (!running) return;
+ var t = now - t0;
+ // cadence of launches, faster during the opening beat
+ if (now > spawnAt) { launchRocket(); spawnAt = now + (t < 2500 ? rand(220, 420) : rand(420, 780)); }
+ step();
+ requestAnimationFrame(loop);
+ }
+
+ function dismiss() {
+ if (dismissed) return; dismissed = true;
+ // celebratory finale
+ for (var i = 0; i < 7; i++) explode(rand(W * 0.15, W * 0.85), rand(H * 0.2, H * 0.6), pick(COLORS), i % 2 === 0);
+ hero.classList.add('hide');
+ setTimeout(function () {
+ running = false;
+ hero.style.display = 'none';
+ // hand keyboard focus back to the game iframe (keyboard-primary games need it)
+ var f = document.getElementById('frame');
+ if (f) { try { f.focus(); if (f.contentWindow) f.contentWindow.focus(); } catch (e) {} }
+ }, 620);
+ }
+
+ hero.addEventListener('click', dismiss);
+ hero.addEventListener('touchstart', function (e) { e.preventDefault(); dismiss(); }, { passive: false });
+ window.addEventListener('keydown', function (e) {
+ if (dismissed) return;
+ if (e.key === 'Enter' || e.key === ' ' || e.code === 'Space' || e.key === 'Escape') { e.preventDefault(); dismiss(); }
+ });
+
+ resize();
+ // reveal the ENTER button after the title lands (JS, so it works even when
+ // CSS animations are suppressed by prefers-reduced-motion / headless)
+ var enterBtn = document.getElementById('heroEnter');
+ if (enterBtn) setTimeout(function () { enterBtn.classList.add('show'); }, 1600);
+ // opening barrage so the splash lands with a bang
+ for (var b = 0; b < 3; b++) setTimeout(launchRocket, b * 180);
+ requestAnimationFrame(loop);
+ // auto-enter after a beat so the splash is never a wall
+ setTimeout(dismiss, 9000);
+})();
+</script>
</body>
</html>
← d6f86bc Arcade: correctly label all games; add my Flappy Clone along
·
back to Games Agentabrams
·
Add Abrams Blocks (Tetris) to the arcade — a genuinely diffe 8784aaf →