<div class="container">
  <div class="box">
    <canvas></canvas>
    <p>t = <span class="text"></span></p>
  </div>
</div>
.container {
  width: 100%;
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
}
.box {
  position: relative;
  border: 1px solid #ccc;
  padding: 30px;
}
p {
  position: absolute;
  top: 30px;
  left: 30px;
}
canvas {
  display: block;
}
View Compiled
const T_SIZE = 100
const WIDTH = 200
const HEIGHT = 200
const PADDING = 5

const P0 = { x: 0, y: 0 }
const P3 = { x: 1, y: 1 }

class Canvas {
  constructor(el) {
    this.el = el
    this.ctx = el.getContext('2d')

    this.el.width = WIDTH
    this.el.height = HEIGHT
    this.ctx.strokeStyle = '#444'
    this.ctx.lineWidth = 2

    this.points = []
  }

  addPoint(normalizedX, normalizedY) {
    const x = PADDING + normalizedX * (WIDTH - PADDING * 2)
    const y = PADDING + (1 - normalizedY) * (HEIGHT - PADDING * 2)

    this.points.push({ x, y })
  }

  clearPoints() {
    this.points = []
  }

  draw() {    
    this.ctx.beginPath()

    this.points.forEach(({ x, y }, i) => {
      if (i === 0) {
        this.ctx.moveTo(x, y)
      } else {
        this.ctx.lineTo(x, y)
      }
    })

    this.ctx.stroke()
  }

  clear() {
    this.ctx.clearRect(0, 0, WIDTH, HEIGHT)
  }
}

class Bezier {
  constructor(p1, p2) {
    this.p1 = p1
    this.p2 = p2
  }

  calc(t) {
    return {
      x: Math.pow(1 - t, 3) * P0.x + 3 * Math.pow(1 - t, 2) * t * this.p1.x + 3 * (1 - t) * Math.pow(t, 2) * this.p2.x + Math.pow(t, 3) * P3.x,
      y: Math.pow(1 - t, 3) * P0.y + 3 * Math.pow(1 - t, 2) * t * this.p1.y + 3 * (1 - t) * Math.pow(t, 2) * this.p2.y + Math.pow(t, 3) * P3.y
    }
  }
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms))  
}

function round(val, digit = 2) {
  return Math.round(val * Math.pow(10, digit)) / Math.pow(10, digit)
}

async function main() {
  const p1 = { x: 0.76, y: 0 }
  const p2 = { x: 0.24, y: 1 }

  const bezier = new Bezier(p1, p2)
  const canvas = new Canvas(document.querySelector('canvas'))
  const text = document.querySelector('.text')

  const drawBezier = async () => {
    for (let i = 0; i < T_SIZE; i++) {
      const t = i / (T_SIZE - 1)
      const { x, y } = bezier.calc(t)
    
      canvas.addPoint(x, y)
      canvas.clear()
      canvas.draw()

      text.textContent = round(t)

      await sleep(16)
    }
  }

  const loop = async () => {
    canvas.clearPoints()

    await drawBezier()
    await sleep(800)

    loop()
  }

  loop()
}

main()
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.