The architectural decision behind playground — and the GitHub-account-mess question. With a clear answer for you, today.
You've got playground at ~/lab/projects/playground/ with ~40 HTML prototypes, a few games on the horizon, a Node server, some Python tools. The question is whether it becomes one repo on GitHub (a "monorepo") or whether each sub-experiment gets its own repo, with playground just being a portal that points at them.
Both paths work. Real companies ship both. The trade-offs are real, but neither is "the wrong answer" — pick what fits where you are right now.
One GitHub repo. Everything inside. Push once, deploy once.
utils/)One repo per game. Playground is just a portal that links to them.
Yes. In a monorepo deployed to Cloudflare Pages, any push to main triggers a full rebuild of the whole project. If you edit games/duck-hunt/index.html, Pages rebuilds and republishes the entire site.
But here's the surprise: it doesn't matter. Three reasons:
1. Static builds are fast. Pages builds a folder of HTML files in 10–30 seconds. The "whole site rebuild" takes a coffee sip.
2. CF Pages caches aggressively. Unchanged files get cache-hits — only the changed files actually transit the network on redeploy. The build is full, but the deploy delta is tiny.
3. Atomic deploys. Pages doesn't half-update the site. The new version goes live all at once. No visitor ever sees a broken mid-deploy state.
Big monorepos with heavy build steps (think: a project that does a 10-minute webpack build) — there, "whole site rebuild on every commit" becomes painful, and you reach for tools like Turborepo or Nx that build only what changed. You are nowhere near this problem. Static HTML + the occasional minified JS bundle rebuilds in seconds.
You asked specifically: if duck-hunt and pepper-popper each have their own repos, how does playground show them? Three patterns:
Each game lives in its own repo, deploys to its own URL (e.g. duck-hunt.pages.dev). Playground's portal page embeds each game with <iframe src="https://duck-hunt.pages.dev">. Clean isolation, but iframes are awkward for full-screen games and bad for SEO.
Playground has a build script that, on each deploy, downloads the latest build of each game (e.g. via gh release download or git clone --depth 1) and copies it into games/duck-hunt/ before Pages publishes. Games stay independent, but they ship inside playground's URL. More moving parts.
From Lesson 1: submodules. Don't. They look right; they cost more than they save.
You wondered: "would I have ~/apps/playground/games/duck-hunt/ ON the VPS, mirrored with Mac, but also a GitHub repo??"
The answer depends on who's serving the files. Two cases:
The VPS does not need a copy. At all. Cloudflare Pages pulls directly from GitHub and serves the files from its edge nodes. Your VPS is uninvolved.
Mental model: your Mac writes the code → GitHub stores it → Cloudflare serves it to visitors. The VPS isn't in the picture.
The VPS does have a copy — but Coolify manages it for you. You never git clone manually on the VPS. Coolify clones into its own internal storage when you create the app, then auto-pulls new commits when GitHub webhooks fire.
Mental model: your Mac writes the code → GitHub stores it → Coolify on the VPS pulls it on every push → Docker container runs it. You manage code on your Mac. Coolify owns the VPS-side copy.
You do not need to manually mirror a folder between your Mac and the VPS. That's the manual workflow Coolify exists to eliminate. git push is the only sync action you ever take.
This is what happens behind the scenes every time you make a change. Slower than reading it the first time, then second nature.
Make changes in ~/lab/projects/router-go/. Test locally with npm run dev or whatever your run command is.
git add . → git commit -m "fix routing bug" → git push. Takes 2 seconds. GitHub now has your new commit on main.
GitHub fires an HTTP POST to Coolify's webhook URL: "hey, new commit on main, repo lovebuilt/router-go". You don't do anything for this step — it's automatic from the moment you connected the repo in Coolify.
Coolify on your VPS does git pull into its internal storage, then runs your Dockerfile to build a new container image. If your repo has a Dockerfile, Coolify uses it. If not, Coolify auto-detects Node/Python/etc. and builds with sensible defaults.
Old container gets gracefully stopped, new one starts. Cloudflare tunnel keeps routing visitors to the new container's port. Zero downtime in practice. You see the new version live within ~60 seconds of git push finishing.
Once it's wired, the workflow you live in is just: edit → commit → push. Coolify's webhook + auto-deploy handles the rest. The first-time setup of a new app in Coolify's UI is the only place you click around — after that, it's terminal-only forever.
If you go many-repos, the GitHub-account-mess is real. You're already at 7 repos. At 30 it gets uncomfortable. At 100 you can't find anything. Four tools to manage this:
Pin your 6 most important repos to your profile (GitHub UI: "Customize your pins"). Add topic tags (game, tool, library) so the list is filterable. Costs nothing.
You already do this — lovebuilt is your org. Personal experiments can stay under your user (coachname/whatever) while polished things move to lovebuilt/. Tier 1 vs tier 2.
Even in many-repos land, you keep playground as a repo whose README lists and links to every sub-game. It's the table of contents. New visitors land there, get oriented, click through.
GitHub's "Archive repo" makes it read-only and visually-grayed-out without deleting. Use it on anything you've stopped maintaining. Your active-repo list stays clean. You already have my-old-n8n-setup archived — exactly this pattern.
For where you are right now — solo dev, no collaborators on the games, ~40 prototypes already in one folder, no game with independent release cadence — monorepo wins on every dimension that matters:
1. Playground is already one folder. Converting it to one repo is one git init + one gh repo create. Converting to 40 separate repos is 40 of each.
2. CF Pages does branch previews on a single repo for free. You get dev/staging/prod (next lesson) automatically from one repo — no per-game-repo coordination.
3. Shared style + utilities are trivial. Your tts-shootout.html and nootropic-tracker.html already share an aesthetic. One repo = one place to update the shared bits.
4. You can split out later. If duck-hunt grows into a real thing with collaborators, git filter-repo can extract its history into a standalone repo cleanly. Splitting later costs nothing extra.
Move a sub-game to its own repo when AT LEAST TWO are true: (a) it has its own collaborator(s), (b) it has its own release cadence different from playground's, (c) it has been built and shipped enough to feel like a "real" thing not a prototype, (d) you want it findable/forkable by strangers under its own name.