<div class="visHolder">
  <svg id="svg" width="" height="" viewBox="">
  <rect id="bg" x="0" y="0" width="" height="" />
  <g id="particleHolder"></g>
</svg>
  <div id="rendererHolder">
  </div>
</div>
<button id="replayButton">replay</button>
button {
  margin: 1rem;
  width: 200px;
}
// matter.js cdn:  https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.20.0/matter.min.js

const { Engine, Body, Bodies, Composite, Render} = Matter;
const engine = Engine.create();

// svg variables
const viewportWidth = 400;
const viewportHeight = 400
const w = 400;
const h = 400;
// svg namespace just in case we're creating some graphics
const namespace = "http://www.w3.org/2000/svg";


// particle vars
let particleGraphic, particleBody;

const particleGraphics = [];
const particleBodies = [];
const numberOfParticles = 50;
const particleWidth = 15;
const particleHeight = 15;
const wallThickness = 100;

// boundaries
let leftwall, rightwall, floor;

const particleHolder = document.querySelector("#particleHolder");

// ui
const replayButton = document.querySelector("#replayButton");

function initSVG() {
  const svg = document.querySelector("svg");
  svg.setAttribute("width", `${viewportWidth}`);
  svg.setAttribute("height", `${viewportHeight}`);
  svg.setAttribute("viewBox", `0 0 ${w} ${h}`);
  const bg = document.querySelector("#bg");
  bg.setAttribute("width", w);
  bg.setAttribute("height", h);
  bg.setAttribute("fill", "#eaeaea")
}

function initRenderer() {
  // create renderer
  const rendererHolder = document.querySelector("#rendererHolder");
  const render = Render.create({
    element: rendererHolder,
    engine: engine,
    options: {
      width: w,
      height: h,
      showAngleIndicator: true
    }
  });

  Render.run(render);
}

function initParticleGraphics() {
  for (let i = 0; i < numberOfParticles; i++) {
    const graphicHolder = document.createElementNS(namespace, "g");
    const particleGraphic = document.createElementNS(namespace, "rect");
    particleGraphic.setAttribute("x", -particleWidth/2);
    particleGraphic.setAttribute("y", -particleHeight/2);
    particleGraphic.setAttribute("width", particleWidth);
    particleGraphic.setAttribute("height", particleHeight);
    particleGraphic.setAttribute("fill", getRandomColor());
    
    graphicHolder.appendChild(particleGraphic);
    particleHolder.appendChild(graphicHolder);
    particleGraphics.push(graphicHolder);
  }
};

function getRandomColor() {
  return `hsl(${Math.round(Math.random() * 360)} 50% 50%)`;
};

function initParticleBodies() {
  for (let i = 0; i < numberOfParticles; i++) {
    const particleBody = Bodies.rectangle(0, 0, particleWidth, particleHeight, {
      id: `particleBody_${i}`,
      friction: 0,
      restitution: 0.9
    });
    const xpos = w/3 + Math.random() * w/3;;
    const ypos = Math.random() * (-i * particleHeight*2);
    Body.setPosition(particleBody, { x: xpos, y: ypos });

    particleBodies.push(particleBody);
  }
};

function initWallAndFloor() {
  floor = Bodies.rectangle(w/2, h + wallThickness/2, w, wallThickness, {
    isStatic: true,
    id: "floor"
  });

  leftwall = Bodies.rectangle(-wallThickness/2, h/2, wallThickness, h, {
    isStatic: true,
    id: "leftwall"
  });

  rightwall = Bodies.rectangle(w + wallThickness/2, h/2, wallThickness, h, {
    isStatic: true,
    id: "righttwall"
  });
};

function makeWorld() {
  Composite.add(engine.world, [...particleBodies, leftwall, rightwall, floor]);
};

function initUI() {
  replayButton.addEventListener("click", () => {
    particleBodies.forEach((particleBody, index) => {
      const xpos = w/3 + Math.random() * w/3;
      const ypos = -index * (particleHeight*2);
      Body.setPosition(particleBody, { x: xpos, y: ypos });
      Body.setSpeed(particleBody, 0);
    });
  });
};

function update() {
  // update the engine
  Engine.update(engine);
  // look at the particleBody position and update graphic position accordingly.
  particleGraphics.forEach((pg, index) => {
    const pos = particleBodies[index].position;
    const transformString = `translate(${pos.x} ${pos.y})`
    pg.setAttribute("transform", transformString);
  });

  window.requestAnimationFrame(update);
};

initSVG();
initRenderer();
initParticleGraphics();
initParticleBodies();
initWallAndFloor();
makeWorld();
initUI();
update();
Run Pen

External CSS

  1. https://codepen.io/aokorodu/pen/poBNOgp.css

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/matter-js/0.20.0/matter.min.js