A10: Build a Game: Put It on the Internet
You have an empty repo (A09). Today it becomes a real web page with your own address, one you can send to a friend. There is almost no game in it yet, and that is on purpose: getting the publishing out of the way now means every lesson after this one goes live the moment you push it.
The Canvas
A canvas is a rectangle of pixels you can draw on with code. Everything in our game world will be drawn there.
Create index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Kakkoi Online</title>
</head>
<body>
<canvas id="world" width="640" height="480"></canvas>
<script type="module" src="./main.js"></script>
</body>
</html>
And main.js:
const canvas = document.querySelector('#world');
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#1b1b22';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#e8e8ef';
ctx.font = '20px monospace';
ctx.fillText('Kakkoi Online', 20, 40);
ctx is short for context: the thing you give drawing orders to. fillRect paints a rectangle, fillText paints words. That is the whole drawing toolkit for now.
Now Try to Open It the Obvious Way
Double-click index.html. Your browser opens it, and the canvas is blank.
Open the developer console (F12, then the Console tab). There is an error, something like:
Access to script at 'file:///.../main.js' from origin 'null'
has been blocked by CORS policy
Nothing is broken. You have just met a rule that will follow you for your whole career.
Why a Page Needs a Server, Even on Your Own Computer
When you double-click a file, the browser loads it from file:// — straight off your disk. There is no website involved, so the browser cannot tell which website the page belongs to. Its name for that is origin null: no address, no identity.
Browsers refuse to load JavaScript modules into a page with no origin. If they allowed it, a file you downloaded could quietly read other files on your computer, and there would be no website to blame.
Serve the same folder over http:// and the page has an origin — localhost — so the rule is satisfied.
Two more things need a real origin later in this project, so this is worth remembering: saving data in the browser, and the scrambling function we use to make duels fair (A25).
Run a Server
Install Bun, a tool that both serves your files and, later, understands TypeScript:
curl -fsSL https://bun.com/install | bash
Close and reopen the terminal, then, inside your project folder:
bun ./index.html
It prints an address like http://localhost:3000. Open it. Now the canvas draws. Same files, different door.
Leave it running while you work. Edit main.js, save, refresh: your change is there.
Publish It
Commit and push:
git add .
git commit -m "A canvas that draws"
git push
Now switch on the free hosting. On your repo page: Settings → Pages, and under Build and deployment set Source: Deploy from a branch, branch main, folder / (root). Save.
Wait a minute, then open:
https://YOUR-USERNAME.github.io/kakkoi-online/
That is your game, on the internet, at your own address, for free, forever. Send it to someone.
Our version lives at online.kakkoi.dev instead of a
github.ioaddress. That is a custom domain, which needs a domain name and some DNS setup — a separate topic you do not need. Agithub.ioaddress works exactly as well.
Ask Your Assistant
My repo has index.html with a <canvas id="world"> and main.js loaded as a module.
Change main.js to also draw a red circle in the middle of the canvas, whatever
the canvas size is. Explain what each new line does, and tell me which numbers
would change if the canvas were a different size.
Check the output for: is the circle actually in the middle when you resize the canvas in index.html? Did it use canvas.width / 2 or did it hardcode 320? Hardcoded numbers are the most common thing an assistant gets away with, because the page still looks right — until something changes.
What Went Wrong When We Did This
Two real mistakes from building the version you can play, both worth recognising:
A file that looked like configuration. We had a file in the repo that was supposed to set the site's address. It did nothing at all — that file only works for a different way of publishing than the one we used. The address was empty on GitHub's side the whole time. Lesson: when something should be live and isn't, check each end separately — is the page published? is the address pointing at it? — instead of staring at the middle.
A publishing robot that never ran. Later we set up automatic publishing, and it was watching a branch called master while our code was on main. No error, no warning, just nothing happening. Lesson: a robot that never runs looks exactly like a robot that works. Go and look at the run; do not assume.
This Week's Exercise
- Create
index.htmlandmain.js, and see the blank canvas fromfile://plus the console error. - Install Bun, run
bun ./index.html, and see the same page work onlocalhost. - Push, turn on GitHub Pages, and open your live address.
- Use the prompt above to add the circle, and check whether it hardcoded the middle.
- Post your live link in the channel.
Check it worked: the live address opens on a phone, on someone else's computer, with your project folder closed.
Key Takeaways
- A canvas is a rectangle of pixels; `ctx` takes your drawing orders
- Opening a file directly gives the page no origin, so modules are blocked — serve it over http instead
- `bun ./index.html` serves your folder while you work
- GitHub Pages publishes your repo for free at your own address
- Publishing early means every later lesson goes live the moment you push