{x: 34, y: 202}, {x: 41, y: 189}, {x: 48, y: 187}, {x: 58, y: 183},
{x: 69, y: 169}, {x: 94, y: 157}, {x: 107, y: 162}, {x: 117, y: 172},
{x: 125, y: 197}, {x: 134, y: 226}, {x: 143, y: 232}, {x: 157, y: 234},
{x: 167, y: 231}, {x: 177, y: 228}, {x: 187, y: 204}, {x: 196, y: 188},
{x: 206, y: 180}, {x: 217, y: 178}, {x: 238, y: 183}, {x: 257, y: 181},
{x: 277, y: 169}, {x: 291, y: 179}, {x: 301, y: 183}, {x: 307, y: 194},
{x: 322, y: 205}, {x: 338, y: 214}, {x: 350, y: 226}, {x: 374, y: 229},
{x: 381, y: 208}, {x: 385, y: 192}, {x: 386, y: 178}, {x: 387, y: 167},
rdp(0, movements.length - 1, movements, rdpPoints);
smoothPoints = generateCatmullRomPoints(rdpPoints, segmentCount);
for (let i = 0; i < smoothPoints.length - 1; i++) {
distances[i] = dist(smoothPoints[i].x, smoothPoints[i].y, smoothPoints[i + 1].x, smoothPoints[i + 1].y);
for (let p of movements) {
for (let p of smoothPoints) {
if (currentDistance < distances.reduce((a, b) => a + b, 0)) {
while (index < distances.length && distanceCovered < currentDistance) {
distanceCovered += distances[index];
let distance = distances[index];
let t = (currentDistance - distanceCovered + distance) / distance;
let x = lerp(smoothPoints[index].x, smoothPoints[index + 1].x, t);
let y = lerp(smoothPoints[index].y, smoothPoints[index + 1].y, t);
let x = smoothPoints[0].x;
let y = smoothPoints[0].y;
currentDistance += speed;
function rdp(startIndex, endIndex, allPoints, rdpPoints) {
rdpPoints.push(allPoints[startIndex]);
const nextIndex = findFurthest(allPoints, startIndex, endIndex);
if (startIndex !== nextIndex) {
rdp(startIndex, nextIndex, allPoints, rdpPoints);
rdpPoints.push(allPoints[nextIndex]);
if (endIndex !== nextIndex) {
rdp(nextIndex, endIndex, allPoints, rdpPoints);
if (endIndex === allPoints.length - 1 && !rdpPoints.includes(allPoints[endIndex])) {
rdpPoints.push(allPoints[endIndex]);
function findFurthest(movements, a, b) {
const start = movements[a];
const end = movements[b];
for (let i = a + 1; i < b; i++) {
const currentPoint = movements[i];
const d = lineDist(currentPoint, start, end);
if (d > recordDistance) {
return recordDistance > epsilon ? furthestIndex : -1;
function lineDist(c, a, b) {
const norm = scalarProjection(c, a, b);
return dist(c.x, c.y, norm.x, norm.y);
function scalarProjection(p, a, b) {
const ap = createVector(p.x - a.x, p.y - a.y);
const ab = createVector(b.x - a.x, b.y - a.y);
return createVector(a.x + ab.x, a.y + ab.y);
function generateCatmullRomPoints(movements, segments) {
result.push(movements[0]);
for (let i = 0; i < movements.length - 1; i++) {
} else if (i === movements.length - 2) {
for (let t = 0; t < 1; t += 1 / segments) {
let x = 0.5 * ((2 * p1.x) +
(2 * p0.x - 5 * p1.x + 4 * p2.x - p3.x) * t * t +
(-p0.x + 3 * p1.x - 3 * p2.x + p3.x) * t * t * t);
let y = 0.5 * ((2 * p1.y) +
(2 * p0.y - 5 * p1.y + 4 * p2.y - p3.y) * t * t +
(-p0.y + 3 * p1.y - 3 * p2.y + p3.y) * t * t * t);
result.push(movements[movements.length - 1]);