Quick answer: The “WebGL context lost” error means your game has exceeded the GPU’s available texture memory. Reduce your total texture footprint by downscaling large sprites, reducing animation frame counts, optimizing spritesheet packing, and destroying off-screen objects that are no longer needed. On mobile, keep total GPU memory usage under 256 MB.
Your Construct 3 game runs fine on your development machine, but players report a black screen with “WebGL context lost” on their phones or lower-end laptops. Or maybe you see it yourself after playing for a few minutes as more levels load. The game freezes, the canvas goes black, and sometimes the browser tab crashes entirely. This is a GPU memory problem, and it is fixable.
The Symptom
The game runs normally for some period — anywhere from a few seconds to several minutes — and then the screen goes black or white. The browser’s developer console shows an error like WebGL: CONTEXT_LOST_WEBGL: loseContext: context lost. In some browsers, you may see a more descriptive message about the GPU process crashing or being unable to allocate a texture.
On mobile devices, the crash often happens faster because mobile GPUs have far less memory available. A game that works perfectly on a desktop with a dedicated GPU may crash within seconds on a phone. The issue is especially common on older Android devices, iPads running Safari, and Chromebooks with integrated graphics.
If you are using Construct 3’s built-in preview, you may not see the error at all because your development machine has enough GPU memory. The problem only surfaces when you export and test on actual target devices or when players report the crash via bug reports.
What Causes This
There are four primary causes of WebGL context loss in Construct 3 games:
1. Total texture memory exceeds GPU limits. Every image in your game occupies GPU memory when loaded. A single 2048x2048 pixel RGBA image uses 16 MB of GPU memory (2048 × 2048 × 4 bytes). If your game has 50 unique sprite types with multiple animation frames, you can easily reach hundreds of megabytes. Mobile GPUs typically have a hard limit of 256–512 MB for all WebGL contexts combined, and that memory is shared with the rest of the browser and operating system.
2. Large background images or tilemaps. A common pattern is using a single large image for a level background. A 4000x2000 pixel background uses 32 MB of GPU memory — and if you have multiple layouts each with their own background loaded into memory, the total adds up fast. Tilemaps are more efficient because they reuse a single tileset texture, but if the tileset image itself is very large, it still consumes significant memory.
3. Spritesheet fragmentation and poor packing. Construct 3 packs sprites into spritesheets (texture atlases) at export time. If your sprites have wildly different sizes or if you have many single-frame sprites, the packing algorithm may produce spritesheets with large amounts of wasted space. Each spritesheet occupies its full dimensions in GPU memory regardless of how much of that space contains actual pixels.
4. Not releasing textures from previous layouts. When you navigate between layouts, Construct 3 needs to load textures for the new layout. If the previous layout’s textures are not released first (because objects are still referenced or the layout uses shared spritesheets), both sets of textures coexist in GPU memory simultaneously. This peak memory usage during transitions is often what triggers the context loss.
The Fix
Step 1: Audit your project’s texture memory usage.
Calculate the approximate GPU memory your game needs. For each sprite, multiply its dimensions by 4 bytes per pixel, then multiply by the number of animation frames:
// GPU memory per sprite = width * height * 4 bytes * frame_count
//
// Example calculations:
// Player sprite: 128x128, 24 frames = 128*128*4*24 = 1.5 MB
// Enemy sprite: 64x64, 12 frames = 64*64*4*12 = 192 KB
// Background: 1920x1080, 1 frame = 1920*1080*4 = 8.3 MB
// Tileset: 2048x2048, 1 frame = 2048*2048*4 = 16 MB
//
// Total all sprites and images to estimate peak GPU usage.
// Target: under 256 MB for mobile, under 512 MB for desktop.
You can also check the exported spritesheet sizes in your export folder. Each PNG spritesheet gets uploaded to the GPU at its full dimensions.
Step 2: Reduce individual sprite sizes and frame counts.
The biggest wins usually come from reducing your largest assets:
// Before: Player character with 60 animation frames at 256x256
// GPU memory: 256*256*4*60 = 15.7 MB
// After: Reduce to 128x128 and 30 frames (remove near-duplicate frames)
// GPU memory: 128*128*4*30 = 1.96 MB
// Savings: 87%!
// Tips:
// - Scale down sprites that are displayed small on screen
// - Remove animation frames that are barely different from adjacent frames
// - Use Construct 3's animation speed to slow down fewer frames
// instead of adding more frames for smooth animation
Step 3: Optimize spritesheet settings in Project Properties.
Configure the spritesheet export settings to match your target platform:
// Project Properties > Advanced
Spritesheet size: 2048x2048 // Use 2048 for mobile targets
// Use 4096 for desktop-only
// In sprite editor, check "Crop" is enabled to trim transparent pixels
// This reduces the area each frame occupies in the spritesheet
// Group related sprites into the same spritesheet by using
// similar sizes. A 32x32 sprite and a 2000x1000 background
// in the same sheet wastes enormous space.
Step 4: Manage layout transitions to reduce peak memory.
Use a lightweight transition layout between heavy layouts to allow the engine to release textures:
// Instead of going directly from Level1 to Level2:
// Level1 (100 MB textures) -> Level2 (100 MB textures)
// Peak: 200 MB during transition!
// Use a minimal loading layout in between:
// Level1 -> LoadingScreen -> Level2
// LoadingScreen has almost no textures, so:
// Peak: ~100 MB (Level1 unloads, then Level2 loads)
Event: On function "GoToNextLevel"
Action: System > Set NextLayout to "Level2"
Action: System > Go to layout "LoadingScreen"
// In LoadingScreen event sheet:
Event: On start of layout
Action: System > Wait 0.1 seconds
Action: System > Go to layout NextLayout
Step 5: Handle context loss gracefully with recovery events.
Even with optimizations, some low-end devices may still lose context. Add handlers so the game recovers instead of crashing:
// System events for WebGL context management:
Event: System > On context lost
Action: System > Set time scale to 0 // Pause the game
Action: StatusText > Set text "Recovering graphics..."
Action: StatusText > Set visible true
Event: System > On context restored
Action: System > Set time scale to 1 // Resume the game
Action: StatusText > Set visible false
Step 6: Use the scripting API to monitor GPU memory at runtime.
// In a script block or JS file, you can query WebGL info:
const canvas = document.querySelector("canvas");
const gl = canvas.getContext("webgl2");
if (gl) {
const ext = gl.getExtension("WEBGL_debug_renderer_info");
if (ext) {
const renderer = gl.getParameter(ext.UNMASKED_RENDERER_WEBGL);
console.log("GPU:", renderer);
}
// Check max texture size supported:
const maxSize = gl.getParameter(gl.MAX_TEXTURE_SIZE);
console.log("Max texture size:", maxSize);
}
Why This Works
WebGL context loss is fundamentally a resource exhaustion problem. The GPU has a finite amount of video memory (VRAM), and every texture your game uses must be uploaded to that memory before it can be rendered. When the total exceeds what the GPU can provide, the browser forcibly destroys the WebGL context to prevent the entire system from becoming unstable.
Reducing texture dimensions has a quadratic effect on memory usage — halving a sprite’s width and height reduces its memory footprint by 75%, not 50%. This is why downscaling sprites is the single most effective optimization. Similarly, removing animation frames has a linear but still significant effect.
The transition layout technique works because Construct 3 releases a layout’s textures when that layout is no longer active (assuming the textures are not shared with the current layout). By inserting a minimal layout between two heavy ones, you ensure the first layout’s textures are freed before the second layout’s textures are loaded, keeping peak memory usage close to the maximum of the two layouts rather than their sum.
Context restoration handlers do not prevent the underlying problem, but they give the game a chance to recover when the browser restores the WebGL context. Without these handlers, the game simply freezes or shows a black screen with no way back.
“Test on the lowest-end device your players will use. If your game survives a 2019 Android phone with 2 GB of RAM, it will survive anything.”
Related Issues
If your game is not crashing but simply not loading at all, check loader layout stuck not progressing for issues with the loading screen. If variables reset after a crash recovery, see global variable resets on layout restart to ensure state is preserved. For multiplayer games where the context loss disconnects players, multiplayer signaling connection failures covers reconnection strategies. And if objects reappear in the wrong visual order after context restoration, Z order not updating at runtime explains the rendering pipeline.
Halve the image size, quarter the memory. Always do the math.