About
How the thing is put together and where to change it.
Files
Thirteen files, flat, no subfolders. No build step, no framework, and nothing fetched from anywhere — the fonts are embedded in the stylesheet. Open index.html straight off your disk or drop the folder on any static host.
index.html home math.html arithmetic drills — practice, sprint, ladder ai.html chat, four providers, your own key library.html all the tables, as a list or a grid play.html the felt — reads ?g= to know which table proxy.html address bar, four open modes, frame, log youtube.html player, a way out to YouTube, vertical shorts feed link.html link generator settings.html accent, motion, backend, stored data about.html this style.css everything visual, tokens at the top app.js table list, storage, shell, one function per page casino.js the bankroll and all eight games
The header and the sidebar are copied into each HTML file instead of being built by script. That is deliberate. If the JavaScript breaks, you still get a page.
Running it off a flash drive
Copy the eleven files onto a stick and open index.html. There is no server involved and no build step, so it just runs. The fonts are embedded in the stylesheet rather than fetched from Google, which means it looks the same with no internet at all.
One thing changes. Some browsers refuse to keep site data for a page opened as a local file, and if that happened your chips would reset every time you moved from one page to another. So there is a second tier: when local storage is blocked, everything is kept in the tab itself instead. Chips, favourites and settings then survive moving around the site but not closing the tab. The status bar at the bottom tells you which one you are on.
What needs a network still needs one. YouTube embeds play if you are online. The deploy button on the Links page will not work from a file at all, because it has to read its own files back and a local page is not allowed to — it says so rather than failing quietly. Everything else, all eight tables included, runs offline.
Math
Three modes. Practice runs forever and tracks your streak. Sprint gives you sixty seconds and counts how many you land. Ladder is ten questions that climb through the difficulty levels as you go.
Pick which operations are in play and how hard the numbers get. Division questions are built backwards from a product so the answer always comes out whole. Subtraction never goes negative. Type and press enter — correct answers advance on their own after a beat, wrong ones pause to show you what it was.
Focus mode
Settings has a toggle that drops the top bar when you want the room. It is not a trapdoor: move the pointer to the very top of the window and the bar slides back, and the number keys keep switching pages either way. On a phone it stays put, since there is no hover to bring it back with.
One look throughout — black, hairlines, IBM Plex, amber only for state. The math page is no exception.
AI
Four providers: Anthropic, OpenAI, Google Gemini, and anything that speaks the OpenAI /chat/completions shape, which covers OpenRouter, Groq and a server on your own machine. Everyone supplies their own key, so hosting this page exposes nothing of yours.
Requests go straight from the browser to the provider. There is no server in the middle, which is why Anthropic needs its browser-access header set and why a provider that refuses cross-origin calls simply will not work. Replies are escaped before any formatting is applied, so nothing a model returns can become live markup on the page.
One request, one answer — no streaming. Three providers means three different response shapes, and one round trip is far easier to get right than three streaming parsers.
Chips and odds
You start with a thousand chips. There is no way to buy more and no way to take any out. Go broke and the button in the sidebar puts you back to a thousand, as often as you like.
The house edges are the real ones. Roulette keeps 2.70 in every hundred because of the single zero. Dice, crash, mines and hi-lo keep 1.00. Plinko keeps between 0.94 and 1.09 depending on the risk level. The reels keep 3.70. Blackjack sits near 0.50 if you play it well, worse if you do not.
All of those are under a hundred, which is the whole point. Play long enough and the number goes down. That is not a bug in the maths, it is the maths.
Every table prints its return in the top right so you can see what you are up against before you sit down.
Adding a table
Two steps, two files. Write the game in casino.js, then list it in app.js. The id has to be identical in both or the table will not open.
// casino.js
CASINO.games.keno = {
title:'Keno', blurb:'Pick numbers, wait.', rtp:'95.00%',
mount(stage, ctrl, api){
// stage — the middle of the page
// ctrl — your controls, under the bet box
// api — stake, win, record, say, goLabel, onGo, canvas
}
};
// app.js, in TITLES
{ id:'keno', title:'Keno', cat:'Instant',
controls:'Click numbers', rtp:'95.00%', ready:true }
Take a chip off the player with api.stake(), give one back with api.win(n), and log the round with api.record(multiplier). That last one drives the strip of recent results in the sidebar. Set ready:false while you are still working and the row shows up dimmed with a badge instead of disappearing.
Categories build themselves from whatever you type in cat. Invent new ones freely, the filters will follow.
Browse and shorts
The YouTube page has three modes. Watch takes an address and plays it here. Browse hands you off to YouTube itself. Shorts is a vertical feed you scroll with the wheel, a swipe, or the arrow keys, mounting one player at a time so twenty clips do not all load at once.
Browse does not show a grid of videos, and that is deliberate. The only thing a page can fetch without your account is a trending chart, and trending is not the same as recommendations. Your home page is built from your own watch history, which exists solely behind a login, and Google will not let you sign in inside a frame. A grid of strangers' videos labelled "recommended" would have been a lie.
So Browse hands you off to YouTube properly, in a real tab, with shortcuts to your subscriptions, history, watch later and the rest. Sign in there once and everything works. Copy a link back into Watch and it plays here.
Shorts can pull clips on its own if you put a free YouTube Data API key in the sidebar. Without one, paste Shorts links on the Watch tab and they join the feed.
Proxy modes
Four ways to open an address. Three of them share one limitation, so it is worth reading before you pick.
- about:blank window — opens a blank popup and writes a full-height frame into it. The address bar stays on about:blank because the window was never navigated anywhere.
- Blob window — the same document, built in memory and opened from a
blob:address. Unlike about:blank it survives a reload. - Frame — renders on the proxy page itself. Nothing pops up, so nothing can be blocked.
- Plain new tab — an ordinary navigation, no frame anywhere.
The first three put the target inside an iframe. Plenty of sites send X-Frame-Options: DENY or a frame-ancestors policy that forbids exactly that, and when they do, none of the three will load them. Wrapping the frame in a blob or a blank window changes nothing. The browser runs the same check either way.
Two things get past it. A plain tab, because there is no frame to refuse. Or your own server, set in settings, because the page then comes from your origin and those headers never reach the browser. Joetoro appends the encoded address to whatever endpoint you enter.
Links
The buttons at the top give any visitor their own copy in one click. Each hands them to a host's own setup flow with your repository prefilled — Netlify and Vercel both clone it into the visitor's own Git account before building, so they end up owning a real site at their own address.
No credential moves in either direction, and that is the point. Embedding your GitHub token so visitors could deploy on your behalf would hand it to every visitor: it takes seconds to read out of page source, and a repo-scoped token can create, rewrite and delete anything on your account.
The owner's only setup is pointing the buttons at one public repository. If you do not have one, the section below that will make it for you with a token, once.
Under those are the throwaway kinds. A blob address only exists inside the tab that made it. Close the tab and it is gone, and it will not open for anyone else.
The portable file is the shareable one. It downloads a small HTML file that opens the launcher when you double-click it. It points at the launcher rather than containing it, so the site still has to be reachable.
Nothing running in a page can mint a genuinely new web address. If you want a second one that works everywhere, deploy the folder again under a different name. Cloudflare Pages allows unlimited projects on the free plan.
Shortcuts
- 1 through 9 — jump between the nine pages
- / — focus the filter box on the library