Repository navigation
Expand file tree
/
Copy pathindex.html
More file actions
317 lines (286 loc) · 21.3 KB
/
Copy pathindex.html
File metadata and controls
317 lines (286 loc) · 21.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>FUCAD ARCADE — A public good, not a product</title>
<meta name="description" content="Open-source, ad-free, free-forever casual games. No ads, no paywalls, no data harvesting. Insert no coin.">
<meta property="og:title" content="FUCAD ARCADE">
<meta property="og:description" content="Open-source, ad-free, free-forever casual games. Insert no coin.">
<meta property="og:type" content="website">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&family=VT323&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<style>
*{box-sizing:border-box}
body{margin:0;background:#06090c;font-family:'JetBrains Mono',ui-monospace,monospace;color:#cfeaf1}
a{color:#5ad1e6;text-decoration:none}a:hover{color:#8ee6f4}
::selection{background:#5ad1e6;color:#04252c}
.crt-scan{position:absolute;inset:0;pointer-events:none;background:repeating-linear-gradient(180deg,rgba(0,0,0,0) 0 2px,rgba(0,0,0,.28) 2px 4px);mix-blend-mode:multiply;z-index:3}
.crt-vig{position:absolute;inset:0;pointer-events:none;box-shadow:inset 0 0 120px 20px rgba(0,0,0,.7);z-index:2}
@keyframes flick{0%,96%,100%{opacity:1}97%{opacity:.82}98%{opacity:.94}}
@keyframes blink{0%,49%{opacity:1}50%,100%{opacity:0}}
@keyframes scrollmarq{0%{transform:translateX(0)}100%{transform:translateX(-50%)}}
.blink{animation:blink 1s steps(1) infinite}
[hidden]{display:none !important}
/* The design is authored desktop-first; below ~720px the nav row overflows. */
@media (max-width:720px){
nav{padding:12px 16px !important;gap:12px !important;flex-wrap:wrap}
#nav-logo{font-size:12px !important;gap:6px !important}
#nav-links{gap:6px !important}
#nav-links a{padding:7px 9px !important;font-size:10px !important}
}
@media (prefers-reduced-motion:reduce){
*{animation:none !important}
html{scroll-behavior:auto}
}
</style>
</head>
<body>
<div style="min-height:100vh;background:radial-gradient(130% 80% at 50% -10%,#0f1e25 0%,#06090c 60%)">
<!-- ===== NAV ===== -->
<nav style="position:sticky;top:0;z-index:20;display:flex;align-items:center;justify-content:space-between;gap:20px;padding:16px 34px;background:rgba(6,9,12,.82);backdrop-filter:blur(8px);border-bottom:2px solid rgba(90,209,230,.28)">
<a href="#home" data-nav="home" id="nav-logo" style="font-family:'Press Start 2P',monospace;font-size:15px;color:#5ad1e6;letter-spacing:.04em;display:flex;align-items:center;gap:10px">▛ FUCAD <span style="color:#eafcff">ARCADE</span> ▜</a>
<div id="nav-links" style="display:flex;gap:8px;align-items:center;flex-wrap:wrap"></div>
</nav>
<!-- ===== HOME ===== -->
<div data-page="home">
<!-- hero cabinet -->
<div style="padding:46px 24px 8px;display:flex;justify-content:center">
<div style="width:100%;max-width:1080px;position:relative;background:#06090c;padding:22px;border-radius:10px;animation:flick 6s infinite">
<div style="border:2px solid rgba(90,209,230,.4);border-radius:8px;background:linear-gradient(180deg,#0e1a20,#0a0d11);position:relative;overflow:hidden">
<!-- scrolling marquee strip -->
<div style="border-bottom:2px solid rgba(90,209,230,.4);background:rgba(90,209,230,.07);overflow:hidden;white-space:nowrap">
<div style="display:inline-block;animation:scrollmarq 22s linear infinite;font-family:'Press Start 2P',monospace;font-size:11px;color:#5ad1e6;padding:13px 0">
<span style="padding:0 26px">A PUBLIC GOOD — NOT A PRODUCT</span>·<span style="padding:0 26px">INSERT NO COIN</span>·<span style="padding:0 26px">FREE · OPEN-SOURCE · AD-FREE FOREVER</span>·<span style="padding:0 26px">A PUBLIC GOOD — NOT A PRODUCT</span>·<span style="padding:0 26px">INSERT NO COIN</span>·<span style="padding:0 26px">FREE · OPEN-SOURCE · AD-FREE FOREVER</span>·
</div>
</div>
<div style="padding:70px 40px 60px;text-align:center;position:relative;z-index:4">
<div style="font-family:'Press Start 2P',monospace;font-size:clamp(46px,9vw,104px);line-height:1;color:#eafcff;text-shadow:0 0 20px rgba(90,209,230,.5),0 0 3px #5ad1e6;display:flex;justify-content:center;align-items:center;gap:.04em">FUC<span style="filter:blur(20px);opacity:.85">R</span></div>
<div style="font-family:'Press Start 2P',monospace;font-size:clamp(46px,9vw,104px);line-height:1;color:#5ad1e6;text-shadow:0 0 26px rgba(90,209,230,.7);margin-top:16px">ADS</div>
<div style="margin:44px auto 0;max-width:680px;font-size:clamp(15px,1.8vw,19px);line-height:1.7;color:#bfe6ef">Why should we watch ads for games AI can build in a week? And why should we get <span style="color:#eafcff;background:rgba(90,209,230,.14);padding:1px 6px">ad-punished</span> for clearing — or failing — a stage?</div>
<div style="margin-top:14px;font-family:'VT323',monospace;font-size:26px;color:#7fe3f0">> we deserve to play without being ad-punished.</div>
<div style="display:flex;gap:16px;justify-content:center;flex-wrap:wrap;margin-top:40px">
<a href="#games" data-nav="games" style="font-family:'Press Start 2P',monospace;font-size:13px;color:#04252c;background:#5ad1e6;padding:16px 24px;border-radius:3px;box-shadow:0 0 24px rgba(90,209,230,.45)">▸ PLAY FREE</a>
<a href="#manifesto" data-nav="manifesto" style="font-family:'Press Start 2P',monospace;font-size:13px;color:#8ee6f4;background:transparent;padding:16px 24px;border:2px solid rgba(90,209,230,.4);border-radius:3px">THE MANIFESTO</a>
</div>
<div style="margin-top:34px;font-family:'Press Start 2P',monospace;font-size:12px;color:#eafcff;animation:blink 1.1s steps(1) infinite">◎ INSERT NO COIN ◎</div>
</div>
<div class="crt-scan"></div><div class="crt-vig"></div>
</div>
</div>
</div>
<!-- the pitch / stance -->
<div style="max-width:960px;margin:0 auto;padding:70px 30px 30px">
<div style="font-family:'VT323',monospace;font-size:24px;line-height:1.4;color:#7fe3f0;border-left:2px solid rgba(90,209,230,.4);padding-left:22px">
<div style="opacity:.55">fucad@public-good:~$ ./boot --no-ads</div>
<div style="margin-top:10px">[ ok ] if AI builds it in a week, it shouldn't cost your attention.</div>
<div>[ ok ] simple entertainment is a digital public good.</div>
<div>[ ok ] entering arcade<span class="blink">_</span></div>
</div>
<div style="margin-top:40px;font-size:16px;line-height:1.8;color:#cfeaf1;max-width:760px">
I say <span style="color:#eafcff">no more ads</span>. If you want ads on a game, then make a game good enough that we <em>can't</em> build it in a week. This project provides free entertainment for everyone — and pushes the whole industry to put in more effort. I'm not shutting anything down. I'm setting a <span style="color:#5ad1e6">baseline</span>. With AI, the bottom line of games just got higher — and these free games are proof of where it should sit.
</div>
</div>
<!-- ===== GAMES ===== -->
<div id="games" style="max-width:1080px;margin:0 auto;padding:60px 30px 90px;scroll-margin-top:80px">
<div style="display:flex;align-items:baseline;justify-content:space-between;gap:20px;flex-wrap:wrap;border-bottom:2px solid rgba(90,209,230,.28);padding-bottom:18px;margin-bottom:40px">
<div style="font-family:'Press Start 2P',monospace;font-size:22px;color:#eafcff">▚ THE ARCADE</div>
<div style="font-size:12px;color:#7fbecb;letter-spacing:.05em">FREE · OPEN-SOURCE · NO ADS · ALL PLATFORMS</div>
</div>
<div id="game-grid" style="display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:22px"></div>
<div style="margin-top:40px;text-align:center;font-size:13px;color:#7fbecb">Want to add one? Every repo is MIT-licensed and AI-friendly. <a href="#manifesto" data-nav="manifesto">Read the rules →</a></div>
</div>
</div>
<!-- ===== MY STORY ===== -->
<div data-page="story" hidden>
<div style="max-width:820px;margin:0 auto;padding:70px 30px 100px">
<div style="font-family:'Press Start 2P',monospace;font-size:12px;color:#5ad1e6;letter-spacing:.05em">◂ PLAYER 1 — CONTINUE?</div>
<h1 style="font-family:'Press Start 2P',monospace;font-size:clamp(26px,5vw,44px);line-height:1.25;color:#eafcff;margin:22px 0 0;text-shadow:0 0 18px rgba(90,209,230,.35)">MY SAFE<br>SPOT.</h1>
<div style="margin-top:36px;position:relative;background:linear-gradient(180deg,#0e1a20,#0a0d11);border:2px solid rgba(90,209,230,.3);border-radius:8px;padding:34px 30px;overflow:hidden">
<div style="font-size:16px;line-height:1.9;color:#cfeaf1;position:relative;z-index:4">
<p style="margin:0 0 20px">I just like lying down with a favorite Netflix show on, playing a simple arcade game on my phone. That's it. That's my safe spot — my way to switch off and relax.</p>
<p style="margin:0 0 20px">But I'm <span style="color:#eafcff;background:rgba(90,209,230,.14);padding:1px 6px">tired of an ad popping up every ten seconds</span>. Clear a stage — ad. Fail a stage — ad. Get punished either way for the crime of… playing a game.</p>
<p style="margin:0 0 20px">So I'm making free games instead. Not to shut down the games industry — I love games. I'm setting a <span style="color:#5ad1e6">baseline</span>. Now that AI can build a polished casual game in a week, the bottom line of what a game should be just moved up. These are proof of that line.</p>
<p style="margin:0">Let's make free entertainment for everyone to enjoy. <span style="color:#8ee6f4">Insert no coin.</span></p>
</div>
<div class="crt-scan"></div>
</div>
<div style="margin-top:30px;font-family:'VT323',monospace;font-size:24px;color:#7fe3f0">> — the person who got tired of being ad-punished<span class="blink">_</span></div>
<div style="margin-top:40px"><a href="#games" data-nav="games" style="font-family:'Press Start 2P',monospace;font-size:12px;color:#04252c;background:#5ad1e6;padding:15px 22px;border-radius:3px">▸ GO PLAY</a></div>
</div>
</div>
<!-- ===== MANIFESTO ===== -->
<div data-page="manifesto" hidden>
<div style="max-width:880px;margin:0 auto;padding:70px 30px 100px">
<div style="font-family:'Press Start 2P',monospace;font-size:12px;color:#5ad1e6">▚ HIGH SCORE TABLE</div>
<h1 style="font-family:'Press Start 2P',monospace;font-size:clamp(24px,4.5vw,40px);line-height:1.25;color:#eafcff;margin:20px 0 0">THE MANIFESTO</h1>
<p style="margin:26px 0 0;font-size:16px;line-height:1.8;color:#cfeaf1;max-width:720px">Open-source, ad-free, free-forever casual games. Every game ships to Android and iOS at no cost — no ads, no paywalls, no data harvesting. Built with Flutter + Flame, all code public to inspect, fork, and improve.</p>
<div id="principle-list" style="margin-top:44px;display:grid;gap:14px"></div>
<div style="margin-top:44px;background:rgba(90,209,230,.06);border:1px dashed rgba(90,209,230,.35);border-radius:6px;padding:24px 24px">
<div style="font-family:'Press Start 2P',monospace;font-size:12px;color:#8ee6f4">WHAT THIS IS NOT</div>
<p style="margin:16px 0 0;font-size:14px;line-height:1.75;color:#cfeaf1">This is not an attack on developers. Developer talent is too valuable to spend ad-cloning games that already exist. Building something genuinely new and complex? Charge whatever you want. This movement is only about the simple arcade and puzzle games that require no ongoing creative labor — the ones that should never have been ad-farms in the first place.</p>
</div>
<div style="margin-top:24px;font-size:12px;color:#7fbecb">Code: MIT · Assets: CC BY · A game qualifies if its complete mechanics fit in under 500 words.</div>
<div style="margin-top:34px"><a href="#games" data-nav="games" style="font-family:'Press Start 2P',monospace;font-size:12px;color:#04252c;background:#5ad1e6;padding:15px 22px;border-radius:3px">▸ SEE THE GAMES</a></div>
</div>
</div>
<!-- ===== FOOTER ===== -->
<footer style="border-top:2px solid rgba(90,209,230,.22);padding:30px;text-align:center;font-size:11px;color:#6f93a0;letter-spacing:.05em">
FUCAD ARCADE · A PUBLIC GOOD, NOT A PRODUCT · <a href="https://github.com/fucad" target="_blank" rel="noopener">GITHUB</a> · INSERT NO COIN
</footer>
</div>
<script>
(function () {
var ICONS = {
github: '<svg width="18" height="18" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z"/></svg>',
play: '<svg width="16" height="18" viewBox="0 0 20 22" fill="currentColor" aria-hidden="true"><path d="M.5 1.1v19.8c0 .5.5.8.9.5l11-10.4L1.4.6C1 .3.5.6.5 1.1Zm14.4 6.6L3.6.9 14.9 7.7Zm0 6.6L3.6 21.1l11.3-6.8Zm4.1-4.1L16.3 8.6l-2.5 2.4 2.5 2.4 2.7-1.6c.6-.4.6-1.2 0-1.6Z"/></svg>',
app: '<svg width="16" height="18" viewBox="0 0 16 19" fill="currentColor" aria-hidden="true"><path d="M13.1 10.1c0-1.7.9-3.1 2.3-3.9-.8-1.1-2-1.8-3.5-1.9-1.5-.1-3.1 .9-3.7 .9-.6 0-1.9-.9-3.1-.8C3.5 4.5 2 5.5 1.2 7 .5 8.5.3 11.4 1.7 14c.7 1.3 1.5 2.7 2.6 2.7 1 0 1.4-.7 2.7-.7 1.3 0 1.6.7 2.7.6 1.1 0 1.8-1.2 2.5-2.5.5-.8.7-1.3 1-2.2-2.5-1-2.1-3.5-2.1-3.8ZM10.7 2.7c.6-.8 1-1.8 .9-2.7-.9 0-1.9.6-2.5 1.3-.6.7-1 1.7-.9 2.6.9.1 1.9-.5 2.5-1.2Z"/></svg>'
};
function mk(name, glyph, blurb) {
return { name: name, glyph: glyph, blurb: blurb, status: 'SOON', github: '#', play: '#', app: '#' };
}
var GAMES = [
{
name: 'BLOCK PUZZLE',
glyph: '▟▙',
icon: 'assets/icons/block_puzzle.png',
blurb: 'Drag pieces onto the 8x8 board. Clear lines, chain combos. Endless Classic + a Quest map.',
status: 'IN DEV',
github: 'https://github.com/fucad/block_puzzle',
play: '#',
app: '#'
},
mk('SNAKE', '▰▰▰', "Grow the line. Don't bite yourself."),
mk('MINES', '◈', 'Flag the bombs. Trust the numbers.'),
mk('SUDOKU', '▦', 'Nine by nine. No ads, no timers.'),
mk('BREAKOUT', '▬', 'Bounce, break every brick.'),
mk('2048', '⧉', 'Slide, merge, chase the tile.'),
mk('PONG', '│ ●', 'The original. Two paddles.'),
mk('SOLITAIRE', '♤', 'One deck. One quiet win.')
];
var PRINCIPLES = [
{ n: '01', title: 'ZERO EXTRACTION', body: 'No ads, no microtransactions, no data harvesting, no dark patterns. Ever.' },
{ n: '02', title: 'RADICAL OPENNESS', body: 'All code, all decisions, all contributions are public.' },
{ n: '03', title: 'HONEST SCOPE', body: 'Simple games only. It qualifies if its complete mechanics fit in under 500 words.' },
{ n: '04', title: 'AI AS AMPLIFIER', body: 'AI-assisted contribution is embraced; the codebase is built to support it.' },
{ n: '05', title: 'SUSTAINABLE MINIMALISM', body: 'No investors, no exit strategy, no overhead beyond what is necessary.' },
{ n: '06', title: 'DEVELOPER RESPECT', body: 'Developer talent is too valuable to spend ad-cloning simple games.' }
];
var NAV = [
{ label: 'Home', page: 'home' },
{ label: 'Games', page: 'games' },
{ label: 'My Story', page: 'story' },
{ label: 'Manifesto', page: 'manifesto' }
];
var PAGES = ['home', 'story', 'manifesto'];
var state = { page: 'home' };
var el = function (id) { return document.getElementById(id); };
var esc = function (s) {
return String(s).replace(/[&<>"']/g, function (c) {
return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[c];
});
};
var STORE_BTN = 'flex:1;display:flex;align-items:center;justify-content:center;height:38px;border:1px solid rgba(90,209,230,.3);border-radius:3px;color:#9fdce8;background:rgba(90,209,230,.06)';
function storeLink(href, title, icon) {
var disabled = !href || href === '#';
return '<a href="' + esc(disabled ? '#' : href) + '"' +
(disabled ? ' aria-disabled="true" tabindex="-1" style="' + STORE_BTN + ';opacity:.4;pointer-events:none"'
: ' target="_blank" rel="noopener" style="' + STORE_BTN + '"') +
' title="' + esc(title) + '" aria-label="' + esc(title) + '">' + icon + '</a>';
}
// Games without a real app icon yet fall back to the glyph placeholder.
function artwork(g) {
if (g.icon) {
return '<img src="' + esc(g.icon) + '" alt="' + esc(g.name) + ' app icon" loading="lazy" ' +
'style="width:100%;height:100%;object-fit:cover;display:block">';
}
return '<div style="font-family:\'Press Start 2P\',monospace;font-size:11px;color:rgba(127,227,240,.5);text-align:center;line-height:1.6">' +
esc(g.glyph) + '<br><span style="font-size:8px">ICON</span></div>';
}
function renderGames() {
el('game-grid').innerHTML = GAMES.map(function (g) {
return '' +
'<div style="background:linear-gradient(180deg,#0e1a20,#0a0d11);border:1px solid rgba(90,209,230,.2);border-radius:8px;overflow:hidden;display:flex;flex-direction:column">' +
'<div style="position:relative;aspect-ratio:1/1;background:repeating-linear-gradient(45deg,#0d171d 0 10px,#0a1216 10px 20px);display:flex;align-items:center;justify-content:center;border-bottom:1px solid rgba(90,209,230,.18)">' +
artwork(g) +
'<div style="position:absolute;top:9px;right:9px;font-family:\'JetBrains Mono\',monospace;font-size:9px;color:#04252c;background:#5ad1e6;padding:2px 6px;border-radius:2px">' + esc(g.status) + '</div>' +
'</div>' +
'<div style="padding:16px 15px 15px;display:flex;flex-direction:column;gap:12px;flex:1">' +
'<div>' +
'<div style="font-family:\'Press Start 2P\',monospace;font-size:13px;color:#eafcff">' + esc(g.name) + '</div>' +
'<div style="margin-top:8px;font-size:11px;line-height:1.5;color:#8fbccb">' + esc(g.blurb) + '</div>' +
'</div>' +
'<div style="display:flex;gap:8px;margin-top:auto">' +
storeLink(g.github, 'GitHub', ICONS.github) +
storeLink(g.play, 'Google Play', ICONS.play) +
storeLink(g.app, 'App Store', ICONS.app) +
'</div>' +
'</div>' +
'</div>';
}).join('');
}
function renderPrinciples() {
el('principle-list').innerHTML = PRINCIPLES.map(function (p) {
return '' +
'<div style="display:flex;gap:18px;align-items:flex-start;background:linear-gradient(180deg,#0e1a20,#0a0d11);border:1px solid rgba(90,209,230,.2);border-radius:6px;padding:18px 20px">' +
'<div style="font-family:\'Press Start 2P\',monospace;font-size:16px;color:#5ad1e6;min-width:34px">' + esc(p.n) + '</div>' +
'<div>' +
'<div style="font-family:\'Press Start 2P\',monospace;font-size:12px;color:#eafcff">' + esc(p.title) + '</div>' +
'<div style="margin-top:9px;font-size:14px;line-height:1.6;color:#9fbccb">' + esc(p.body) + '</div>' +
'</div>' +
'</div>';
}).join('');
}
function renderNav() {
el('nav-links').innerHTML = NAV.map(function (n) {
var active = n.page === state.page || (n.page === 'games' && state.page === 'home');
var style = 'font-size:12px;letter-spacing:.06em;text-transform:uppercase;padding:9px 14px;border-radius:3px;' +
'border:1px solid ' + (active ? '#5ad1e6' : 'rgba(90,209,230,.3)') + ';' +
'color:' + (active ? '#04252c' : '#9fdce8') + ';' +
'background:' + (active ? '#5ad1e6' : 'transparent');
return '<a href="#' + n.page + '" data-nav="' + n.page + '" style="' + style + '"' +
(active ? ' aria-current="page"' : '') + '>' + esc(n.label) + '</a>';
}).join('');
}
function scrollToGames() {
var target = el('games');
if (!target) return;
window.scrollTo({ top: target.getBoundingClientRect().top + window.scrollY - 70, behavior: 'smooth' });
}
function show(page) {
state.page = page;
Array.prototype.forEach.call(document.querySelectorAll('[data-page]'), function (node) {
node.hidden = node.getAttribute('data-page') !== page;
});
renderNav();
}
// `#games` is a scroll target on the home page, not a page of its own.
function applyHash(hash, animate) {
var key = (hash || '').replace(/^#/, '') || 'home';
if (key === 'games') {
var wasHome = state.page === 'home';
show('home');
if (wasHome && animate) scrollToGames();
else setTimeout(scrollToGames, 60);
return;
}
show(PAGES.indexOf(key) === -1 ? 'home' : key);
window.scrollTo(0, 0);
}
document.addEventListener('click', function (e) {
var link = e.target.closest ? e.target.closest('a[data-nav]') : null;
if (!link) return;
var page = link.getAttribute('data-nav');
e.preventDefault();
if (('#' + page) === window.location.hash) applyHash(page, true);
else window.location.hash = page;
});
window.addEventListener('hashchange', function () { applyHash(window.location.hash, true); });
renderGames();
renderPrinciples();
applyHash(window.location.hash, false);
})();
</script>
</body>
</html>