Simulate Flagellar Motor Propulsion in Matter.js
This article details how to model low Reynolds number bacterial locomotion, driven by a rotary flagellar motor, using the Matter.js 2D physics engine. Because bacteria swim in environments dominated by viscous forces rather than inertia, standard Newtonian rigid-body physics engines require specific adjustments. Below, you will learn how to adapt Matter.js to mimic Stokes flow, construct a two-part bacterium with a counter-rotating motor, apply anisotropic drag via Resistive Force Theory (RFT), and calculate forward thrust.
Understanding Low Reynolds Number Locomotion
Bacterial swimming operates at a Reynolds number (\(Re\)) of roughly \(10^{-4}\) to \(10^{-5}\). In this regime, viscous forces completely dominate inertial forces, meaning momentum is negligible: when the motor stops, movement stops instantaneously. Matter.js is inherently an inertial physics engine, so you must negate default momentum and implement linear, non-inertial resistance to recreate this behavior accurately.
Step 1: Modeling the Cell Anatomy
A typical flagellated bacterium consists of a cell body (the soma) and a helical flagellar filament powered by a rotary motor embedded in the cell envelope.
In a 2D Matter.js simulation:
- The Soma (Body): Create an elongated capsule or
rectangle with rounded ends using
Matter.Bodies.rectangle. - The Flagellum: Represent the flagellar filament as
either a rigid rod or a series of constrained circular segments linked
by
Matter.Constraint. - The Motor: Connect the soma and flagellum using a
revolute joint (
Matter.Constraint.createwith zero length) allowing free relative rotation.
const body = Matter.Bodies.rectangle(400, 300, 60, 25, {
chamfer: { radius: 10 },
density: 0.001
});
const flagellum = Matter.Bodies.rectangle(350, 300, 50, 6, {
density: 0.0005,
collisionFilter: { group: -1 } // Prevent self-collision
});
const motor = Matter.Constraint.create({
bodyA: body,
pointA: { x: -30, y: 0 },
bodyB: flagellum,
pointB: { x: 25, y: 0 },
length: 0,
stiffness: 1
});
Matter.Composite.add(engine.world, [body, flagellum, motor]);Step 2: Overriding Inertia with Viscous Drag
To replicate Stokes flow, apply a drag force directly proportional to velocity (\(F_{drag} = -\gamma v\)) on every update tick, rather than letting Matter.js rely solely on quadratic air friction.
Within an engine.beforeUpdate event, zero out angular
and linear velocity accumulations from prior frames that exceed the
current propulsion:
Matter.Events.on(engine, 'beforeUpdate', () => {
const bodies = [body, flagellum];
const linearDragCoefficient = 0.08;
const angularDragCoefficient = 0.15;
bodies.forEach(b => {
// Stokes drag: F = -gamma * v
const dragForce = {
x: -b.velocity.x * linearDragCoefficient,
y: -b.velocity.y * linearDragCoefficient
};
Matter.Body.applyForce(b, b.position, dragForce);
// Rotational viscous damping
b.torque -= b.angularVelocity * angularDragCoefficient;
});
});Step 3: Applying Motor Torque and Counter-Rotation
The flagellar motor acts as a rotary engine that exerts equal and opposite torque on the filament and the cell body (Newton’s third law). If the flagellum rotates clockwise, the body counter-rotates counter-clockwise.
const motorTorque = 0.05;
Matter.Events.on(engine, 'beforeUpdate', () => {
// Apply counter-rotational torque
body.torque -= motorTorque;
flagellum.torque += motorTorque;
});Step 4: Generating Thrust via Resistive Force Theory (RFT)
True flagella generate thrust via 3D helical rotation. Because Matter.js operates in 2D, a rotating planar rod cannot produce net thrust without asymmetrical fluid interaction. According to Resistive Force Theory, a slender filament moving through a viscous fluid experiences roughly twice as much drag perpendicular to its axis (\(C_\perp\)) as it does parallel to its axis (\(C_\parallel\)).
You can simulate this mechanism in 2D using one of two methods:
Method A: Direct Thrust Conversion
Translate the relative rotational speed between the soma and the flagellar filament directly into an axial propulsive force applied along the body’s longitudinal axis:
Matter.Events.on(engine, 'beforeUpdate', () => {
const relativeSpin = flagellum.angularVelocity - body.angularVelocity;
const thrustMagnitude = relativeSpin * 0.002; // Coupling efficiency
const angle = body.angle;
const thrustVector = {
x: Math.cos(angle) * thrustMagnitude,
y: Math.sin(angle) * thrustMagnitude
};
Matter.Body.applyForce(body, body.position, thrustVector);
});Method B: Anisotropic Drag on Flagellar Segments
If modeling the flagellum as a traveling wave or multi-jointed tail:
- Decompose each segment's velocity into normal (\(v_\perp\)) and tangential (\(v_\parallel\)) components relative to the segment angle.
- Apply anisotropic drag: \[F_\perp = -C_\perp v_\perp\] \[F_\parallel = -C_\parallel v_\parallel\] where \(C_\perp \approx 2 \cdot C_\parallel\).
- The net difference in resistance pushes the cell forward as the segments undulate.
Tuning and Validation
To confirm the model mimics realistic bacterial mechanics:
- Check for Scallop Theorem Compliance: Reciprocal (symmetrical back-and-forth) motion must result in zero net displacement. Net movement should only occur when rotation or wave propagation breaks time-reversal symmetry.
- Observe Immediate Halting: When
motorTorqueis set to zero, forward velocity must drop to zero within 1–2 engine ticks, reflecting the non-inertial reality of microscale aquatic transport.