JSFiddle - React, Tailwind, and code Playground

by sosegon

HTML

<div id='container'>

</div>

JavaScript

import { SvJs, Gen, Noise } from "https://cdn.jsdelivr.net/npm/[email protected]/+esm"

const svg = new SvJs().addTo(document.getElementById("container"))
const svgSize = Math.min(window.innerHeight, window.innerWidth)
svg.set({
  x: 0,
  y: 0,
  width: svgSize,
  height: svgSize,
  viewBox: "0 0 1000 1000",
})

svg.create("rect").set({
  x: 0,
  y: 0,
  width: 1000,
  height: 1000,
  fill: "#000",
})

const frameSize = Gen.random(500, 700)
const frame = svg.create("rect").set({
  id: "frame",
  x: (1000 - frameSize) / 2,
  y: (1000 - frameSize) / 2,
  width: frameSize,
  height: frameSize,
  fill: "#abcdef",
  stroke: "#12121288",
  stroke_width: frameSize / 10,
})

const numCircles = Math.floor(frameSize / 20)
const circles = []

for (let i = 0; i < numCircles; i++) {
  let radius = Gen.random(frameSize / 100, frameSize / 25)

  let velocityX = Gen.random(0.1, 5, true)
  let velocityY = Gen.random(0.1, 5, true)

  let circle = svg.create("circle").set({
    cx: 500,
    cy: 500,
    r: radius,
    vx: Gen.chance() ? velocityX : -velocityX,
    vy: Gen.chance() ? velocityY : -velocityY,
    fill: `hsl(${Gen.random(0, 360)} 80% 80% / .8)`,
  })
  circles.push(circle)
}

let frameEdge = Number(frame.get('x'));
let frameInset = Number(frame.get('stroke-width')) / 2;

function animate(time) {
  if (time === undefined) time = 0

  for (let i = 0; i < numCircles; i++) {
  	let radius = Number(circles[i].get('r'));
    let lowerBound = frameEdge + radius + frameInset;
    let upperBound = frameEdge + frameSize - radius - frameInset;
    
    let vx = Number(circles[i].get("vx"))
    let vy = Number(circles[i].get("vy"))
    let cx = Number(circles[i].get("cx"))
    let cy = Number(circles[i].get("cy"))

    if (cx <= lowerBound || cx >= upperBound) {
      vx = -vx
    }
    if (cy <= lowerBound || cy >= upperBound) {
      vy = -vy
    }
    cx += vx
    cy += vy

    circles[i].set({ cx, cy, vx, vy })
  }

  requestAnimationFrame(animate)
}

animate(0)