Web performance: fast to load, smooth to play

Play this lesson

Fast or forgotten

Remy shares a Hyper Shards link in our Discord. A player taps it on the bus, on a cheap phone with a weak signal. Eight seconds of black screen later, they close the tab. They never even saw the title screen.

Players don't wait. web.dev reports that the BBC lost an extra 10% of users for every extra second its site took to load. Web performance is how fast a page loads and how smoothly it responds. For a game it has two halves: fast to load, and smooth to play for a whole hour.

Bolt says: Smooth frames have their own lesson, 60 frames per second, in Stage 3. This one is about loading, the web's speed scores and long play sessions.

A download budget

Every file must travel over the player's connection before the game can start. A performance budget is a limit the team agrees on, like pocket money: "the first load stays under 3 MB". If a change breaks the budget, something else has to shrink.

Bolt says: A robot can guard the budget: a CI check that fails the pull request when the game's files grow past the limit.

Core Web Vitals: three numbers

Google grades websites with three Core Web Vitals. A page counts as good when at least 75% of visits hit each target (the 75th percentile), measured separately on phones and computers.

Read the numbers

PageSpeed Insights, mobile
play.ourstudio.com, real players, last 28 days(75th percentile) LCP   3.9 sINP   140 msCLS   0.02

Which vital misses "good", and which fix fits it?

  1. LCP: the title screen waits for big files, so show the logo and Start button first
  2. INP: taps are slow, so make every button bigger
  3. CLS: the page jumps, so remove the logo
Show the answer

LCP: the title screen waits for big files, so show the logo and Start button first

Good LCP is 2.5 seconds or less, so 3.9 needs improvement (poor starts above 4). INP at 140 ms is under 200, and CLS at 0.02 is under 0.1, so both are already good.

Lighthouse and PageSpeed Insights

Load only what's needed first

Lazy loading means fetching a file only when it is needed. A player on World 1 doesn't need World 5's boss yet.

A canvas never counts for LCP, so the HTML title logo usually does. Show it first.

Bolt says: Second visits should cost almost nothing. Cloudflare keeps copies near players (the Cloudflare lesson), the browser gets a tiny "304 Not Modified" for files that haven't changed, and our service worker serves the rest from the device.

Load order

boot.js
await Assets.load('title-logo.png');showTitleScreen();await Assets.load('world1.json');await Assets.load('music-all-worlds.mp3'); // 18 MBenableStartButton();

Players stare at a grey Start button for ages. Which line should change?

  1. Line 1
  2. Line 3
  3. Line 4
Show the answer

Line 4

Line 4 makes Start wait for 18 MB of music for every world. World 1 only needs its own track, and the rest can load in the background once Start works. Lines 1 and 3 load what the first screen and first world really need.

Memory leaks in long sessions

The browser's garbage collector frees memory that nothing points to any more. A memory leak is memory something still points to, but the game never uses again. After an hour of waves, the game stutters, then the phone closes the tab.

In DevTools, the Memory panel takes heap snapshots: play 10 waves, snapshot, play 10 more, snapshot, and compare what grew.

Bug hunt

boss.js
function startBossWave() {  const boss = new Sprite(bossTexture);  stage.addChild(boss);  window.addEventListener('resize',    () => fitToScreen(boss));  return boss;}function endBossWave(boss) {  stage.removeChild(boss);}

Line 9 takes the boss off the stage, so the garbage collector can now clean up every old boss.

Show the answer

False

Lines 4 and 5 add a resize listener that still points at the boss, and nothing removes it. Every boss wave leaves one more boss stuck in memory. The fix: remove the listener with removeEventListener and call boss.destroy() when the wave ends.

Test on a cheap phone

Our laptops are far faster than most players' phones. A cheap phone has a slower processor, so the same JavaScript takes longer to start, and less memory, so a leak crashes it sooner.

DevTools can slow down the CPU and network to imitate a phone, and Lighthouse already tests as one. But the honest test is real: keep a cheap Android phone in the studio, play for 30 minutes, and plug it into the laptop with USB so Chrome DevTools can watch it. That is called remote debugging.

Bolt says: Hyper Shards is light and quick now. Next: the phone stores, where Garden Defense will live.

Fact-checked 9 October 2026