Gltch Arcade
A neon, 80s-style arcade cabinet in a single HTML file. Seventy-two tiny games, puzzles, toys and oracles with fluid animations, CRT fuzz and synthesised sound. No frameworks, no build step, no tracking.
Play it: https://shanemc92.github.io/gltch-arcade/
Highlights
- One file.
index.html (about 550 KB) holds all the CSS, JavaScript, pixel art, the hand-made pixel font and a 25,000-word list for Nine Letters. The manifest, service worker and icons below are optional extras for installing it.
- No dependencies, nothing from anywhere else. Everything comes from the page itself, so once it is open it works offline.
- Installable, if you want. A web app manifest lets browsers that support it (Chrome, Edge, Android) install it as a standalone app with its own icon and window, and an Install as an app button appears at the bottom of the page when your browser offers that. On iPhone and iPad use Share, then Add to Home Screen. A tiny service worker (
sw.js) keeps a copy so the installed app opens offline. It always loads the newest version when you are online, and none of it is needed: open index.html directly and everything still works.
- Shareable links. Every cabinet has its own address, such as
#snake or #beat-lane, and the Menu lists all of them.
- Synthesised sound. Every bleep, drum and chord is generated with the Web Audio API. Sound stays off until you switch it on.
- Keyboard, mouse and touch. Canvas games have touch controls.
- Motion and static are optional. The FX button in the header switches off the animation and the CRT static (Neon Cube still turns its layers, just a little quicker, so you can follow each move). It starts off if your system asks for reduced motion (
prefers-reduced-motion), and your choice is remembered on your device.
- Tickets and a prize counter. Wins, high scores and time spent playing earn tickets, and the count sits in the top bar of the screen. Open the Menu and press Cash out for a high-score-style payout and a prize that is exactly as good as a real arcade's. More tickets, better junk.
- One cabinet is hidden. It is not in the Menu, Random never picks it and it has no link. It is a tribute to a 1983 film, and the password is in the film.
- Private by default. High scores, your tickets, the shared chip bank and your Pixel Pad drawing live in
localStorage on your device and nowhere else.
The cabinets
Press Random for something new, or open the Menu to pick one. Random never repeats a cabinet until you have seen them all.
Arcade and table games (24)
| Cabinet | What it is |
|---|
| Beat Lane | Hit each note as it crosses the line. Keys D, F, J and K, or tap the lanes. |
| Blackjack | Get closer to 21 than the dealer without going over. |
| Block Fall | Seven shapes drop into a ten-wide well. Fill a row to clear it and keep the stack off the ceiling. Hold, ghost piece, next three and levels. |
| Brick Glitch | Smash every brick. Catch the falling capsules: M splits the ball, W widens the paddle, L fires lasers. |
| Bug Whacker | Bugs pop out of the holes. Bop them before they hide. |
| Byte Maze | Collect every data bit while the bugs hunt you down. |
| Cave Flyer | One button. Hold to climb, let go to drop, and thread the neon cave as it narrows. |
| Double Up | Slide the whole board and matching numbers merge into their double. Build a 2048 tile, then keep going. |
| Drop Four | Line up four discs in a row, column or diagonal before the CPU does. |
| Higher or Lower | Will the next card be higher or lower? Aces are low. |
|
Brain teasers and puzzles (24)
| Cabinet | What it is |
|---|
| 80s Trivia | Ten questions drawn from sixty, all about the decade of neon, synths and shoulder pads. |
| Blackout | Every tap flips that light and the ones touching it. |
| Brainteasers | Have a proper think, then tap the card to check. |
| Chroma Flip | Every tap pushes that tile and the ones touching it on to the next colour: pink, then cyan, then yellow, then round again. |
| Code Cracker | Crack the 4-digit code in 10 tries. No digit repeats. |
| Colour Clash | A colour word shown in a different ink. Tap the colour of the ink, not the word, as many times as you can in thirty seconds. Keys 1 to 5 work too. |
| Defuse | Clear the board without touching a bomb. Numbers count the bombs touching that square. |
| Echo | Watch the pads light up, then play the pattern back. |
| Flood Fill | Start in the top-left corner and paint the whole 12 by 12 board one colour in 27 moves or fewer. Every board can be won. Keys 1 to 6 work too. |
| Footsteps Illusion | Both bars glide at one steady speed. So why do they seem to take turns stepping? |
Oracles and chance (8)
| Cabinet | What it is |
|---|
| Card Psychic | Pick any card in your head and keep it to yourself. |
| Coin Flip | Heads or tails? Tap the coin to toss it and see how long a streak you can ride. |
| Decision Wheel | Can’t decide? Let the wheel choose. |
| Dice Tower | Pick a die and roll it. Natural 20s get the full fanfare. |
| Fortune Cookie | Crack it open and read your destiny. Please do not eat the paper. |
| Mind Reader | Think of a number from 1 to 63, say whether it is on each of six cards, and the cabinet names it. A neat bit of binary. |
| Octagon Oracle | Ask a yes or no question, then tap the octagon. |
| Tarot Draw | Three cards for your past, present and future from a neon deck of twenty-two, some of them reversed. For entertainment only. |
Toys (16)
| Cabinet | What it is |
|---|
| Band Name Gen | Every 80s band needed a name, a debut album and a questionable haircut. |
| Beat Box | A 16-step drum machine. Tap squares to build a loop, press play and tweak the tempo. |
| Bubble Wrap | An endless supply. Tap a bubble, or drag across the sheet to pop a whole row. |
| Dad Jokes | Certified groan-grade material. Read the setup, brace yourself, then reveal the punchline. |
| Excuse Generator | Need to get out of something? Here is a reason nobody can argue with, because nobody will believe it. |
| Fireworks | Tap or click anywhere in the sky to send a rocket there. |
| Kaleidoscope | Drag across the disc and watch it mirror into a bloom. Pick 4, 6, 8 or 12 mirrors, or let it draw by itself. |
| Lava Lamp | A slow, glowing lava lamp. Pick a colour scheme and a speed, then let your brain idle for a bit. |
| Life Lab | Conway’s Game of Life. Draw cells, press play, and watch four simple rules build gliders, blinkers and glorious chaos. |
| Morse Station | Type a message to see and hear it in Morse code, or switch to Decode and name the letter from the beeps. |
Run it locally
Open index.html in any modern browser. That is the whole setup.
Install and the offline copy need https:// or localhost, so use a local server for those:
python3 -m http.server 8000
# then browse to http://localhost:8000
Deploy to GitHub Pages
- Push this folder to a repository named
gltch-arcade.
- In the repository, go to Settings > Pages.
- Under Build and deployment, set Source to Deploy from a branch, then pick
main and / (root).
- Save. The site appears at
https://shanemc92.github.io/gltch-arcade/ within a minute or two.
The empty .nojekyll file tells Pages to serve the files as they are, without running Jekyll.
To use a custom domain, add a CNAME file containing the domain (for example arcade.example.com), point a DNS CNAME record at shanemc92.github.io, and enable Enforce HTTPS in the Pages settings.
Security and privacy
- Content Security Policy. A meta CSP sets
default-src 'none' and only allows the inline script and styles, data: images, and the page's own manifest, icons and service worker. The page cannot make network requests or load external scripts, fonts, images or frames.
- No HTML injection. Anything a visitor types is written with
textContent. innerHTML is only used for fixed markup that ships with the page.
- Minimal storage. All keys are prefixed
gltch-arcade:. They hold numbers (scores, tickets, chips, settings) plus the Pixel Pad drawing. Nothing typed into Password Gauntlet or Mainframe Breach is ever stored, and those fields switch off autocomplete, spellcheck and password-manager prompts.
- Safe phishing quiz. Spot the Phish uses only made-up brands on the reserved
.invalid top-level domain, and none of its links are clickable.
- Known limit. GitHub Pages cannot send custom response headers, and
frame-ancestors is ignored in a meta tag, so clickjacking protection is not possible there. If you self-host, add headers such as:
add_header Content-Security-Policy "frame-ancestors 'self'" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "no-referrer" always;
The CSP allows 'unsafe-inline' for scripts because the whole app is one inline script. Hash-based CSP would be stricter, but every edit would mean recomputing the hash.
Adding a cabinet
Each cabinet is one item() call. Copy any existing one or start from this:
item('toy', 'My Thing', 'One-line description shown under the title.', (el, ctx) => {
const out = h('div', { class: 'msg', text: 'Ready' });
const btn = h('button', { class: 'btn big', text: 'Press me', onclick: () => { say(out, 'Pressed'); Sound.coin(); } });
ctx.interval(() => { /* runs every second, stopped automatically when you leave the cabinet */ }, 1000);
el.append(btn, out);
});
The category (game, brain, oracle or toy) sets the colour and menu section. The menu, shareable link and counters update themselves. Tickets come for free too: in a game or brain cabinet, Sound.win() and best(key, score) pay them out (toys and oracles do not). The menu sections are kept at an even length, so add cabinets in pairs.
For a cabinet that should stay out of the Menu, Random and the links, register it with secret(title, blurb, mount) instead. The only way in is the trigger near the end of the script.
Two rules keep things tidy:
- Anything that outlives the page elements (timers, animation loops,
window listeners) goes through ctx.on, ctx.timeout, ctx.interval, ctx.wait or ctx.loop, so it is torn down when you move on to another cabinet.
- Build elements with
h() and its text option so visitor input never becomes HTML.
Credits
Built by Shane McElhinney. Every game, sprite, sound and the pixel font are original. Nine Letters checks words against the common part of the public-domain ENABLE word list, with the rude ones taken out, stored in the page as a compressed string. Block Fall, Double Up, Road Hop, Sky Guard, Colour Clash and Flood Fill use well-known, unowned game mechanics with original names and code, and the Tarot Draw readings are original too. The hidden cabinet is a fan tribute to the 1983 film WarGames, with a hand-drawn map; a few short lines of dialogue are quoted, and the film and its names belong to their owners. 80s Trivia and the arcade facts mention real films, games, people and brands by name for quiz purposes only; those names belong to their owners, and this project is not affiliated with any of them.
License
MIT