live - 60fps 1920 x 1080
<!DOCTYPE html>
<html>
<head>
<title>DNA Helix</title>
<style>
:root { --bg-color: #05070f; --strand-1: #22d3ee; --strand-2: #f472b6; }
* { margin: 0; padding: 0; }
body { height: 100vh; background: var(--bg-color); overflow: hidden; }
canvas { display: block; }
</style>
</head>
<body>
<canvas id="c"></canvas>
<script>
const cv = document.getElementById('c'), ctx = cv.getContext('2d');
const css = getComputedStyle(document.documentElement);
const bg = (css.getPropertyValue('--bg-color') || '#05070f').trim();
function hex(h){h=(h||'').trim().replace('#','');if(h.length===3)h=h.split('').map(c=>c+c).join('');const n=parseInt(h,16);return[(n>>16)&255,(n>>8)&255,n&255];}
const s1 = hex(css.getPropertyValue('--strand-1') || '#22d3ee');
const s2 = hex(css.getPropertyValue('--strand-2') || '#f472b6');
let w, h, cx, R, count, spacing;
function build() { w = cv.width = innerWidth; h = cv.height = innerHeight; cx = w / 2; R = Math.min(w * 0.17, 165); spacing = 9; count = Math.ceil(h / spacing) + 6; }
addEventListener('resize', build); build();
function bead(x, y, z, col) {
const depth = (z + 1) / 2; // 0 back .. 1 front
const rad = 2.2 + depth * 5.5;
const a = 0.18 + depth * 0.82;
ctx.globalAlpha = a * 0.35; ctx.fillStyle = `rgb(${col[0]},${col[1]},${col[2]})`;
ctx.beginPath(); ctx.arc(x, y, rad * 2.1, 0, Math.PI * 2); ctx.fill(); // soft glow
ctx.globalAlpha = a; ctx.beginPath(); ctx.arc(x, y, rad, 0, Math.PI * 2); ctx.fill(); // core
}
function step(t) {
ctx.fillStyle = bg; ctx.fillRect(0, 0, w, h);
ctx.globalCompositeOperation = 'lighter';
const scroll = t * 46;
const items = [];
for (let i = 0; i < count; i++) {
const y = ((i * spacing + scroll) % (h + spacing * 6)) - spacing * 3;
const ph = i * 0.34 + t * 1.6;
const xA = cx + Math.sin(ph) * R, zA = Math.cos(ph);
const xB = cx + Math.sin(ph + Math.PI) * R, zB = Math.cos(ph + Math.PI);
if (i % 2 === 0) items.push({ t: 'r', y, xA, xB, z: Math.min(zA, zB) - 0.01 });
items.push({ t: 'b', x: xA, y, z: zA, col: s1 });
items.push({ t: 'b', x: xB, y, z: zB, col: s2 });
}
items.sort((a, b) => a.z - b.z);
for (const it of items) {
if (it.t === 'r') {
ctx.globalAlpha = 0.12 + ((it.z + 1) / 2) * 0.28;
ctx.strokeStyle = '#9fb4d8'; ctx.lineWidth = 2;
ctx.beginPath(); ctx.moveTo(it.xA, it.y); ctx.lineTo(it.xB, it.y); ctx.stroke();
} else bead(it.x, it.y, it.z, it.col);
}
ctx.globalCompositeOperation = 'source-over'; ctx.globalAlpha = 1;
}
if (matchMedia('(prefers-reduced-motion: reduce)').matches) step(0.5);
else { let t = 0; (function loop(){ t += 0.012; step(t); requestAnimationFrame(loop); })(); }
</script>
</body>
</html> About this animation
A luminous double helix rotates and scrolls in 3D, cyan and magenta strands winding around glowing base-pair rungs.
Related