<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, Render, Body, Bodies, Composite } = Matter;

/// matterjs engine and runner
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 particleRadius = 10;

// holder variable
const particleHolder = document.querySelector("#particleHolder");

let floor;
const wallThickness = 100;



// 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", `${viewportWidth}`);
  bg.setAttribute("height", `${viewportHeight}`);
  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 initParticleGraphic() {
  particleGraphic = document.createElementNS(namespace, "circle");
  particleGraphic.setAttribute("cx", "0");
  particleGraphic.setAttribute("cy", "0");
  particleGraphic.setAttribute("r", particleRadius);
  particleGraphic.setAttribute("fill", "black");
  particleHolder.appendChild(particleGraphic);
}

function initParticleBody() {
  particleBody = Bodies.circle(0, 0, particleRadius, {
    id: `particleBody`,
    friction: 0,
    restitution: 0.99
  });
  Body.setPosition(particleBody, { x: w/2, y: particleRadius });
}

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

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

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

function update() {
  // look at the particleBody position and update graphic position accordingly.
  Engine.update(engine);
  const pos = particleBody.position;
  particleGraphic.setAttribute("cx", pos.x);
  particleGraphic.setAttribute("cy", pos.y);

  window.requestAnimationFrame(update);
}

initSVG();
initRenderer();
initParticleGraphic();
initParticleBody();
initFloor();
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