How to Model Optical Tweezers in Matter.js
This article explains how to simulate optical tweezers trapping micro-spheres in a fluid medium using the Matter.js 2D physics engine. By translating the underlying physics—primarily the optical gradient force, fluidic drag, and Brownian motion—into computational forces, you can build an interactive, browser-based laser trap. The following sections break down the theoretical approximations and provide a direct implementation in Matter.js.
The Physical Forces to Model
An optical tweezer uses a strongly focused laser beam to trap microscopic dielectric particles. At the microscopic scale, three main physical phenomena govern the particle's behavior:
- Optical Gradient Force (Trap Force): Near the focus, the electric field gradient pulls the sphere toward the region of highest laser intensity. Within a small radius (the beam waist \(w_0\)), this acts like a Hookean spring: \[\vec{F}_{\text{trap}} = -k (\vec{r} - \vec{r}_0)\] Beyond the beam waist, the force quickly decays to zero following a Gaussian or Lorentzian profile.
- Stokes' Drag (Fluid Friction): Micro-spheres operate at low Reynolds numbers, meaning viscous drag dominates inertia.
- Brownian Motion: Collisions with surrounding liquid molecules cause random thermal fluctuations.
Setting Up the Particle and Environment
To model low Reynolds number physics in Matter.js, disable global
gravity and increase the sphere's air friction
(frictionAir) to represent viscous resistance.
const { Engine, Render, Runner, Bodies, Composite, Body, Vector, Events } = Matter;
const engine = Engine.create({
gravity: { x: 0, y: 0, scale: 0 } // Microscopic scale has negligible gravity
});
// Micro-sphere representation
const sphereRadius = 15;
const microSphere = Bodies.circle(400, 300, sphereRadius, {
frictionAir: 0.15, // Simulates fluid viscosity (Stokes' drag)
restitution: 0,
density: 0.001
});
Composite.add(engine.world, microSphere);Implementing the Trap Mechanics
The optical trap is applied continuously during the simulation loop
using the beforeUpdate event.
1. Optical Gradient Force
Define the trap center (focal point) and apply an inward force. To create a realistic trap, scale the restoring force using a Gaussian envelope so that particles far away from the laser beam are not affected:
const trapCenter = { x: 400, y: 300 };
const trapStiffness = 0.0005; // Spring constant (k)
const beamWaist = 60; // Optical beam radius
function applyOpticalForces(body, target) {
const delta = Vector.sub(target, body.position);
const distance = Vector.magnitude(delta);
if (distance === 0) return;
// Normalized direction vector toward trap center
const direction = Vector.div(delta, distance);
// Gaussian intensity profile factor: exp(-(r / w)^2)
const intensity = Math.exp(-Math.pow(distance / beamWaist, 2));
// Force magnitude: linear with distance near the center, scaled by intensity
const forceMagnitude = trapStiffness * distance * intensity;
const force = Vector.mult(direction, forceMagnitude);
Body.applyForce(body, body.position, force);
}2. Brownian Motion (Thermal Noise)
Brownian motion adds small, random velocity perturbations at every tick:
const thermalNoiseMagnitude = 0.00005;
function applyBrownianMotion(body) {
const randomAngle = Math.random() * Math.PI * 2;
const randomForce = {
x: Math.cos(randomAngle) * thermalNoiseMagnitude,
y: Math.sin(randomAngle) * thermalNoiseMagnitude
};
Body.applyForce(body, body.position, randomForce);
}Running the Simulation Loop
Attach these forces to the Matter.js engine loop:
Events.on(engine, 'beforeUpdate', () => {
applyOpticalForces(microSphere, trapCenter);
applyBrownianMotion(microSphere);
});To simulate dynamic manipulation (such as steering the trapped bead),
update trapCenter.x and trapCenter.y based on
mouse coordinates or an automated path. When the trap moves slowly, the
particle follows stably; moving the trap faster than the drag-limited
escape velocity causes the micro-sphere to fall out of the trap,
mirroring real-world optical tweezers experiments.