Create an Origami Folding Structure in Matter.js
This article explains how to build an origami-style folding mechanism in Matter.js by modeling rigid polygonal plates and connecting them with rotational hinges. By combining Matter.js rigid bodies, custom collision filtering, and distance constraints configured as pivot joints, you can simulate kinetic origami patterns such as Miura-ori folds or accordion hinges within a 2D physics environment.
1. Representing Origami Facets as Rigid Bodies
In origami simulations, the flat polygonal facets act as rigid bodies
that do not deform. In Matter.js, these are created using either
Matter.Bodies.rectangle for uniform panels or
Matter.Bodies.fromVertices for arbitrary polygonal
shapes.
When setting up the bodies, adjust their physical properties to allow realistic movement:
const plateOptions = {
density: 0.001,
friction: 0.1,
frictionAir: 0.02,
restitution: 0.0
};
// Example: Creating two adjacent rectangular plates
const plateA = Matter.Bodies.rectangle(200, 300, 100, 10, plateOptions);
const plateB = Matter.Bodies.rectangle(295, 300, 100, 10, plateOptions);2. Preventing Self-Collision Between Adjacent Plates
Adjacent plates sharing an edge will continuously overlap at the
hinge during rotation. To prevent jitter and unrealistic physics
collisions at the joint, configure collision filtering using a shared
negative group index or discrete category
bitmasks.
const origamiGroup = Matter.Body.nextGroup(true);
plateA.collisionFilter.group = origamiGroup;
plateB.collisionFilter.group = origamiGroup;Bodies sharing a negative group value will never collide with each other, allowing them to pivot freely around shared edges.
3. Creating Revolute Hinges with Constraints
Matter.js does not have a dedicated "hinge" joint, but a revolute
joint is formed by creating a Matter.Constraint with a
length of 0 and a stiffness of
1 (or close to 1 to avoid simulation
instability). The anchor points (pointA and
pointB) must be placed at the respective shared boundary
vertices of the two plates.
// Hinge positioned at the right edge of plateA and the left edge of plateB
const hinge = Matter.Constraint.create({
bodyA: plateA,
pointA: { x: 50, y: 0 }, // Relative to plateA's center
bodyB: plateB,
pointB: { x: -50, y: 0 }, // Relative to plateB's center
length: 0,
stiffness: 0.95
});4. Actuating the Fold
Origami structures require external forces or internal torques to fold and unfold. You can actuate the joints using two primary methods:
- Linear Compression: Apply opposing forces to the outer boundary plates to compress the linkage, forcing the hinges to buckle along their degrees of freedom.
- Target Angle Constraints: Add a secondary, flexible constraint with variable length between non-adjacent points on the plates to pull them toward a folded angle, mimicking mountain or valley fold creasing.
// Actuation constraint acting as an elastic muscle across the hinge
const foldSpring = Matter.Constraint.create({
bodyA: plateA,
pointA: { x: 0, y: -10 },
bodyB: plateB,
pointB: { x: 0, y: -10 },
stiffness: 0.01,
length: 20 // Shorter length forces the plates to fold together
});5. Assembly and Simulation Loop
Add all created plates, hinges, and actuation springs to your simulation world.
const { Engine, Render, Runner, Composite } = Matter;
const engine = Engine.create();
const world = engine.world;
Composite.add(world, [plateA, plateB, hinge, foldSpring]);
const render = Render.create({
element: document.body,
engine: engine,
options: {
width: 800,
height: 600,
wireframes: false
}
});
Render.run(render);
Runner.run(Runner.create(), engine);By chaining multiple plates together in alternating mountain and valley orientations, this setup scales into complex, multi-panel origami mechanisms such as deployable solar arrays and tessellations.