Quick answer: Use the Touch object instead of Mouse, ensure the viewport meta tag is correct, and add touch-action: none to the canvas. These eliminate the 300ms tap delay and browser-side gesture handling.

Your Construct 3 game plays smoothly on desktop. Deploy as a PWA on Android and taps feel like they’re registering 200ms late. The character’s jump comes well after the player’s finger touches the screen. It’s playable but doesn’t feel responsive.

The 300ms Tap Delay

Mobile browsers historically waited about 300ms after touchend to fire a click event, in case the user was about to do a double-tap-to-zoom. Modern browsers (Chrome 32+, Safari 13+) remove the delay if the page declares itself touch-aware via the viewport meta tag. If your exported PWA lacks the correct viewport setting, the delay returns — and 300ms of input latency is brutal for games.

Fix 1: Use the Touch Object

Replace Mouse-based input with Touch-based events:

Touch events fire on the actual touchstart/touchend without the click delay. Even with the viewport fix, this is the more reliable cross-platform path for game input.

Fix 2: Confirm the Viewport Meta Tag

Open Project Properties → Advanced → Viewport. Ensure it’s set to scale appropriately. The exported HTML should include:

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

If the exported HTML lacks this tag, browsers assume desktop viewport and re-introduce tap delay. After export, inspect index.html and confirm the tag is present.

Fix 3: touch-action: none

Even with touch events, the browser may intercept gestures for scrolling or zoom. Add CSS to the canvas:

canvas {
  touch-action: none;
  -webkit-touch-callout: none;
  user-select: none;
}

Add via Project Properties → Custom CSS or by adding a script that injects the rule on load. touch-action: none tells the browser the canvas handles all touch gestures itself — no scrolling, no zoom, no pull-to-refresh.

Fix 4: Prevent Pull-to-Refresh

On Android Chrome PWAs, pulling down at the top of the page triggers refresh. Disable in your manifest:

{
  "display": "fullscreen",
  "orientation": "landscape"
}

Fullscreen PWAs don’t expose the browser UI, so pull-to-refresh doesn’t apply. Combined with touch-action: none, every gesture is yours.

Fix 5: Vibration Polyfill

If you use navigator.vibrate via a script for haptic feedback and it’s wrapped in a debounce or async wrapper, calls can queue and arrive late. Call it synchronously inline with the input event:

// On Touch event sheet
Browser.ExecJS("navigator.vibrate && navigator.vibrate(20)");

Inline ExecJS calls run in the same JS task as the touch handler, with minimal latency.

Verifying

Run a back-to-back test with a desktop browser and the Android PWA. Tap a known-instant action (e.g., a single-frame visual response). Use a high-frame-rate camera or screen recording at 60+ FPS to count frames between touch and response. Target: 1–3 frames (16–50ms). Before the fix, you may see 12+ frames (200+ ms).

“Touch over Mouse, viewport over default, touch-action: none over the OS. Three knobs to turn for responsive web games on mobile.”

Test on real Android devices early — emulator touch latency doesn’t match real device latency.