DEV Community

Yassine Heddachi
Yassine Heddachi

Posted on AI-assisted

What Browser Game Platforms Get Wrong About Main-Thread Performance

Browser games are unusual web applications.

A normal content page might render some text, images, navigation, analytics, and advertising. A game platform has to do all of that while potentially preparing a second application — the game itself.

That makes main-thread performance especially important.

While working on OzoGames, one of the most useful lessons was that performance problems were often not caused by one obviously terrible script.

They came from too many reasonable tasks trying to run at the same time.

The browser doesn't care that every individual task has a legitimate reason to exist.

If enough work reaches the main thread simultaneously, the player still experiences a slow page.

The Main Thread Is a Shared Resource

JavaScript execution, layout, style calculations, event processing, and many rendering tasks depend on the browser's main thread.

Imagine the initial page load doing this:

React hydration
Analytics initialization
Ad initialization
Consent management
Recommendation rendering
Thumbnail processing
Game iframe initialization
Game SDK initialization
WebGL startup
Enter fullscreen mode Exit fullscreen mode

Individually, none of these tasks may look disastrous.

The problem is that the browser receives all of them within the same short period.

That creates contention.

A useful way to think about browser performance is not simply:

How expensive is this script?

but:

What else is happening when this script runs?

Timing matters almost as much as size.

A 40 ms Task Can Still Be a Problem

Suppose we inspect a page and see several tasks:

React hydration       42 ms
Ad initialization     38 ms
Analytics             21 ms
Recommendations       47 ms
Game SDK              55 ms
WebGL initialization  63 ms
Enter fullscreen mode Exit fullscreen mode

None of those numbers alone looks catastrophic.

But if the browser processes them almost consecutively, the user may experience a long period where the page feels unresponsive.

Something like:

42 + 38 + 21 + 47 + 55 + 63
Enter fullscreen mode Exit fullscreen mode

is very different from the same work distributed throughout the user journey.

That's why optimizing web applications purely by reducing individual bundle sizes can miss the larger problem.

Don't Initialize the Product Before the User Wants It

For browser gaming platforms, the game runtime is usually the heaviest application on the page.

Yet many platforms initialize it immediately.

That means the browser may be starting:

Website application
+
Advertising
+
Analytics
+
Game runtime
Enter fullscreen mode Exit fullscreen mode

during the same initial lifecycle.

A better architecture is often:

Page request
      ↓
Website renders
      ↓
Ads initialize
      ↓
Analytics initializes
      ↓
Player sees game information
      ↓
Player presses Play
      ↓
Game runtime initializes
Enter fullscreen mode Exit fullscreen mode

The total amount of work may be similar.

The important difference is when the work happens.

Main-Thread Performance Is About Scheduling

Developers sometimes approach performance by asking:

What can I delete?

That's useful occasionally, but a better question is often:

What can I move?

Consider analytics.

You probably shouldn't remove your analytics system just because it adds JavaScript.

Instead, perhaps some secondary analytics logic can initialize after the critical interface becomes interactive.

The same applies to recommendations, personalization, tracking, and other functionality.

A rough priority model might look like this:

Priority 1
Critical rendering and interaction

Priority 2
Business-critical initialization

Priority 3
Visible secondary UI

Priority 4
Non-critical analytics and enrichment

Priority 5
Heavy functionality triggered by user intent
Enter fullscreen mode Exit fullscreen mode

For a game page, the game runtime itself may belong in Priority 5 until the player presses Play.

Be Careful With Third-Party Scripts

Browser gaming sites often depend heavily on third-party JavaScript.

Examples include:

  • advertising
  • analytics
  • consent platforms
  • authentication
  • social widgets
  • recommendation services

It is tempting to look at a performance report, see a third-party script, and immediately blame it.

That isn't always useful.

The better process is:

  1. Measure how much main-thread time the script consumes.
  2. Determine when it executes.
  3. Identify whether execution blocks critical interaction.
  4. Check whether the script is business-critical.
  5. Decide whether initialization can happen later.

Performance work should be based on evidence, not on automatically removing everything Lighthouse highlights.

Ads Make Gaming Performance More Complicated

Advertising deserves special attention.

For many gaming platforms, advertising isn't optional. It funds the product.

That means the goal cannot simply be:

Delay every ad until later
Enter fullscreen mode Exit fullscreen mode

because doing so may harm revenue or viewability.

Instead, the architecture has to separate game loading from advertising loading.

For example:

Initial page lifecycle:

Navigation
Game metadata
Visible content
Advertising
Essential analytics
Enter fullscreen mode Exit fullscreen mode

Then:

After Play:

Game iframe
Game JavaScript
WebGL runtime
Textures
Audio
Game SDKs
Enter fullscreen mode Exit fullscreen mode

This keeps the revenue-critical systems active while preventing the game itself from competing with them unnecessarily.

Avoid Layout Work You Don't Need

JavaScript execution isn't the only contributor to main-thread pressure.

Layout recalculation can also become expensive.

Suppose a page continuously changes the size of:

Ad containers
Game containers
Recommendation sections
Images
Navigation elements
Enter fullscreen mode Exit fullscreen mode

The browser may repeatedly recalculate layout.

A gaming page should therefore reserve space for major interface elements whenever possible.

For example, an ad container should ideally have stable dimensions before the ad arrives.

Similarly, the game player area should have a predictable aspect ratio.

CSS can help:

.game-container {
  aspect-ratio: 16 / 9;
  width: 100%;
}
Enter fullscreen mode Exit fullscreen mode

Now the browser knows the expected layout before the game loads.

That helps reduce layout instability and unnecessary recalculation.

Watch What Happens After the Play Click

Initial page performance is only half of the problem.

A browser game can have excellent Core Web Vitals while still providing a terrible experience after the player presses Play.

Imagine this sequence:

Player presses Play

0 ms     iframe created
50 ms    game HTML requested
250 ms   JavaScript downloaded
600 ms   game engine initialization
900 ms   textures requested
1800 ms  WebGL initialization
2400 ms  game becomes usable
Enter fullscreen mode Exit fullscreen mode

The player waited 2.4 seconds.

Traditional page-load metrics may not describe this experience very well because the page already loaded long ago.

That's why browser gaming platforms need their own runtime metrics.

Create a Game Startup Metric

One simple approach is measuring the time between:

play_click
Enter fullscreen mode Exit fullscreen mode

and:

game_start
Enter fullscreen mode Exit fullscreen mode

For example:

let playStartedAt: number;

function onPlayClick() {
  playStartedAt = performance.now();

  startGame();
}

function onGameStarted() {
  const startupTime = performance.now() - playStartedAt;

  trackEvent("game_start", {
    startup_time_ms: Math.round(startupTime),
  });
}
Enter fullscreen mode Exit fullscreen mode

Now instead of guessing how quickly games start, you can measure it.

You might discover:

Median startup: 820 ms
P75 startup:    1,450 ms
P95 startup:    4,900 ms
Enter fullscreen mode Exit fullscreen mode

That immediately tells a more useful story.

Perhaps most players are fine, but certain games or devices have severe startup problems.

Measure the Funnel, Not Just the Page

A browser gaming platform has a natural funnel:

game_page_view
       ↓
play_click
       ↓
game_start
       ↓
fullscreen_start
       ↓
continued_play
Enter fullscreen mode Exit fullscreen mode

Each stage can expose different problems.

For example:

Lots of views, few Play clicks

Possible causes:

  • poor game thumbnail
  • confusing interface
  • intrusive advertising
  • weak game description
  • Play button isn't obvious

Lots of Play clicks, few game starts

Possible causes:

  • game runtime errors
  • slow assets
  • iframe restrictions
  • JavaScript failures
  • CDN problems

Lots of starts, short play sessions

Possible causes:

  • game quality
  • controls
  • compatibility
  • performance during gameplay

These are product questions that normal page-view analytics cannot answer.

Don't Assume Every Game Behaves the Same

One of the challenges of a large browser gaming platform is that games are not uniform.

Some games may consist of:

2 MB JavaScript
3 MB assets
Enter fullscreen mode Exit fullscreen mode

while another might require:

20 MB JavaScript
80 MB textures and audio
WebAssembly
WebGL
Multiple SDKs
Enter fullscreen mode Exit fullscreen mode

A performance strategy that works perfectly for one game can behave very differently for another.

This is why measuring individual game startup behavior is valuable.

You can eventually build reports such as:

Game A
Median startup: 620 ms

Game B
Median startup: 1.1 s

Game C
Median startup: 4.8 s
Enter fullscreen mode Exit fullscreen mode

Game C clearly deserves investigation.

Preloading Can Help — But Use It Carefully

Once games are deferred until Play, another possibility appears: intelligent preloading.

For example, if the browser detects strong intent:

Mouse enters Play button
User focuses game container
Game card remains visible for several seconds
Enter fullscreen mode Exit fullscreen mode

you might preload selected lightweight resources.

Example:

const link = document.createElement("link");

link.rel = "preconnect";
link.href = "https://games.example.com";

document.head.appendChild(link);
Enter fullscreen mode Exit fullscreen mode

This prepares the connection without downloading the entire game.

It can reduce startup latency without reintroducing the original problem of loading everything immediately.

But preloading should be measured carefully.

If users hover over ten games while browsing, aggressive preloading could create more network waste than it saves.

Performance Optimization Should Protect Product Requirements

A technically perfect Lighthouse score is not necessarily a successful website.

A gaming platform may need:

Ads
Analytics
Recommendations
Accounts
Game tracking
Consent management
Enter fullscreen mode Exit fullscreen mode

Removing all of them would undoubtedly make the page lighter.

It might also destroy the business.

Good performance engineering therefore works within product constraints.

The goal is:

Make the required systems coexist efficiently.

Not:

Delete anything that consumes CPU.

A Better Debugging Process

When a browser game page feels slow, I like this order of investigation:

1. Reproduce the problem

Use the same device/network conditions where users experience it.

2. Record the performance timeline

Look for:

  • long tasks
  • layout recalculation
  • script evaluation
  • excessive network activity

3. Identify the lifecycle stage

Is the problem happening:

Before page render?
During hydration?
During advertising initialization?
After Play?
During game runtime?
Enter fullscreen mode Exit fullscreen mode

4. Measure before changing anything

Record a baseline.

5. Make one architectural change

Avoid changing ten unrelated things simultaneously.

6. Measure again

If the improvement isn't measurable, reconsider whether the change was useful.

Browser Games Need Two Performance Budgets

For a normal site, we often think about a page performance budget.

For browser games, I think it makes sense to have two.

Website budget

Measure things like:

LCP
INP
CLS
JavaScript execution
Main-thread blocking
Initial transferred bytes
Enter fullscreen mode Exit fullscreen mode

Game startup budget

Measure:

Play → game request
Play → runtime initialization
Play → first rendered game frame
Play → interactive gameplay
Enter fullscreen mode Exit fullscreen mode

These are different experiences.

Treating them separately makes optimization much clearer.

Conclusion

The main thread isn't slow simply because one script is large.

Often, the real problem is that too many systems are demanding attention simultaneously.

Browser game platforms make this especially visible because the site itself and the game runtime are both substantial applications.

The most effective improvement isn't always:

Make everything smaller.
Enter fullscreen mode Exit fullscreen mode

Sometimes it's:

Don't make everything happen at the same time.
Enter fullscreen mode Exit fullscreen mode

Separate initial page rendering from game initialization.

Measure what happens after the player presses Play.

Protect business-critical systems such as advertising.

And optimize based on real performance evidence rather than assumptions.

Once you start treating scheduling as part of performance engineering, browser game architecture becomes much easier to reason about.

Top comments (0)