Viral Capsid Assembly Simulation with Matter.js

This article explains how to simulate the self-assembly of viral capsids using geometric polygonal subunits within the Matter.js 2D physics engine. By defining symmetric rigid bodies, mimicking thermal diffusion with stochastic forces, and programming short-range binding sites that snap complementary edges together, developers can visualize spontaneous macromolecular assembly in a web browser.

1. Designing the Polygonal Subunits (Capsomers)

Viral capsids are naturally composed of repeating protein units that fit together with precise geometric symmetry, forming structures such as icosahedrons in 3D or regular polygons in 2D.

In Matter.js, subunits should be constructed as regular polygons or trapezoidal wedges:

2. Simulating Brownian Motion

Self-assembly requires continuous kinetic agitation so subunits can collide, explore configurations, and find low-energy assembled states. Because Matter.js operates as a standard Newtonian physics engine without native thermodynamic effects, you must manually inject thermal noise.

At each tick of the engine (beforeUpdate event):

Matter.Events.on(engine, 'beforeUpdate', () => {
  subunits.forEach(body => {
    const forceMagnitude = 0.0005 * body.mass;
    const angle = Math.random() * 2 * Math.PI;
    
    Matter.Body.applyForce(body, body.position, {
      x: Math.cos(angle) * forceMagnitude,
      y: Math.sin(angle) * forceMagnitude
    });

    // Apply minor torque to induce rotational diffusion
    Matter.Body.setAngularVelocity(body, body.angularVelocity + (Math.random() - 0.5) * 0.05);
  });
});

Ensure environmental friction (body.frictionAir) is set moderately high (e.g., 0.05 to 0.1) to mimic movement through a viscous fluid.

3. Implementing Sticky Binding Interfaces

Viral subunits bond only when their complementary binding interfaces collide at the correct orientation. You can model this selectively using discrete binding points rather than whole-body attraction.

Method: Proximity-Triggered Constraints

  1. Attach virtual connection points (anchors) to the edges or vertices of each polygon.
  2. In the beforeUpdate loop, iterate through pairs of non-bonded subunits.
  3. Compute the Euclidean distance and the relative angle between their complementary binding coordinates.
  4. If both the spatial distance and angular alignment fall below a strict threshold, bridge the subunits using Matter.Constraint.create():
const bond = Matter.Constraint.create({
  bodyA: subunitA,
  pointA: localAnchorA,
  bodyB: subunitB,
  pointB: localAnchorB,
  stiffness: 0.9,
  damping: 0.1,
  length: 0
});
Matter.Composite.add(world, bond);

Using two constraints per interface prevents the subunits from freely rotating around a single pivot point, locking the geometric angle required for assembly.

4. Balancing Kinetics and Thermodynamics

Accurate self-assembly relies on avoiding "kinetic traps"—disordered, aggregate clumps that form when bonds are too strong and permanent: