How to Show Velocity Vectors in Matter.js

Visualizing velocity vectors in Matter.js is an essential debugging technique for physics simulations. While Matter.js provides a built-in debug flag for quick checks, the most reliable and customizable method is using the afterRender event to draw vectors directly onto the canvas using native HTML5 2D Canvas context methods. This guide covers both the built-in renderer option and the custom canvas drawing implementation to visualize the speed and direction of moving bodies.

Method 1: Using the Built-In Debug Option

Matter.js has a built-in flag within its default renderer specifically for displaying velocity vectors. You can enable it when initializing the Render module or modify it dynamically on an existing instance.

const render = Matter.Render.create({
    element: document.body,
    engine: engine,
    options: {
        width: 800,
        height: 600,
        wireframes: false,
        showVelocity: true // Enables built-in velocity vectors
    }
});

When showVelocity is set to true, Matter.js renders lines from the center of each moving body indicating its current trajectory. However, this feature is restricted to wireframe mode in some Matter.js builds and offers limited control over vector scaling, color, and line thickness.


Method 2: Custom Drawing with afterRender

For complete control over vector length, styling, and arrowheads, hook into the afterRender event. This fires immediately after Matter.js clears and draws the scene, allowing you to draw custom graphics on top of the physics bodies.

Matter.Events.on(render, 'afterRender', () => {
    const context = render.context;
    const bodies = Matter.Composite.allBodies(engine.world);
    const vectorScale = 5; // Multiplier to make vectors clearly visible

    context.beginPath();

    bodies.forEach(body => {
        // Skip static bodies since they have zero velocity
        if (body.isStatic) return;

        const startX = body.position.x;
        const startY = body.position.y;
        const endX = startX + body.velocity.x * vectorScale;
        const endY = startY + body.velocity.y * vectorScale;

        // Draw the velocity line
        context.moveTo(startX, startY);
        context.lineTo(endX, endY);
    });

    context.lineWidth = 2;
    context.strokeStyle = '#ff3333'; // High-contrast color (red)
    context.stroke();
});

Adding Arrowheads to Vectors

To indicate direction clearly, you can extend the afterRender logic by drawing an arrowhead at the tip of each vector line.

function drawArrow(ctx, fromX, fromY, toX, toY, headLength = 8) {
    const dx = toX - fromX;
    const dy = toY - fromY;
    const angle = Math.atan2(dy, dx);

    // Only draw arrowheads if the body is actually moving
    if (Math.hypot(dx, dy) < 1) return;

    ctx.moveTo(fromX, fromY);
    ctx.lineTo(toX, toY);

    // Draw arrowhead branches
    ctx.lineTo(
        toX - headLength * Math.cos(angle - Math.PI / 6),
        toY - headLength * Math.sin(angle - Math.PI / 6)
    );
    ctx.moveTo(toX, toY);
    ctx.lineTo(
        toX - headLength * Math.cos(angle + Math.PI / 6),
        toY - headLength * Math.sin(angle + Math.PI / 6)
    );
}

Matter.Events.on(render, 'afterRender', () => {
    const ctx = render.context;
    const bodies = Matter.Composite.allBodies(engine.world);
    const vectorScale = 4;

    ctx.beginPath();
    ctx.strokeStyle = '#00ffcc';
    ctx.lineWidth = 2;

    bodies.forEach(body => {
        if (body.isStatic) return;

        const startX = body.position.x;
        const startY = body.position.y;
        const endX = startX + body.velocity.x * vectorScale;
        const endY = startY + body.velocity.y * vectorScale;

        drawArrow(ctx, startX, startY, endX, endY);
    });

    ctx.stroke();
});

Key Considerations