Click the green "Use this template" button at the top of this repo to create your own game repository from this starter. (Don't fork — template creates a clean, independent repo with a working Pages deploy and the portal protocol already wired up.)
Showcase & spec: https://github.com/CallumHYoung/gamejam
- A minimal working game (
index.html+game.js) — moving circle, exit portal, incoming-portal spawn logic, auto-picks a destination from the live jam registry. - Realtime multiplayer via Trystero. Pure P2P over BitTorrent trackers — no backend, no accounts, no keys. Open two tabs and you'll see each other as circles in the same demo room. Works from the internet, not just localhost.
portal.js— the Portal Protocol helper library. ~80 lines, no dependencies. This is the only hard requirement of the jam..github/workflows/pages.yml— a GitHub Actions workflow that deploys your game to GitHub Pages on every push tomain.- Purple vibes to match the jam's theme.
Try the starter as-is: after you create your repo and enable Pages, the starter game will already portal to other jam games and show other players that are currently in the demo room.
Multiplayer is optional per the jam spec. If you don't want it, delete the Trystero block in game.js (clearly commented) and the #peers element in index.html. Your game will drop back to solo and the portal protocol still works.
Click "Use this template" → "Create a new repository" at the top of this page. Name it whatever you want (e.g. rocket-racer). Make it public.
git clone https://github.com/<your-username>/<your-game>.git
cd <your-game>Any static file server works:
python -m http.server 8000
# then open http://localhost:8000Walk into the purple portal. It'll redirect you to a random game from the live jam registry.
Replace game.js (and index.html / style.css as needed) with your actual game. Keep portal.js and the calls to Portal.* — those are the jam's contract.
Feed the full build spec into your coding agent for the rules: https://github.com/CallumHYoung/gamejam/blob/main/SPEC.md
Push to main:
git add .
git commit -m "Build my game"
git pushThen on GitHub:
- Go to Settings → Pages on your repo
- Source: GitHub Actions
- Watch the workflow run in the Actions tab (~1 minute)
Your game is live at:
https://<your-username>.github.io/<your-game>/
Open https://github.com/CallumHYoung/gamejam/blob/main/games.json, click the pencil icon (GitHub will auto-fork for you), and add your entry to the games array:
{
"id": "rocket-racer",
"title": "Rocket Racer",
"author": "Your Name",
"description": "One-line pitch.",
"url": "https://your-username.github.io/rocket-racer/",
"repo": "your-username/rocket-racer",
"thumbnail": "thumbnails/rocket-racer.png",
"type": "3d",
"tags": ["platformer", "three.js"],
"status": "wip"
}Commit to a new branch and open a PR. That's it — once merged, your game appears on the showcase with live deploy status pulled from your repo.
Full walkthrough: https://github.com/CallumHYoung/gamejam/blob/main/GETTING_STARTED.md
Every jam game reads the same URL params on load and redirects out the same way. That's how players travel between games without any backend.
Incoming — when your game loads, Portal.readPortalParams() returns:
const { fromPortal, username, color, speed, ref } = Portal.readPortalParams();If fromPortal is true, the player arrived from another game — skip your menu and spawn them in. If ref is set, also draw a return portal pointing back to ref.
Outgoing — when the player enters your exit portal:
const target = await Portal.pickPortalTarget(); // random game from the live registry
Portal.sendPlayerThroughPortal(target.url, {
username, color, speed,
});That's the whole protocol. Full details in SPEC.md.
- 2D: a door, tile, button, or menu item — anything a player can interact with.
- 3D: a visible object in the world (ring, archway, door) with a collision check against the player.
The starter is 2D canvas. If you're building 3D (Three.js / Babylon / PlayCanvas), you can still import portal.js and call Portal.sendPlayerThroughPortal / Portal.readPortalParams — the protocol is framework-agnostic.
Static hosting is compatible with realtime multiplayer through browser-to-service libraries. Don't add multiplayer until your portal loop works. Recommended: PlayroomKit. Full options in SPEC.md § Multiplayer.
Use whatever you want — Three.js, Phaser, Pixi, Babylon, PlayCanvas, raw canvas, raw WebGL, p5.js, HTML + CSS. The only constraints:
- Browser-only. No backend. Static hosting must be enough.
- Portal protocol. Drop in
portal.js(or implement the handful of URL-param behaviors yourself — it's ~15 lines if you want to inline it). - One entry point.
index.htmlat the root.
Have fun.