SlowDen

Why your browser game is unplayable on a phone

By Liza · SlowDen · Published 5 August 2026

There is a specific way a web game fails that almost never shows up in a bug report, because the person who hit it did not think of it as a bug. They opened your game on a phone, tapped where the page told them to tap, and then found that the thing they were holding could not send the inputs your game was waiting for. They did not complain. They left. This article measures how often that happens across a real catalogue of 200 HTML5 games, and what the page around the game does to make it worse.

The short version. We audited the developer-written control list of every game in our catalogue. Of the 155 that have one, 68 never mention touch, tapping, swiping or a phone at all, and 26 name a keyboard key as the movement control with no touch alternative — nine of those expect two people sharing one keyboard. Meanwhile the page around the game says the opposite: on all 14 live pages for those keyboard-driven games, the copy invites the player to tap, all 14 then list a keyboard key, and none of the 14 mentions touch anywhere. And the box any on-screen controls would have to fit into measured 331 by 207 CSS pixels.

What we measured, and what these numbers are not

Everything below was measured on 5 August 2026, in Chrome on Windows, against live pages on slowden.com and against our own game registry. We are the portal in this article. That is deliberate: the interesting data here belongs to whoever runs the host page, and it is easier to publish honestly when the unflattering findings are your own.

Two separate sources, measured two different ways:

The most important caveat, stated before the numbers rather than after them: the audit measures documentation, not games. A game may accept touch perfectly well and simply not say so. Another may say so and handle it badly. Nothing here is a claim about whether any specific game works on your phone. What it does measure is what a player can find out before they commit — and that is its own problem, because a player deciding whether to start has nothing to go on except the page.

We also corrected ourselves twice while doing this, and both corrections are worth knowing if you run the same audit. Our first keyword pass classified Smartphone controls: as having no phone mention, because a word-boundary match on “phone” does not match inside “Smartphone”. It also counted the ordinary English word “space” — as in “free up space in the warehouse” — as the space bar. The load-bearing figure below is therefore a list of entries read by hand, not a regular expression’s output, and five entries are excluded with a written reason each.

Finding 1: 68 of 155 control lists never mention touch

Here is the whole catalogue, split by what the developer wrote about input.

GroupCountShare of the 155 with a list
Documents some touch or phone input path8756.1%
  … of which names an on-screen or virtual control23
  … of which splits “Desktop:” from “Mobile:” explicitly30
Mentions no touch input of any kind6843.9%
  … of which names a keyboard key as the movement control (hand-verified)2616.8%
Has no control list at all45of 200 entries

The 87 in the first row are the good news, and the shape of the good news is worth copying. Thirty of them do the single most useful thing a control list can do: they write two labelled sections, one for desktop and one for phones. “Desktop: the snake turns with the cursor. Mobile: use the joystick to rotate the snake.” That is Snake 2048 by TurtleGamesStudio, and it takes eleven extra words to tell a phone player that the game is for them.

The 45 entries with no list at all are a quieter version of the same problem. A player on a phone gets nothing: not a control scheme, not a warning, not a “works best on desktop”. They find out by starting.

Finding 2: 26 games hand the player a keyboard, and nine hand out two

This is the group where the absence of a touch path is not a documentation gap but a wall. Twenty-six control lists name a keyboard key as the way you move, and mention no alternative. Fourteen of those games are live on the site today; twelve are in the catalogue but not yet published.

A phone has no W, no A, no S, no D. It has no shift key to sprint with, no space bar to jump with, and no separate left and right mouse buttons to shoot and aim with. If a game’s only documented path through its first thirty seconds runs through those, then for a phone player there is no path.

The concentration by genre is not random:

CategoryKeyboard-driven, no touch listedEntries with a control list
Horror716
Block & Sandbox623
Racing418
Sports316
.io Games210
Funny121
Shooting116
For Girls112
2 Player15
Puzzle018

Puzzle games score zero, and that is the useful signal in the table rather than an accident. A puzzle is usually driven by pointing at a thing, and a tap is a point. First-person horror and 3D sandbox games are driven by simultaneous movement plus a look direction plus an action, which is four fingers’ worth of intent on a surface that has room for two thumbs.

The nine that cannot be ported at all as designed

Nine of the 26 are two-players-on-one-keyboard games. Stickman Kombat 2D by Ernar (Tempo Play) gives Player 1 WASD plus F and G, and Player 2 IJKL plus a colon and a quote key. Escape School Duel and Catch a Fish Obby, both by gameVgames, split the board the same way. Soccer Random and Basket Random by RHM Interactive are the elegant extreme: one key each, W for Player 1 and the up arrow for Player 2.

These are not games that need touch controls added. The mode is two people at one keyboard, and a phone has one screen roughly the size of two hands. Same-device local multiplayer is genuinely one of the nicest things a browser game can do, and it is one of the few designs where “this one is for desktop” is a legitimate answer — provided somebody says so on the page. Nobody does.

Finding 3: the page says tap, then lists the keys

This is our fault, not a developer’s, and it is the finding that made this article worth writing.

We fetched the live page for all 14 of those keyboard-driven games that are published today. All 14 returned HTTP 200. Then we read what each page tells a player:

What the live page doesPages
Invites the player to tap14 of 14
Carries a Controls section14 of 14
Names a keyboard key in it14 of 14
Mentions touch, swipe, joystick, mobile or phone anywhere0 of 14

Take Moto X3M by MadPuffers, a Racing game and one of the 14. The page says: “Wait for Moto X3M to finish loading in the player above. Click or tap inside the game window to start. Follow the in-game prompts — controls are listed below.” Below it, the controls are: WASD or arrows, up arrow to accelerate, left and right to balance, down arrow to brake.

So the page invites a tap, and then describes a game played with four keys. A player who followed the instruction exactly did the right thing and still ended up stuck. Nothing on that page is a lie in isolation; the combination is the defect. It is generated from one template, so it is the same defect 14 times.

If you list your game on any portal, this is worth knowing for a blunt reason: the host’s page copy will be written by a template that has never read your control scheme. Whatever your game needs, assume the page will not say it. The only place a phone player can reliably be told is inside your game’s own first frame.

Finding 4: the box your on-screen controls have to fit into

Suppose a developer does the right thing and adds touch controls. How much room do they get? We measured the same live game page at five widths by loading it into a same-origin frame at each exact size.

Viewport (CSS px)Game boxBox areaShare of viewport areaPage above the box
360 × 740301 × 18856,550 px²21.2%283 px
390 × 844331 × 20768,558 px²20.8%283 px
412 × 915353 × 22177,792 px²20.6%259 px
430 × 932371 × 23286,118 px²21.5%259 px
768 × 1024707 × 442312,494 px²39.7%237 px

Across every phone width the answer is remarkably stable: the game gets about one fifth of the screen. The box is width-driven with a fixed aspect ratio, so it scales with the page rather than with the space available, and the share barely moves between a small Android phone and a large iPhone.

The starker number is the page rather than the screen. At 390 by 844, the full document is 4,086 CSS pixels tall — 4.8 screenfuls — with 283 pixels of page above the game and 3,596 pixels below it. Your game is 5.07% of the height of the page it lives on.

What that means for a virtual joystick

The WCAG 2.2 Success Criterion 2.5.8, Target Size (Minimum), Level AA, requires that “the size of the target for pointer inputs is at least 24 by 24 CSS pixels”. That is an accessibility floor for any tappable target, not a size anyone would choose for a control held down mid-action. Using it as a floor, and counting the distinct inputs each control list names by hand:

Game (studio)Distinct inputs namedAt the 24 × 24 floorShare of a 331 × 207 box
Moto X3M (MadPuffers)42,304 px²3.4%
The Tall Man (Sleepless Games)63,456 px²5.0%
Escape from the Portal (Mirra Games)126,912 px²10.1%
Grand Shift Auto (oneru220)158,640 px²12.6%
Hazmob FPS: Online Shooter (Hazmob)1910,944 px²16.0%

Read that table the pessimistic way round. Those percentages are the best possible case — controls shrunk to the smallest size an accessibility standard will tolerate, packed with no gaps, and every one of those pixels still sitting on top of the game the player is trying to see.

Width is the tighter constraint than area, and this next line is an illustration rather than a measurement, because we have no measured figure for a comfortable thumb zone: if you allow two 120-pixel zones for two thumbs, that is 240 of the box’s 331 pixels of width and 120 of its 207 pixels of height. The controls stop being an overlay on the game and become most of it.

The conclusion we draw is not “draw smaller buttons”. It is that a game with nineteen inputs does not become a touch game by growing nineteen buttons. The games that survive the move are redesigned down to one or two simultaneous inputs, which is a design decision made early and cheaply, or very late and expensively.

Finding 5: nothing on the page is protecting your gestures

Say the controls fit. There is one more thing between a swipe and your game, and it is the default behaviour of the browser.

MDN’s reference for the CSS touch-action property puts it plainly: the initial value is auto, and “by default, panning (scrolling) and pinching gestures are handled exclusively by the browser”. Setting touch-action: none is what hands those gestures to the page instead.

We read the computed touch-action of every element on a live game page. The count of elements restricting touch gestures in any way was zero. The root element, the body, the embed container and the frame itself are all auto. And directly below that container sits 3,596 pixels of scrollable page.

So a vertical drag that starts on the game and is not claimed by the game is a drag the browser is entitled to read as a scroll — and the page will happily oblige by moving the game off the screen. This is the mobile counterpart of a problem desktop players know well: on desktop the arrow keys scroll the host page when the frame does not have focus, which we took apart in an earlier piece on what a page does to a game before it runs.

This one you have to fix yourself, and that is not a complaint about hosts. A portal cannot reach inside a cross-origin frame to set touch-action on your canvas — the isolation that stops a host reading your game also stops it helping. So the responsibility genuinely is the developer’s. Two lines:

/* in your game, on whatever surface receives play input */
canvas, .game-surface { touch-action: none; }
// and register listeners so preventDefault is actually allowed
el.addEventListener('touchstart', onTouch, { passive: false });
el.addEventListener('touchmove',  onMove,  { passive: false });

Chrome treats touchstart and touchmove listeners on the document as passive by default, which means preventDefault() inside them is ignored unless you opt out explicitly. A game that calls preventDefault() and still gets scrolled is usually hitting exactly this.

For completeness, the host side of this particular page is not doing anything hostile: the frame carries allowfullscreen and an allow attribute with four tokens including fullscreen, and there is no sandbox attribute. The one genuinely mobile-friendly control on the page is a Play full screen link measuring 170 by 44 CSS pixels, which comfortably clears the 24-pixel floor and does sit above the fold at 390 by 844. It opens the game in a new tab rather than calling the Fullscreen API — requestFullscreen appears nowhere in the page’s source — but for a phone player the practical effect is the right one: the game gets the whole tab instead of a fifth of the screen. It is also, by some distance, the least prominent thing on the page.

The counter-example, and it is not one of ours either

The Cube is the open-source Rubik’s-cube project by Boris Šehovac (bsehovac/the-cube, built with Three.js; no licence is stated in the repository, so we host it with credit and link the source). It is not a SlowDen game and we do not claim it. It is here because it gets everything in this article right by construction.

We read its whole game file — js.js, 101,851 bytes, re-fetched with cache: 'no-store' — and counted its input handling:

HandlerOccurrences
touchstart / touchmove / touchend4 / 4 / 2
mousedown / mousemove / mouseup3 / 2 / 2
keydown0
Reads touches and changedTouchesyes

Zero keyboard handlers. Both pointer paths bound, in parallel, with the touch path reading real touch lists rather than hoping a mouse event will be synthesised for it. Its opening prompt is Double tap to start — an instruction that is true on a phone and true on a laptop, which is a harder thing to write than it looks.

And because it is self-hosted rather than embedded, its page is the game: the canvas measured 1,536 by 695, the document height equals the viewport height exactly, the body has overflow: hidden, and the page is not scrollable. There is no page below it to scroll to. The same game inside a portal embed would have got about a fifth of the screen and 3,596 pixels of page underneath it.

That contrast is the whole argument in one comparison. Nothing about touch support requires a big screen. It requires that somebody decided which inputs the game has before deciding how many buttons to draw.

Eight things to change, roughly in order of payoff

  1. Open your build on an actual phone and finish the first thirty seconds without a keyboard. Not a narrow desktop window — that still delivers key events and a mouse. If you cannot get through the first level, neither can a fifth of the people who find you.
  2. Count your inputs, then cut. Write down every distinct action your first level needs. If the list is longer than two simultaneous inputs, the phone version is a redesign, not a control overlay. Deciding that in week one is cheap.
  3. Set touch-action: none on your play surface and register touch listeners with { passive: false }. Otherwise the browser keeps the pan gesture and the host page scrolls out from under your player.
  4. Handle pointer events, not mouse events. A single pointerdown / pointermove path covers mouse, touch and pen. If you prefer explicit touch handlers, bind both and read changedTouches rather than assuming a synthesised mouse event will arrive.
  5. Design your first frame for 331 by 207 CSS pixels. Not as a stretch goal — as the default. Set your editor to that size once and look at your title screen in it. Most title screens do not survive the experience, and it is better to find that out yourself.
  6. Say what the game needs, inside the game. One line on the title screen: “drag to steer, tap to jump”, or honestly, “this one needs a keyboard”. Do not rely on the host page — we have just shown ours saying the opposite 14 times.
  7. Make every target at least 24 by 24 CSS pixels, and much larger for anything held down. The 24-pixel figure is WCAG 2.2’s minimum, not a target.
  8. If your game really is desktop-only, say so proudly rather than quietly. Two players sharing one keyboard is a genuinely good design. It just needs a label, so a phone player finds out before they start rather than after.

Run this on your own listing

Paste this into the console on any portal page that embeds your game. It reports the geometry your game actually gets and whether anything on the page is reserving touch gestures for it.

(() => {
  const f = document.querySelector('iframe');
  if (!f) return console.log('no iframe on this page');
  const r  = f.getBoundingClientRect();
  const vw = innerWidth, vh = innerHeight;
  const doc = document.documentElement.scrollHeight;
  const restricted = [...document.querySelectorAll('*')]
    .filter(e => getComputedStyle(e).touchAction !== 'auto').length;
  console.table({
    'viewport':                 vw + ' x ' + vh,
    'your frame':               Math.round(r.width) + ' x ' + Math.round(r.height),
    'frame area':               Math.round(r.width * r.height) + ' px2',
    '% of viewport area':       ((r.width * r.height) / (vw * vh) * 100).toFixed(1) + '%',
    'page above the frame':     Math.round(r.top) + ' px',
    'page below the frame':     Math.round(doc - r.bottom) + ' px',
    'frame as % of page':       ((r.height / doc) * 100).toFixed(2) + '%',
    'elements reserving touch': restricted,
    'allowfullscreen':          f.hasAttribute('allowfullscreen'),
    'sandboxed':                f.hasAttribute('sandbox')
  });
})();

If elements reserving touch comes back as 0 and page below the frame is in the thousands, then a swipe your game does not claim will scroll your game off the screen. That is the host’s layout and your touch-action, together.

Two ways this measurement tried to fool us

Both worth knowing if you automate any of this, because both produced a confident wrong answer.

A hidden element that every DOM check called visible. We tried to test whether The Cube starts from touch input by watching its Double tap to start prompt disappear. After a real double-click the prompt was plainly gone from the screen — and every programmatic check still reported it present. Its computed display was block, its visibility was visible, checkVisibility() returned true, and innerText still contained the string. The element was faded to opacity: 0.000107. Only the rendered pixels told the truth. If you are asserting on game state from the DOM, assert on something the game sets, never on whether text looks gone.

Synthetic events did not drive the game, and the control proved it. Our dispatched TouchEvent pairs did nothing. That looks like evidence the game ignores touch — until you run the control, which we did: synthetic MouseEvent pairs did nothing either, on the canvas and on the document, while a real trusted double-click started the game immediately. So the failure was our dispatch method, not the game’s input handling. The touch test is therefore inconclusive and we are reporting it as inconclusive. The reliable evidence for The Cube’s touch support is the handler count read out of its source, above — not our test.

A negative result from an automated harness is worth roughly nothing without a positive control run the same way.

Where these numbers came from, and their limits

If you make browser games

SlowDen lists browser games and takes submissions from developers. If you have a playable web build, you can send it to us — and if it needs a keyboard, tell us, because we would rather write that on the page than let a player find out.

Slow Cook is our creative challenge for developers: pick a challenge, build a small game around it, and submit it before the round closes on 31 August 2026. Selected entries may receive a shoutout on SlowDen’s social accounts and a chance to be featured — nothing is guaranteed, and every entry is read by a person.

Submit your game See the Slow Cook round

Related reading