Pagina nu e încă în română, așa că o vezi în engleză.

Fix an AI-made HTML game that works on a computer but not a phone

Quick answer

Match the symptom to the input code: add touch buttons for keyboard-only games, convert taps to canvas coordinates, limit touch-action to the play area, and start audio from a Start button. Keep desktop controls, then test the updated game on a phone before sharing it.

Preview my game

Uploading uses no AI credits.

On this page

The game loads on a phone, but tapping does nothing. On your computer, the arrow keys still move the player. Start by checking how the game receives input; a working keyboard listener does not supply a touch control.

Use the symptoms below to choose one repair, apply it to the HTML file, and retest. The examples fit games made with ChatGPT, Claude, Gemini, or another AI that gives you HTML and JavaScript. If you see code or a blank page before the game appears, use the file-opening guide first.

Find the symptom before changing the code

SymptomCheckRepair
Arrow keys work, taps do nothingThe game only listens for keydownAdd touch buttons that feed the same movement state
A tap selects something beside your fingerCSS shrinks the canvasConvert screen coordinates to game coordinates
Dragging moves the pageThe browser handles the gestureSet touch-action on the play area
Movement continues after releaseA release or cancellation was missedHandle pointer capture, cancellation, and window blur
Everything is tiny or the bottom is cut offViewport and height rulesSet the mobile viewport and use a responsive layout
The game is silentSound starts on page loadStart or resume audio inside a Start button's click

Add touch buttons while keeping keyboard controls

Ask your AI to connect the controls to the game's existing movement state:

Add mobile controls to this HTML game.
Keep the existing arrow-key and Space controls on desktop.
Add Left, Right, and Jump buttons with touch targets at least 48 CSS pixels wide and tall.
A held button must behave like a held key. Use pointer events and pointer capture.
Release the action on pointerup, pointercancel, lostpointercapture, and window blur.
Keep separate records for keyboard keys and each active pointer so one release cannot cancel another held input.
Keep everything in one HTML file. Add no external libraries, fetch, or eval.
Leave room below the controls so a page footer cannot cover them.

Here is the input layer to add to a game. The game loop must read held.ArrowLeft, held.ArrowRight, and held.Space; adapt those names if your game uses different actions.

<div class="pad">
  <button type="button" data-code="ArrowLeft" aria-label="Left">◀</button>
  <button type="button" data-code="ArrowRight" aria-label="Right">▶</button>
  <button type="button" data-code="Space" aria-label="Jump">●</button>
</div>
const held = {};
const keyboard = new Set();
const pointers = new Map();
const controls = new Set(["ArrowLeft", "ArrowRight", "Space"]);
function sync(code) {
  held[code] = keyboard.has(code) || [...pointers.values()].includes(code);
}
addEventListener("keydown", (e) => {
  if (!controls.has(e.code)) return;
  e.preventDefault();
  keyboard.add(e.code);
  sync(e.code);
});
addEventListener("keyup", (e) => {
  keyboard.delete(e.code);
  sync(e.code);
});
addEventListener("blur", () => {
  keyboard.clear();
  pointers.clear();
  for (const code of controls) held[code] = false;
});
for (const button of document.querySelectorAll(".pad [data-code]")) {
  const code = button.dataset.code;
  button.addEventListener("pointerdown", (e) => {
    button.setPointerCapture(e.pointerId);
    pointers.set(e.pointerId, code);
    sync(code);
  });
  const release = (e) => {
    pointers.delete(e.pointerId);
    sync(code);
  };
  button.addEventListener("pointerup", release);
  button.addEventListener("pointercancel", release);
  button.addEventListener("lostpointercapture", release);
}
// In the game loop: if (held.ArrowLeft) player.x -= speed;
.pad { display: flex; justify-content: center; gap: 16px; margin: 16px 0; }
.pad button {
  min-width: 56px; min-height: 56px; font-size: 24px;
  touch-action: none; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none;
}

The pad stays in the document layout so it can sit above a footer. Put it just below the game canvas. Keyboard controls remain available on a computer, and the buttons also work with a mouse or on a touchscreen laptop.

Pointer capture sends later events back to the pressed button when the finger moves outside it. Cancellation and loss of capture release that input too. The separate keyboard and pointer records let a player hold a key and a touch button at once without one release clearing the other.

Convert a tap to the canvas's coordinates

A canvas can have a drawing width of 400 pixels while CSS displays it only 200 pixels wide. The midpoint is 100 pixels across on screen and 200 across inside the game. Convert between those sizes before checking what the player tapped.

function toGame(canvas, e, W = canvas.width, H = canvas.height) {
  const r = canvas.getBoundingClientRect();
  return {
    x: ((e.clientX - r.left) * W) / r.width,
    y: ((e.clientY - r.top) * H) / r.height,
  };
}
canvas.addEventListener("pointerdown", (e) => {
  const p = toGame(canvas, e);
  // Use p.x and p.y in the game's hit test.
});

This assumes a visible, unrotated canvas with no CSS border or padding. Put a decorative border on a wrapper. If you scale the drawing buffer for devicePixelRatio but keep game coordinates in logical pixels, pass the game's logical width and height as W and H.

Ask your AI: “Use getBoundingClientRect() to convert pointer positions into the game's coordinate system. Keep the conversion correct after a resize or rotation, and use it for mouse input too.” MDN's pointer-event guide describes the shared event model for mouse, pen, and touch.

Keep gestures inside the play area

For a canvas that needs dragging in every direction, tell the browser that gestures inside it belong to the game:

canvas,
.pad button {
  touch-action: none;
}

Scope this rule to the controls and canvas. Leave the instructions and results outside that region so readers can scroll and zoom them. MDN documents how touch-action controls panning and zooming.

If your old code uses touchmove with preventDefault() on document, the listener may be passive. A passive listener cannot cancel scrolling. Prefer the scoped CSS rule and pointer events, or attach the necessary touch listener to the canvas with { passive: false }. The addEventListener documentation explains the passive default.

Fit the screen without disabling zoom

Check that the document's <head> contains:

<meta name="viewport" content="width=device-width, initial-scale=1">

Let the canvas shrink to the available width while preserving its aspect ratio. For a layout that fills the visible screen, 100dvh follows changes in the browser's visible viewport; a fixed pixel height can put controls below the screen. Keep ordinary scrolling available around the game.

Ask your AI to retain pinch zoom for instructions, handle portrait and landscape layouts, and recalculate the canvas size when the viewport changes. The viewport reference and CSS length reference describe these settings.

Start sound from a Start button

Start the audio inside the button's click handler. Create or resume the AudioContext there, and call the audio element's play() there as well. Keep the game playable if either operation fails. This follows MDN's Web Audio guidance.

The snippet assumes startButton, bgm (an audio element), and your existing startGame() function. Remove the second try block if the game has no background audio element.

let audio = null;
startButton.addEventListener("click", () => {
  try {
    if (!audio) audio = new AudioContext();
    if (audio.state === "suspended") audio.resume().catch(() => {});
  } catch {
    // Continue without Web Audio.
  }
  try {
    bgm.play().catch(() => {});
  } catch {
    // Continue without background audio.
  }
  startGame();
});

Call these operations directly in the click handler, before waiting on a promise or timer. A rejected play() is handled separately from starting the game; MDN's autoplay guide covers playback refusals. Also check the phone's volume and silent settings, and keep visual feedback for players using muted devices.

Test and publish the repaired game in 5 steps

1. Upload the repaired HTML

Create a Convika account. On Put your HTML page online, choose Upload a file or Paste code, then Create my preview. Uploads can be up to 2 MB and use no AI credits. If the game is already on Convika, use Update from an HTML file on that page instead of creating another page.

2. Open the account preview on your phone

Click Open preview. The account preview runs your game scripts, and its private link lasts 3 minutes. Send the link to yourself and open it promptly, or sign in on the phone and open the preview there. The anonymous upload-tool preview keeps scripts off; use the account preview for gameplay checks.

3. Try the controls with your fingers

Hold a direction, slide off the button, and lift your finger. The character should stop. Then hold a direction and Jump together. Tap the canvas center and its corners, turn the phone between portrait and landscape, and leave and return to the tab while holding a control. Check sound after pressing Start. Finally, test the computer's keyboard again.

On Free, check the preview with the Convika bar visible. Make sure it does not cover the game's controls.

4. Publish the checked version

For a new page, click Publish page, choose Public under Who can open this page?, and click Next. The first time, click Publish free to publish with the Convika bar. The Publish without the Convika bar option opens Pro's order.

For an existing game, preview the uploaded version and publish it at the same link. How to update an AI-made page covers the version steps. You can also work on the page from Claude or Codex connected through MCP, then choose when to publish the changes.

5. Check the published URL on another phone

Send the live link to someone with a different device and ask them to repeat the controls check. Record the phone, browser, and exact failed action if a problem remains. Update the same page when you fix it; the link people already have stays the same.

When the controls work but the game still fails

A separate error may involve assets, storage, or a network request. Convika's published pages run inline JavaScript, but disallow eval and new Function. External API requests can also be blocked by the page's content policy. Send your AI the actual console error and ask it to keep the repair within the host's allowed features. Publishing an HTML game explains Convika's game-hosting behavior.

Frequently asked questions

Why does my HTML game work on desktop but not mobile?

A common cause is keyboard-only input. Check whether the game responds to keydown but has no touch controls. If the game already accepts taps, check coordinate conversion, browser gestures, and audio startup separately using the symptom table.

How do I stop the character moving after I lift my finger?

Use pointer capture and release the input on pointerup, pointercancel, and lostpointercapture. Clear held inputs on window blur. Keep a separate record for each pointer so releasing one finger does not cancel another held button.

Why are taps offset on my canvas?

The canvas's displayed size and drawing size can differ. Subtract its screen position, then scale the result into the game's coordinate space using getBoundingClientRect(). Use the game's logical dimensions if its drawing buffer is scaled for pixel density.

Why is my HTML game silent on iPhone?

Check whether the code tries to play sound before a user action. Create or resume audio and start playback directly inside a Start button's click handler. Handle playback rejection and let the game start silently. Also check the device's volume and silent settings.

Can I keep keyboard controls after adding touch buttons?

Yes. Feed both inputs into the movement state the game loop already reads. The example keeps keyboard and pointer records separate, then combines them into the held table.

Sources

Try your repaired game on your phone

Upload the HTML, open your account preview, and check the controls before publishing. Update an existing game at the same link.

Preview my game

Uploading uses no AI credits.