"use client"; import React, { useEffect, useRef } from "react"; interface Props { className?: string; } const DNAHelix: React.FC = ({ className }) => { const canvasRef = useRef(null); useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext("2d"); if (!ctx) return; // Dimensions based on parent container let width = canvas.width = canvas.parentElement?.clientWidth || window.innerWidth; let height = canvas.height = canvas.parentElement?.clientHeight || window.innerHeight; let animationFrameId: number; let time = 0; const handleResize = () => { if (canvas.parentElement) { width = canvas.width = canvas.parentElement.clientWidth; height = canvas.height = canvas.parentElement.clientHeight; } }; window.addEventListener("resize", handleResize); const render = () => { ctx.clearRect(0, 0, width, height); time += 0.02; // Rotation speed const strandGap = 40; // Vertical distance between "base pairs" const amplitude = 50; // Width of the helix const frequency = 0.015; // Tightness of the loops // Position helix on the right side (85% of width) to keep content clear const centerX = width * 0.85; ctx.lineWidth = 2; // Calculate number of points based on container height const numPoints = Math.ceil(height / strandGap) + 5; for (let i = 0; i < numPoints; i++) { // Scroll the helix slowly downward const y = i * strandGap - (time * 10) % strandGap; // Calculate rotation phase const phase = y * frequency + time; // Strand 1 (Cyan) const x1 = centerX + Math.sin(phase) * amplitude; // Strand 2 (Emerald) - Offset by PI const x2 = centerX + Math.sin(phase + Math.PI) * amplitude; // Depth calculation for 3D effect (fade when "back") const depth1 = Math.cos(phase); const depth2 = Math.cos(phase + Math.PI); // Map depth (-1 to 1) to opacity (0.2 to 0.8) const alpha1 = (depth1 + 1) / 2 * 0.6 + 0.2; const alpha2 = (depth2 + 1) / 2 * 0.6 + 0.2; // Draw Connector Line (Base Pair) ctx.beginPath(); ctx.moveTo(x1, y); ctx.lineTo(x2, y); ctx.strokeStyle = `rgba(34, 211, 238, 0.05)`; // Very faint connector ctx.stroke(); // Draw Strand 1 Particle ctx.beginPath(); ctx.arc(x1, y, 4 + depth1, 0, Math.PI * 2); ctx.fillStyle = `rgba(34, 211, 238, ${alpha1})`; // Cyan ctx.fill(); // Draw Strand 2 Particle ctx.beginPath(); ctx.arc(x2, y, 4 + depth2, 0, Math.PI * 2); ctx.fillStyle = `rgba(52, 211, 153, ${alpha2})`; // Emerald ctx.fill(); } animationFrameId = requestAnimationFrame(render); }; render(); return () => { window.removeEventListener("resize", handleResize); cancelAnimationFrame(animationFrameId); }; }, []); return ( ); }; export default DNAHelix;