Matter.js Plugin: matter-wrap (Making the World Round)

Introduction

Remember a scene from the comic "Smile Campus" where someone shoots forward, and after a while, the bullet hits the back of their head? The author used this dark joke to remind us that the Earth is round.

In the default Matter.js world, there is no boundary. If you throw an object in a direction beyond the canvas boundary, you may never find it again.

To make the Matter.js world "round," you can use the matter-wrap plugin.

What is matter-wrap?

matter-wrap describes itself as:

This plugin allows you to automatically wrap the position of bodies and composites such that they always stay with in the given bounds. Upon crossing a boundary the body will appear on the opposite side of the bounds, while maintaining its velocity. An example of this effect can be seen in the classic Asteroids and Pacman games.

In simple terms, it turns the scene created by Matter.js into a wraping world. When an object crosses a boundary, it appears on the opposite side while preserving its velocity and other physical properties.

Wrap effect

Here is a concrete example using matter-wrap:

Triangle wrapping

In this example, I throw a triangle beyond the boundary, and it reappears from the opposite side. That's what matter-wrap does.

Using matter-wrap

To use matter-wrap, you need to install it first. There are two ways: using CDN or npm. Choose the method that suits your project.

CDN

Download the matter-wrap.js or matter-wrap.min.js files from the matter-wrap repository and include them in your project:

<script src="../js/matter.js"></script>
<script src="../js/matter-wrap.js"></script>

<script>
// Your code
</script>

NPM

Install matter-wrap via npm:

npm install matter-wrap

Then import it in your project:

import MatterWrap from 'matter-wrap'

Usage

Let's start with a single shape to make it easy to understand. (For details on creating a canvas and objects with Matter.js, refer to "Interactive Journey in the Physical World: A Matter.js Beginner's Guide.")

Two key steps are required:

  1. Tell Matter to use the matter-wrap plugin.
  2. Configure the plugin property when creaitng elements, enabling wrap with boundary settings.

Here's an example:

<div id="canvas"></div>

<script src="../js/matter.js"></script>
<script src="../js/matter-wrap.js"></script>

<script>
  function init() {
    // Step 1: Tell matter to use matter-wrap
    Matter.use(MatterWrap);

    let Engine = Matter.Engine;
    let Render = Matter.Render;
    let Runner = Matter.Runner;
    let Composite = Matter.Composite;
    let Composites = Matter.Composites;
    let Common = Matter.Common;
    let MouseConstraint = Matter.MouseConstraint;
    let Mouse = Matter.Mouse;
    let Bodies = Matter.Bodies;

    // Create engine
    let engine = Engine.create();

    // Create renderer
    let render = Render.create({
      element: document.getElementById('canvas'),
      engine: engine,
      options: {
        width: 800,
        height: 600
      }
    });

    // Run renderer
    Render.run(render);

    // Create runner
    let runner = Runner.create();
    Runner.run(runner, engine);

    // Ground
    Composite.add(engine.world, [
      Bodies.rectangle(400, 600, 1200, 50.5, {
        isStatic: true,
        render: { fillStyle: '#060a19' }
      })
    ]);

    Composite.add(engine.world, [
      // Triangle
      Bodies.polygon(200, 460, 3, 60, {
        // Step 2: Configure plugin with wrap boundary
        plugin: {
          wrap: {
            min: {
              x: render.bounds.min.x,
              y: render.bounds.min.y
            },
            max: {
              x: render.bounds.max.x,
              y: render.bounds.max.y
            }
          }
        }
      })
    ]);

    // Mouse event
    let mouse = Mouse.create(render.canvas);
    let mouseConstraint = MouseConstraint.create(engine, {
      mouse: mouse,
      constraint: {
        stiffness: 0.2,
        render: {
          visible: false
        }
      }
    });
    Composite.add(engine.world, mouseConstraint);
  }

  init();
</script>

By using render.bounds.min.x, render.bounds.min.y, render.bounds.max.x, and render.bounds.max.y, you can get the coordinates of the canvas corners, defining the object's movement boundaries.

Note: An object will only reappear on the opposite side when it fully leaves the boundary. If only a part goes out, that part will not show on the other side.

Partial wrap

If you have multiple elements and want all of them to use matter-wrap boundaries, you can iterate through all bodies and configure them uniformly:

// ... (omitted code)

// Ground
Composite.add(engine.world, [
  Bodies.rectangle(400, 600, 1200, 50.5, { isStatic: true, render: { fillStyle: '#060a19' } })
]);

// Create a stack of balls
let stack = Composites.stack(100, 0, 10, 8, 10, 10, function(x, y) {
  return Bodies.circle(x, y, Common.random(15, 30), { restitution: 0.6, friction: 0.1 });
});

// Add everything to the world
Composite.add(engine.world, [
  stack,
  Bodies.polygon(200, 460, 3, 60), // triangle
  Bodies.polygon(400, 460, 5, 60), // pentagon
  Bodies.rectangle(600, 460, 80, 80) // square
]);

// Get all bodies
let allBodies = Composite.allBodies(engine.world);

// Set wrap plugin for each body
for (let i = 0; i < allBodies.length; i++) {
  allBodies[i].plugin.wrap = {
    min: { x: render.bounds.min.x, y: render.bounds.min.y },
    max: { x: render.bounds.max.x, y: render.bounds.max.y }
  };
}

The result is:

All bodies wrapping

That covers the whole article.

Recommended Reading

👍 Interactive Journey in the Physical World: A Matter.js Beginner's Guide

Tags: Matter.js matter-wrap physics plugin game development

Posted on Fri, 15 May 2026 17:11:24 +0000 by atrocious