!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Worm Animation</title>
<style>
body {
margin: 0;
background: #eee;
}
svg {
width: 100vw;
height: 100vh;
display: block;
background: #eee;
}
</style>
</head>
<body>
<svg viewBox="0 0 600 600">
<g id="worm">
</g>
</svg>
<script>
const svgNS = "http://www.w3.org/2000/svg";
const worm = document.getElementById("worm");
const N = 40;
const elems = [];
for (let i = 0; i < N; i++) {
const use = document.createElementNS(svgNS, "use");
use.setAttributeNS(null, "href", "#seg");
worm.appendChild(use);
elems.push({ x: 300, y: 300, use });
}
const pointer = { x: 300, y: 300 };
let frm = 0;
function run() {
requestAnimationFrame(run);
let e = elems[0];
frm++;
const ax = (Math.cos(3 * frm) * 100) / 600;
const ay = (Math.sin(4 * frm) * 100) / 600;
e.x += (ax + pointer.x - e.x) / 10;
e.y += (ay + pointer.y - e.y) / 10;
for (let i = 1; i < N; i++) {
let e = elems[i];
let ep = elems[i - 1];
const a = Math.atan2(e.y - ep.y, e.x - ep.x);
e.x += (ep.x - e.x + Math.cos(a) * (100 - i) / 5) / 4;
e.y += (ep.y - e.y + Math.sin(a) * (100 - i) / 5) / 4;
const s = (162 + 4 * (1 - i)) / 50;
e.use.setAttributeNS(null, "transform",
`translate(${(ep.x + e.x) / 2}, ${(ep.y + e.y) / 2}) rotate(${(180 / Math.PI) * a})`);
}
}
run();
</script>
<!-- Hidden SVG shape -->
<svg style="display: none">
<symbol id="seg" viewBox="0 0 100 100">
<path d="M0,0 Q50,80 100,0 Q50,-80 0,0Z" fill="black" />
</symbol>
</svg>
</body>
</html>
HTML.