A continuation of index.html. The complete source identity, every recorded occurrence, and linked equations are on its first page.
Source transcript · continued
Download complete source text ↓1,700 lines · 63.7 KB
// Generate helix points
const strand1Points = [];
const strand2Points = [];
for (let i = 0; i <= numPoints; i++) {
const t = i / numPoints;
const y = (t - 0.5) * helixHeight;
const angle = t * Math.PI * 2 * turns;
strand1Points.push(new THREE.Vector3(
Math.cos(angle) * helixRadius,
y,
Math.sin(angle) * helixRadius
));
strand2Points.push(new THREE.Vector3(
Math.cos(angle + Math.PI) * helixRadius,
y,
Math.sin(angle + Math.PI) * helixRadius
));
}
// Create strands
const curve1 = new THREE.CatmullRomCurve3(strand1Points);
const curve2 = new THREE.CatmullRomCurve3(strand2Points);
const tubeGeo1 = new THREE.TubeGeometry(curve1, 200, 0.18, 12, false);
const tubeGeo2 = new THREE.TubeGeometry(curve2, 200, 0.18, 12, false);
helixGroup.add(new THREE.Mesh(tubeGeo1, strandMaterial1));
helixGroup.add(new THREE.Mesh(tubeGeo2, strandMaterial2));
// Create pairbonds
const sphereGeo = new THREE.SphereGeometry(0.22, 12, 8);
for (let i = 0; i < numPoints; i += pairbondSpacing) {
const t = i / numPoints;
const y = (t - 0.5) * helixHeight;
const angle = t * Math.PI * 2 * turns;
const p1 = new THREE.Vector3(
Math.cos(angle) * helixRadius,
y,
Math.sin(angle) * helixRadius
);
const p2 = new THREE.Vector3(
Math.cos(angle + Math.PI) * helixRadius,
y,
Math.sin(angle + Math.PI) * helixRadius
);
const sunsetColor = getSunsetColor(t);
const pairbondMat = new THREE.MeshStandardMaterial({
color: sunsetColor,
transparent: true,
opacity: 0.75,
metalness: 0.3,
roughness: 0.2,
emissive: sunsetColor,
emissiveIntensity: 0.2,
});
// Create pairbond line
const direction = new THREE.Vector3().subVectors(p2, p1);
const length = direction.length();
const center = new THREE.Vector3().addVectors(p1, p2).multiplyScalar(0.5);
const cylGeo = new THREE.CylinderGeometry(0.08, 0.08, length, 8);
const cylinder = new THREE.Mesh(cylGeo, pairbondMat);
cylinder.position.copy(center);
cylinder.quaternion.setFromUnitVectors(
new THREE.Vector3(0, 1, 0),
direction.clone().normalize()
);
helixGroup.add(cylinder);
// Connection spheres
const sphere1 = new THREE.Mesh(sphereGeo, pairbondMat.clone());
sphere1.position.copy(p1);
helixGroup.add(sphere1);
const sphere2 = new THREE.Mesh(sphereGeo, pairbondMat.clone());
sphere2.position.copy(p2);
helixGroup.add(sphere2);
}
// Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.4);
scene.add(ambientLight);
const pointLight1 = new THREE.PointLight(0xffc857, 1, 100);
pointLight1.position.set(20, 20, 20);
scene.add(pointLight1);
const pointLight2 = new THREE.PointLight(0x00d4ff, 0.8, 100);
pointLight2.position.set(-20, -20, 20);
scene.add(pointLight2);
camera.position.z = 40;
// Animation
function animate() {
requestAnimationFrame(animate);
helixGroup.rotation.y += 0.002;
stars.rotation.y += 0.0002;
stars.rotation.x += 0.0001;
nebula.rotation.y -= 0.0003;
renderer.render(scene, camera);
}
animate();
// Resize handler
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
})();
// ============================================
// NAVIGATION SCROLL EFFECT
// ============================================
const nav = document.getElementById('nav');
window.addEventListener('scroll', () => {
if (window.scrollY > 50) {
nav.classList.add('scrolled');
} else {
nav.classList.remove('scrolled');
}
});
// ============================================
// SCROLL ANIMATIONS WITH GSAP
// ============================================
gsap.registerPlugin(ScrollTrigger);
document.querySelectorAll('.animate-in').forEach((el, i) => {
gsap.fromTo(el,
{ opacity: 0, y: 30 },
{
opacity: 1,
y: 0,
duration: 0.6,
ease: 'power3.out',
scrollTrigger: {
trigger: el,
start: 'top 85%',
toggleActions: 'play none none none'
},
delay: i % 3 * 0.1
}
);
});
// ============================================
// STATS COUNTER ANIMATION
// ============================================
const statValues = document.querySelectorAll('.stat-value[data-count]');
statValues.forEach(stat => {
const target = parseInt(stat.dataset.count);
ScrollTrigger.create({
trigger: stat,
start: 'top 80%',
onEnter: () => {
gsap.to(stat, {
innerHTML: target,
duration: 2,
ease: 'power2.out',
snap: { innerHTML: 1 },
onUpdate: function() {
stat.innerHTML = Math.floor(this.targets()[0].innerHTML) + '+';
}
});
},
once: true
});
});
// ============================================
// SMOOTH SCROLL
// ============================================
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function(e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
}
});
});
</script>
</body>
</html>