How to Build a Tentacle Arm with Matter.js

This article explains how to construct a multi-segment, flexible tentacle arm using the Matter.js 2D physics engine and drive it toward target coordinates. You will learn how to configure chained rigid bodies using pin constraints, disable self-collisions, anchor the base, and apply continuous steering forces to make the tentacle naturally reach and curl toward a target.

1. Setting Up the Matter.js Environment

To create a tentacle, initialize the standard Matter.js modules: Engine, Render, Runner, Bodies, Composite, Constraint, and Vector.

const { Engine, Render, Runner, Bodies, Composite, Constraint, Vector, Body } = Matter;

const engine = Engine.create();
const world = engine.world;

const render = Render.create({
    element: document.body,
    engine: engine,
    options: {
        width: 800,
        height: 600,
        wireframes: false
    }
});

Render.run(render);
Runner.run(Runner.create(), engine);

2. Creating Chained Segments

A flexible tentacle consists of a series of small rectangular bodies connected end-to-end via revolute constraints. To prevent the segments from colliding with each other and breaking the chain, assign them a shared negative collision group.

const segmentCount = 12;
const segmentWidth = 30;
const segmentHeight = 10;
const startX = 400;
const startY = 500;
const collisionGroup = Body.nextGroup(true); // Generates a unique negative group

const segments = [];
let prevBody = null;

for (let i = 0; i < segmentCount; i++) {
    const x = startX;
    const y = startY - i * segmentWidth;

    // Scale segment size down slightly toward the tip for a tapered look
    const scale = 1 - (i / segmentCount) * 0.5;
    const body = Bodies.rectangle(x, y, segmentWidth * scale, segmentHeight * scale, {
        collisionFilter: { group: collisionGroup },
        frictionAir: 0.05, // Adds drag to simulate underwater or muscle resistance
        density: 0.001
    });

    segments.push(body);
    Composite.add(world, body);

    if (prevBody) {
        // Connect current segment to the previous segment
        const joint = Constraint.create({
            bodyA: prevBody,
            pointA: { x: 0, y: -segmentWidth / 2 },
            bodyB: body,
            pointB: { x: 0, y: segmentWidth / 2 },
            stiffness: 0.9,
            damping: 0.1,
            render: { visible: false }
        });
        Composite.add(world, joint);
    }

    prevBody = body;
}

3. Anchoring the Base

To keep the tentacle anchored in place, pin the root segment to a fixed point in the physics world:

const anchor = Constraint.create({
    pointA: { x: startX, y: startY },
    bodyB: segments[0],
    pointB: { x: 0, y: segmentWidth / 2 },
    stiffness: 1
});

Composite.add(world, anchor);

4. Directing the Tentacle Toward a Target

To make the tentacle actively reach toward a target (such as mouse coordinates or a moving game object), apply targeted physics forces before each engine update.

Rather than pulling only the tip—which makes the arm behave like a limp rope—apply a progressive force across the upper segments toward the target.

const target = { x: 400, y: 200 };

// Track mouse as target
window.addEventListener('mousemove', (event) => {
    target.x = event.clientX;
    target.y = event.clientY;
});

Matter.Events.on(engine, 'beforeUpdate', () => {
    const tip = segments[segments.length - 1];

    // Apply proportional reaching forces across the top half of the tentacle
    for (let i = Math.floor(segmentCount / 2); i < segmentCount; i++) {
        const seg = segments[i];
        
        // Calculate direction vector to target
        const direction = Vector.sub(target, seg.position);
        const distance = Vector.magnitude(direction);

        if (distance > 0) {
            const normalized = Vector.normalise(direction);
            
            // Weight force higher near the tip
            const weight = (i / segmentCount) * 0.0005;
            const force = Vector.mult(normalized, weight);

            Body.applyForce(seg, seg.position, force);
        }
    }
});

5. Tuning Flexibility and Movement