div(id='container')
  canvas(id='bezier', class='canvas', width='600', height='400')
  - for (let i = 0; i < 11; ++i)
    div(id='box'+i,class='box')
View Compiled
body { background-color:#000; overflow: hidden; }
body, html { height: 100%; width: 100%; margin: 0; padding: 0; }
.canvas { position:relative; margin:auto; top:0; left:0; }
#container { position: absolute; }
.box {
  position: absolute;
  pointer-events: none;
  top: -4px; left: -4px;
  height: 8px; width: 8px;
  background-color: red;
  animation: move1 1s linear infinite, move2 1s linear infinite, move3 1s linear infinite;
}

:root {
  --p0x: 50px;
  --p0y: 100px;
  --p1x: 330px;
  --p1y: -250px;
  --p2x: 390px;
  --p2y: 350px;
  --p3x: 30px;
  --p3y: 50px;
}

@keyframes move1 {
  from { transform: translate3d(var(--p0x), var(--p0y), 0); }
  to { transform: translate3d(var(--p1x), var(--p1y), 0); }
}
@keyframes move2 {
  to { transform: translate3d(var(--p2x), var(--p2y), 0); }
}
@keyframes move3 {
  to { transform: translate3d(var(--p3x), var(--p3y), 0); }
}

@for $i from 1 to 11 {
  #box#{$i} { animation-delay: #{-0.1 * $i}s; }
}
View Compiled
var canvas;
var ctx;
var xa = 50;
var ya = 100;
var xca = 250;
var yca = 50;
var xb = 30;
var yb = 50;
var xcb = 150;
var ycb = 150;
var WIDTH = 700;
var HEIGHT = 400;
var dragok = false;
var pointA = false;
var pointControlA = false;
var pointB = false;
var pointControlB = false;

function rect(x,y,w,h) {
 ctx.beginPath();
 ctx.rect(x,y,w,h);
 ctx.closePath();
 ctx.fill();
}

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

function init() {
 canvas = document.getElementById("bezier");
 ctx = canvas.getContext("2d");
 canvas.setAttribute('width', WIDTH);
 canvas.setAttribute('height', HEIGHT);
 return setInterval(draw, 10);
}

function draw() {
 clear();
 ctx.fillStyle = "#FAF7F8";
 rect(0,0,WIDTH,HEIGHT);
 ctx.fillStyle = "#444444";
 rect(xa - 5, ya - 5, 10, 10);
 rect(xb - 5, yb - 5, 10, 10);
 ctx.fillStyle = "#0095cd"; 
 rect(xca - 5, yca - 5, 10, 10);
 rect(xcb - 5, ycb - 5, 10, 10);
 
  lerp(xa, ya, xca, yca);
  lerp(xb, yb, xcb, ycb);
  
  bezier();
}

function lerp(pAx, pAy, pBx, pBy){
  ctx.strokeStyle = "#0095cd";
  ctx.beginPath();
  ctx.moveTo(pAx,pAy);
  ctx.lineTo(pBx,pBy);
  ctx.stroke();
}

function bezier(){
  ctx.strokeStyle ="#000";
  ctx.beginPath();
  ctx.moveTo(xa,ya);
  ctx.bezierCurveTo(xca,yca,xcb,ycb,xb,yb);
  ctx.stroke();
  
  const rootElement = document.querySelector(':root');
  rootElement.style.setProperty('--p0x', xa + 'px');
  rootElement.style.setProperty('--p0y', ya + 'px');
  rootElement.style.setProperty('--p1x', (3*xca - 3*xcb + xb) + 'px');
  rootElement.style.setProperty('--p1y', (3*yca - 3*ycb + yb) + 'px');
  rootElement.style.setProperty('--p2x', (3*xcb - 2*xb) + 'px');
  rootElement.style.setProperty('--p2y', (3*ycb - 2*yb) + 'px');
  rootElement.style.setProperty('--p3x', xb + 'px');
  rootElement.style.setProperty('--p3y', yb + 'px');
}
function myMove(e){
 if (dragok){
   if (pointA){
     xa = e.pageX - canvas.offsetLeft;
     ya = e.pageY - canvas.offsetTop;
   } else if (pointB){
     xb = e.pageX - canvas.offsetLeft;
     yb = e.pageY - canvas.offsetTop;
   } else if (pointControlA){
     xca = e.pageX - canvas.offsetLeft;
     yca = e.pageY - canvas.offsetTop;
   } else if (pointControlB){
     xcb = e.pageX - canvas.offsetLeft;
     ycb = e.pageY - canvas.offsetTop;
   }
 }
}

function myDown(e){
  /*var debugX = e.pageX - 5 - canvas.offsetLeft;
  var debugY = e.pageY -5 - canvas.offsetTop;
  console.log('x '+debugX+' y '+debugY);*/
 if (e.pageX < xa + 5 + canvas.offsetLeft && e.pageX > xa - 5 +
 canvas.offsetLeft && e.pageY < ya + 5 + canvas.offsetTop &&
 e.pageY > ya -5 + canvas.offsetTop){
  xa = e.pageX - canvas.offsetLeft;
  ya = e.pageY - canvas.offsetTop;
  dragok = true;
  pointA = true;
  canvas.onmousemove = myMove;
 } else if (e.pageX < xb + 5 + canvas.offsetLeft && e.pageX > xb - 5 +
 canvas.offsetLeft && e.pageY < yb + 5 + canvas.offsetTop &&
 e.pageY > yb -5 + canvas.offsetTop){
  xb = e.pageX - canvas.offsetLeft;
  yb = e.pageY - canvas.offsetTop;
  dragok = true;
  pointB = true;
  canvas.onmousemove = myMove;
 } else if (e.pageX < xca + 5 + canvas.offsetLeft && e.pageX > xca - 5 +
 canvas.offsetLeft && e.pageY < yca + 5 + canvas.offsetTop &&
 e.pageY > yca -5 + canvas.offsetTop){
  xca = e.pageX - canvas.offsetLeft;
  yca = e.pageY - canvas.offsetTop;
  dragok = true;
  pointControlA = true;
  canvas.onmousemove = myMove;
 } else if (e.pageX < xcb + 5 + canvas.offsetLeft && e.pageX > xcb - 5 +
 canvas.offsetLeft && e.pageY < ycb + 5 + canvas.offsetTop &&
 e.pageY > ycb -5 + canvas.offsetTop){
  xcb = e.pageX - canvas.offsetLeft;
  ycb = e.pageY - canvas.offsetTop;
  dragok = true;
  pointControlB = true;
  canvas.onmousemove = myMove;
 }
}

function myUp(){
 dragok = false;
 pointA = false;
 pointControlA = false;
 pointB = false;
 pointControlB = false;
 canvas.onmousemove = null;
}

init();
canvas.onmousedown = myDown;
canvas.onmouseup = myUp;

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.