Phaser Games on Mobile and as a PWA
Mobile gaming represents the largest segment of the games market, and browser-based games are uniquely positioned to reach mobile players without the friction of app store downloads. A Phaser game that loads quickly in a mobile browser and plays well with touch controls can reach millions of players through a simple URL. Adding PWA capabilities on top makes the experience nearly indistinguishable from a native app.
Configure the Scale Manager for Mobile Screens
The Scale Manager controls how your game canvas fits into the browser viewport. For mobile games, set the scale mode to Phaser.Scale.FIT, which scales the canvas to fill the available space while maintaining the original aspect ratio. This ensures your game looks correct on screens ranging from small phones to large tablets without distortion.
Set the autoCenter property to Phaser.Scale.CENTER_BOTH to center the canvas horizontally and vertically within the viewport. On devices where the screen aspect ratio does not match your game's ratio, this produces symmetric letterboxing on either the sides or top and bottom rather than having the game stuck in a corner.
Lock the orientation if your game is designed for a specific layout. Set the scale configuration's orientation property to landscape or portrait to display a "rotate your device" message when the player holds their phone the wrong way. Most action games work best in landscape, while puzzle and casual games often suit portrait. If your game works in both orientations, skip the lock and let the Scale Manager adapt.
Handle the full-screen toggle by listening for a tap or button press and calling this.scale.startFullscreen(). Full-screen mode removes the browser's address bar and navigation buttons, giving your game the maximum screen real estate. Some mobile browsers automatically enter a minimal UI mode for games, but explicitly requesting full screen provides a consistent experience across browsers and devices.
Set the game's base resolution to match the most common mobile screen ratios. A 360 by 640 base at 16:9 works well for portrait mobile games, while 640 by 360 works for landscape. The Scale Manager handles upscaling to higher-resolution screens, and the pixel art rendering mode preserves crisp edges when scaling up by integer multiples.
Optimize Touch Input for Mobile Play
Mobile players interact with your game through imprecise finger taps on a glass screen, which is fundamentally different from the pixel-precise mouse clicks of desktop play. Every interactive element needs a touch target of at least 48 by 48 CSS pixels, though 64 by 64 is better for fast-paced games. Set the hit area of interactive sprites larger than their visual size using setInteractive with a custom hit area.
Position on-screen controls in the lower corners of the screen where thumbs naturally rest when holding a phone. A directional pad or virtual joystick goes in the bottom-left corner, and action buttons go in the bottom-right. Keep the controls within the bottom 30% of the screen height so they do not obscure the gameplay area. Make the controls semi-transparent with an alpha of 0.3 to 0.5 so the game remains visible behind them.
Prevent default browser touch behaviors that interfere with gameplay. Disable the pull-to-refresh gesture, the long-press context menu, and the double-tap zoom through CSS touch-action properties and JavaScript event.preventDefault() calls. Without these overrides, players will accidentally trigger browser features while trying to play your game, creating a frustrating experience.
Provide immediate visual and haptic feedback for every touch interaction. When a button is pressed, change its tint, scale it down slightly, and play a short click sound. If the device supports vibration through the Vibration API, add a subtle 10-millisecond vibration pulse on button presses. This tactile feedback compensates for the lack of physical button feel and confirms to the player that their touch was registered.
Improve Performance for Mobile Hardware
Mobile devices have significantly less GPU memory, CPU power, and thermal headroom than desktop computers. A game that runs smoothly at 60 FPS on a laptop might stutter on a mid-range phone if it pushes too many draw calls, uses too much texture memory, or runs expensive JavaScript in the update loop.
Reduce draw calls by packing sprites into texture atlases and batching rendering. Every texture switch costs performance, so combining all sprites for a scene into one or two atlas images lets the renderer batch them into fewer draw calls. Phaser's multi-texture batching helps automatically, but the biggest gains come from reducing the number of unique textures in active use.
Manage texture memory by loading only the assets needed for the current scene and unloading assets from previous scenes. Mobile GPUs typically have 256 MB to 1 GB of texture memory, and exceeding it causes stuttering as the GPU swaps textures in and out. Keep individual texture atlases under 2048 by 2048 pixels for broad compatibility, as some older mobile GPUs do not support 4096-pixel textures.
Limit the number of active physics bodies. Each body requires collision checks every frame, and the cost scales roughly as O(n^2) for naive collision detection. Use object pooling for projectiles and particles, disable physics on off-screen objects, and destroy objects that are no longer needed. For scenes with many enemies, stagger their updates across frames so not all enemies run expensive AI logic on the same frame.
Profile your game on actual mobile hardware using Chrome DevTools' remote debugging feature. Connect your phone to your computer via USB, open chrome://inspect in desktop Chrome, and access the performance profiler for your mobile browser tab. The profile shows exactly where frame time is being spent, whether it is JavaScript execution, rendering, or garbage collection. Target a consistent 16.6ms frame time (60 FPS) and optimize the slowest operations first.
Create a Web App Manifest
The web app manifest is a JSON file that tells the browser how to present your game when installed as a PWA. Create a file named manifest.json in your project root with the required properties: name (the full game title), short_name (a condensed version for the home screen), start_url (the URL to load when the game launches), display (set to "fullscreen" for games), and icons (an array of icon images at multiple sizes).
Provide icons at 192x192 and 512x512 pixels at minimum. These are used for the home screen icon, the splash screen during loading, and the app listing in the browser's "Installed Apps" section. Use a maskable icon format that allows the operating system to crop and reshape the icon to match the device's icon style, whether rounded squares on Android or rounded rectangles on iOS.
Set the theme_color and background_color properties to match your game's visual identity. The theme color is used for the browser's address bar and the system tray on Android, while the background color fills the splash screen before your game loads. Choose colors that make the transition from splash screen to game feel seamless.
Link the manifest in your HTML file's head section with a link tag: rel="manifest" href="/manifest.json". Also add meta tags for mobile web app capability on iOS: apple-mobile-web-app-capable set to "yes" and apple-mobile-web-app-status-bar-style set to "black-translucent." These meta tags ensure iOS devices also present your game in full-screen mode when launched from the home screen.
Set Up a Service Worker for Offline Play
A service worker is a JavaScript file that runs in the background and intercepts network requests. For a game PWA, the service worker's primary job is to cache all game assets during the first visit so subsequent visits and offline play load entirely from the local cache.
Register the service worker in your main JavaScript file with navigator.serviceWorker.register('/sw.js'). In the service worker file, listen for the "install" event and use caches.open() to create a named cache. Then use cache.addAll() with an array of all your game files: the HTML entry point, JavaScript bundles, CSS files, the Phaser library, all sprite images, audio files, and the manifest. This pre-caches everything the game needs to run.
In the "fetch" event listener, intercept every network request and check if the requested resource exists in the cache. If it does, return the cached version. If not, fetch from the network, cache the response for future use, and return it to the game. This cache-first strategy makes your game load instantly on repeat visits and keeps working when the device loses internet connectivity.
Version your cache names to handle updates. When you deploy a new version of your game, change the cache name in the service worker. The new service worker will install alongside the old one, create a new cache with the updated files, and activate on the next visit. In the "activate" event, delete old caches to free storage space. Without versioning, players would continue playing the cached old version even after you push updates.
Test and Deploy Your PWA Game
Use Google Chrome's Lighthouse tool to audit your PWA. Open DevTools, navigate to the Lighthouse tab, and run a PWA audit. Lighthouse checks for a valid manifest, a registered service worker, HTTPS hosting, offline capability, and other PWA best practices. Fix any issues it identifies before deploying.
Test on real mobile devices, not just desktop emulation. Browser developer tools can simulate screen sizes and touch events, but they cannot replicate actual mobile performance, touch feel, or the installation flow. Test on at least one Android device and one iOS device, with both high-end and mid-range hardware if possible. Pay attention to loading time on a 3G connection, which many mobile users still experience.
Deploy your game to HTTPS hosting, which is required for service workers and PWA installation. Static hosting services like Netlify, Vercel, and Cloudflare Pages provide free HTTPS hosting with automatic certificate management and CDN distribution. Upload your built game files and the manifest, and the hosting provider handles SSL and caching headers.
For app store distribution, wrap your PWA in a Trusted Web Activity (TWA) for the Google Play Store or use Capacitor to build native containers for both iOS and Android. A TWA is the lightest approach because it runs your web content directly in Chrome without a WebView layer, providing full performance and automatic updates whenever you deploy to your web host. Capacitor provides more native integration options but requires maintaining a native project alongside your web project.
Optimize for mobile by configuring the Scale Manager, building touch-friendly controls, and managing performance. Add a web manifest and service worker to turn your game into a PWA that installs on the home screen and plays offline, reaching mobile players without app store friction.