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:

  1. The Soma (Body): Create an elongated capsule or rectangle with rounded ends using Matter.Bodies.rectangle.
  2. The Flagellum: Represent the flagellar filament as either a rigid rod or a series of constrained circular segments linked by Matter.Constraint.
  3. The Motor: Connect the soma and flagellum using a revolute joint (Matter.Constraint.create with 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:

  1. Decompose each segment's velocity into normal (\(v_\perp\)) and tangential (\(v_\parallel\)) components relative to the segment angle.
  2. Apply anisotropic drag: \[F_\perp = -C_\perp v_\perp\] \[F_\parallel = -C_\parallel v_\parallel\] where \(C_\perp \approx 2 \cdot C_\parallel\).
  3. The net difference in resistance pushes the cell forward as the segments undulate.

Tuning and Validation

To confirm the model mimics realistic bacterial mechanics: