Building 60 FPS Physics Games on the Web: Lessons from Matter.js & HTML5 Canvas
Published: October 22, 2026 • By Kushal B K • 12 min read
Creating fluid, responsive browser games like Fruit Merge and Wheel Art requires strict attention to the 16.6ms frame budget. This article explores how we leveraged Matter.js for rigid body simulation, optimized canvas redraw passes, and prevented garbage collection pauses on mobile hardware.
The Core Physics Loop: Verlet Integration & Fixed Timesteps
Real-time physics engines must reconcile real-world wall-clock time with discrete numerical simulation steps. If a physics engine directly ties position updates to requestAnimationFrame(deltaTime), variable frame rates will cause erratic collision resolutions—leading to fruit objects tunneling through boundaries.
In Fruit Merge, we implement a fixed timestep accumulator:
- Fixed Time Delta: The Matter.js physics engine always advances by exactly
1000 / 60 ≈ 16.66msper step. - Accumulator Pattern: Real elapsed time is added to an accumulator pool. While the accumulator exceeds 16.66ms, we step the physics engine and subtract 16.66ms.
- Prevents Tunneling: Fast-moving objects (such as dropped cherries or rolling plums) never skip collision boundaries, regardless of device display refresh rates (60Hz, 90Hz, or 120Hz ProMotion).
Optimizing Collision Filtering with Bitmasks
Testing pairwise collisions between $N$ bodies has an algorithmic complexity of $O(N^2)$. As dozens of fruits pile up in the container, testing every fruit against every other object would quickly stall the main thread.
By configuring Matter.js collision categories and bitwise masks, we restrict collision testing exclusively to valid contact pairs:
// Bitmask Category Definitions
const WALL_CATEGORY = 0x0001;
const FRUIT_CATEGORY = 0x0002;
const SENSOR_CATEGORY = 0x0004;
// Dropped fruit body configuration
const body = Bodies.circle(x, y, radius, {
collisionFilter: {
category: FRUIT_CATEGORY,
mask: WALL_CATEGORY | FRUIT_CATEGORY // Ignores sensors
},
restitution: 0.2, // Low bounciness for natural stacking
friction: 0.1
});
Eliminating Memory Allocations in the Render Loop
The most frequent cause of micro-stutter in JavaScript games is the V8 engine garbage collector (GC). Creating temporary objects, vectors, or arrays inside the 60 FPS animation loop forces the garbage collector to perform stop-the-world sweeps.
We employ three critical rendering rules:
- Object Pooling: Particle explosions during fruit merges (sparkles and fruit splatters) reuse pre-allocated object pools rather than creating new objects via
new Particle(). - Zero Closure Creation: Avoid anonymous arrow functions inside event listeners or render calls.
- Direct Canvas Matrix Operations: Use
ctx.save(),ctx.translate(),ctx.rotate(), andctx.restore()to render rotating fruit sprites with hardware acceleration.
High-DPI Retina Scaling
Modern smartphone and tablet displays feature device pixel ratios (DPR) between 2.0 and 3.0. A canvas sized only by CSS looks fuzzy and pixelated.
TolGame games automatically match the backing canvas coordinate store to the physical hardware pixels while scaling the CSS container:
const dpr = window.devicePixelRatio || 1;
canvas.width = rect.width * dpr;
canvas.height = rect.height * dpr;
ctx.scale(dpr, dpr);
This ensures crisp vector and raster rendering on 4K monitors and mobile OLED displays without impacting simulation math.
More from TolGame Blog
View All →Unleash The Avatar: 인도의 서사시 소울라이크 RPG 완벽 분석
Aeos Games의 Unleash The Avatar에 대한 모든 정보: 비크람의 스토리, 분쇄된 차크라 전투 엔진 및 PC 출시 정보.
Grand Theft Auto VI: Engine Tech, Fire Stick Leaks, Release Timeline & Price Matrix
An exhaustive breakdown of GTA 6: RAGE 9 water physics, the Arion Kurtaj Fire Stick hack, official trailers, console vs PC release windows, and USD pricing across all editions.
50 Funny Prank Sound Effects to Play on Friends (No Download Needed)
Discover 50 hilarious, instant-play prank sound effects across 5 categories—from phantom tech glitches to meme audio. Play them straight from your browser with zero downloads.