Architecture · How Open Arcade Is Built

One site, one tree.

This page is the written structure of Open Arcade: one folder that is the whole site, one Cloudflare Pages project it deploys to, the game list kept as data and baked in at build time, and proof by eye before anything is called done. It exists so the site can never quietly split into two copies that overwrite each other.

1 deploy tree1 Pages project: openarcadeopenarcade.lolEvery game embed-checked

The One Rule

One source of truth. Open Arcade lives in exactly one folder (~/workspace/openarcade). That folder, and only that folder, is deployed to the Pages project named openarcade. If a file is not in that folder, it is not on the site. No second tree, no shadow copy, no exceptions.

Rule 1

One tree

Pages, covers, logo files and the small print files all live in the single deploy tree. Working folders elsewhere are tools and inputs, never deploy sources, and are named below.

Rule 2

The game list is data

The builder reads the GameBoat catalogs and bakes the list into the homepage at build time. Counts, categories and order change in the data, never by editing numbers into a page.

Rule 3

One builder

build_openarcade.py builds the homepage, /brand/, /template/ and this page in one run. Every page has exactly one way it gets made, so the written system cannot drift from the site it describes.

Rule 4

Hosting follows the game

Games stay on their own hosts and play inside the player only after a header check proves they can be framed; anything that blocks framing stays out. Covers are copied into /img/, never hotlinked from another site.

Rule 5

One deploy pipe

Deploys upload the whole audited tree in one run. Before upload: file count, total size, and every expected path present and non-zero.

Rule 6

Proof by eye

A deploy is done only when the live page is read back and checked by title and content, including a page below the homepage. A status code alone never counts.

The Folder Map

What lives where.

/ (index.html)
The game app itself: header, chips, search, the 16:9 player, the Up Next sidebar and the browse grid. The game list is baked in at build time and every game deep-links as #game-id.
/img/
The joystick logo files and one cover per game (img/<id>.webp). Every image the site shows is served from this site, never borrowed from another domain.
/brand/ /template/ /architecture/
The written system: the brand, the canonical page frame, and this architecture page.
404.html · robots.txt · sitemap.xml
The small print: a branded not-found page, the robots file and the sitemap, written by the same builder on every run.
openarcade-api (Worker)
The progress API, beside the Pages project: it verifies the caller's session with e2-auth, then reads and writes per-user progress (plays, minutes, favorites, last game). It also keeps the owner delete tombstones, so a delete hides a game for everyone without ever editing the game list. It holds no secrets of its own.
openarcade-progress (KV)
The progress store, keyed by Discord user id. The page also keeps a local copy and merges it into the account copy on first login.
e2-auth (Worker)
One Discord login for the whole E2 family. Open Arcade is a named destination: the login returns to openarcade.lol with the session token in the #t= fragment. Identify scope only, so it can never read or send messages.
openarcade-www-redirect (Worker)
www.openarcade.lol answers here and 301-redirects to the apex, path preserved. One route, one job.
GameBoat catalogs (input)
own-games, hosted-full, itch-full and fun-scores JSON in the GameBoat catalog folder. The builder's source data, not part of the tree.

Ownership

Who writes what.

Page or dataBuilder or ownerNotes
/ (the app)build_openarcade.pyOne builder for the whole site. Games come from the catalogs, never from a list pasted into the page.
/brand/ /template/ /architecture/build_openarcade.pyThe written system is built in the same run as the site, so it cannot drift from what it describes.
Game dataGameBoat catalogsCuration and the embed check happen before a game joins the catalog pull.
Progressopenarcade-api WorkerCode and deploy script live in ~/workspace/openarcade-auth/. No secrets in this Worker.
Logine2-auth WorkerThe shared Discord login. Open Arcade never stores passwords; it holds a session token.
www redirectopenarcade-www-redirect WorkerOne route (www.openarcade.lol/*), one job: send www to the apex.

Not Deploy Trees

Three nearby folders serve the site but are never deployed: ~/workspace/gameboat-catalog/ (the source data the builder reads), ~/workspace/openarcade-auth/ (Worker code and deploy scripts), and ~/workspace/openarcade-assets-raw/ (raw logo art before it is sized into /img/). The GameBoat tree is a different site entirely that feeds the catalog. Confusing any of these with the deploy tree is how double trees are born, so they are written down here.

1
deploy tree, the whole site
1
Pages project it deploys to
3
small Workers beside it
0
second copies of the site, anywhere

The Domain

openarcade.lol is registered at Porkbun and its DNS zone lives on Cloudflare, on the assigned nameservers diana.ns.cloudflare.com and lex.ns.cloudflare.com. The apex attaches to the single Pages project as a custom domain, www 301-redirects to the apex through the redirect Worker, and openarcade-epu.pages.dev stays as the permanent mirror address. One project, one tree, one front door.