A continuation of ch06-golden-ratio.html. The complete source identity, every recorded occurrence, and linked equations are on its first page.
Source transcript · continued
Download complete source text ↓1,871 lines · 53.0 KB
let arcX, arcY, startAngle, endAngle;
switch (i % 4) {
case 0:
arcX = x + h;
arcY = y + h;
startAngle = Math.PI;
endAngle = Math.PI * 1.5;
break;
case 1:
arcX = x;
arcY = y + w;
startAngle = Math.PI * 1.5;
endAngle = Math.PI * 2;
break;
case 2:
arcX = x;
arcY = y;
startAngle = 0;
endAngle = Math.PI * 0.5;
break;
case 3:
arcX = x + h;
arcY = y;
startAngle = Math.PI * 0.5;
endAngle = Math.PI;
break;
}
spiralCtx.arc(arcX, arcY, h, startAngle, endAngle);
spiralCtx.stroke();
// Update for next rectangle
const newW = h;
const newH = w - h;
switch (i % 4) {
case 0:
x = x + h;
break;
case 1:
y = y + (h - newH);
break;
case 2:
x = x - newH;
y = y;
break;
case 3:
break;
}
w = newW;
h = newH;
}
}
ScrollTrigger.create({
trigger: '.spiral-section',
start: 'top 60%',
onEnter: () => {
if (!spiralAnimated) {
spiralAnimated = true;
let progress = 0;
function animate() {
progress += 0.02;
drawGoldenSpiral(Math.min(progress, 1));
if (progress < 1) {
requestAnimationFrame(animate);
}
}
animate();
}
}
});
// ═══════════════════════════════════════════════════════════════
// FIBONACCI SEQUENCE
// ═══════════════════════════════════════════════════════════════
const fibSequence = document.getElementById('fibSequence');
const fibNumbers = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144];
fibNumbers.forEach((num, i) => {
const ratio = i > 0 ? (fibNumbers[i] / fibNumbers[i-1]).toFixed(6) : '-';
const isConverged = i > 6;
const item = document.createElement('div');
item.className = 'fib-item';
item.style.transitionDelay = (i * 0.1) + 's';
item.innerHTML = `
<span class="fib-number">${num}</span>
<div class="fib-bar" style="height: 0px;" data-height="${Math.min(num * 1.5, 150)}"></div>
<span class="fib-ratio ${isConverged ? 'converged' : ''}">${ratio}</span>
`;
fibSequence.appendChild(item);
});
let fibAnimated = false;
ScrollTrigger.create({
trigger: '.fibonacci-section',
start: 'top 60%',
onEnter: () => {
if (!fibAnimated) {
fibAnimated = true;
document.querySelectorAll('.fib-item').forEach((item, i) => {
setTimeout(() => {
item.classList.add('visible');
const bar = item.querySelector('.fib-bar');
bar.style.height = bar.dataset.height + 'px';
}, i * 150);
});
// Animate ratio display
setTimeout(() => {
const ratioDisplay = document.getElementById('fibRatioDisplay');
let step = 0;
const ratios = fibNumbers.slice(1).map((n, i) => fibNumbers[i+1] / fibNumbers[i]);
function showRatio() {
if (step < ratios.length) {
const ratio = ratios[step];
const diff = Math.abs(ratio - PHI);
const color = diff < 0.01 ? '#34d399' : '#f0f0f2';
ratioDisplay.innerHTML = `
<span style="color: var(--muted);">F(${step+2})/F(${step+1}) = </span>
<span style="color: ${color}; font-size: 2rem;">${ratio.toFixed(10)}</span>
<span style="color: var(--muted); font-size: 0.9rem;"> (diff: ${diff.toFixed(10)})</span>
`;
step++;
setTimeout(showRatio, 800);
} else {
ratioDisplay.innerHTML = `
<span style="color: var(--gold); font-size: 2.5rem;">Converges to phi = ${PHI.toFixed(15)}</span>
`;
}
}
showRatio();
}, fibNumbers.length * 150 + 500);
}
}
});
// ═══════════════════════════════════════════════════════════════
// PHI CALCULATION ANIMATION
// ═══════════════════════════════════════════════════════════════
let calcAnimated = false;
ScrollTrigger.create({
trigger: '.calculation-section',
start: 'top 50%',
onEnter: () => {
if (!calcAnimated) {
calcAnimated = true;
const steps = ['calcStep1', 'calcStep2', 'calcStep3', 'calcStep4'];
steps.forEach((id, i) => {
setTimeout(() => {
document.getElementById(id).classList.add('active');
}, i * 800);
});
// Animate final result
setTimeout(() => {
const result = document.getElementById('calcResult');
let value = 0;
const duration = 1500;
const start = performance.now();
function animate(timestamp) {
const elapsed = timestamp - start;
const progress = Math.min(elapsed / duration, 1);
const eased = 1 - Math.pow(1 - progress, 4);
value = eased * PHI;
result.textContent = value.toFixed(15);
if (progress < 1) {
requestAnimationFrame(animate);
}
}
requestAnimationFrame(animate);
}, steps.length * 800);
}
}
});
// ═══════════════════════════════════════════════════════════════
// CONVERGENCE CANVAS
// ═══════════════════════════════════════════════════════════════
const convergenceCanvas = document.getElementById('convergenceCanvas');
const convCtx = convergenceCanvas.getContext('2d');
let convAnimated = false;
function resizeConvergenceCanvas() {
const container = convergenceCanvas.parentElement;
convergenceCanvas.width = container.clientWidth - 60;
convergenceCanvas.height = 300;
}
resizeConvergenceCanvas();
window.addEventListener('resize', resizeConvergenceCanvas);
function drawConvergence(progress) {
const w = convergenceCanvas.width;
const h = convergenceCanvas.height;
convCtx.clearRect(0, 0, w, h);
// Background grid
convCtx.strokeStyle = 'rgba(255, 255, 255, 0.03)';
convCtx.lineWidth = 1;
for (let i = 0; i <= 10; i++) {
convCtx.beginPath();
convCtx.moveTo(0, i * h / 10);
convCtx.lineTo(w, i * h / 10);
convCtx.stroke();
convCtx.beginPath();
convCtx.moveTo(i * w / 10, 0);
convCtx.lineTo(i * w / 10, h);
convCtx.stroke();
}
// Target line (phi)
const targetY = h - (PHI / 2) * h;
convCtx.beginPath();
convCtx.strokeStyle = 'rgba(212, 175, 55, 0.5)';
convCtx.setLineDash([5, 5]);
convCtx.moveTo(0, targetY);
convCtx.lineTo(w, targetY);
convCtx.stroke();
convCtx.setLineDash([]);
// Label
convCtx.fillStyle = 'rgba(212, 175, 55, 0.8)';
convCtx.font = '11px IBM Plex Mono';
convCtx.fillText('phi = 1.618', w - 80, targetY - 5);
// Node paths
const nodes = [
{ values: generateConvergence(0.3, 0.856), color: '#60a5fa' },
{ values: generateConvergence(0.25, 0.797), color: '#a78bfa' },
{ values: generateConvergence(0.35, 0.82), color: '#fb7185' },
{ values: generateConvergence(0.28, 0.81), color: '#34d399' }
];
nodes.forEach(node => {
convCtx.beginPath();
convCtx.strokeStyle = node.color;
convCtx.lineWidth = 2;
const maxPoints = Math.floor(progress * node.values.length);
node.values.slice(0, maxPoints).forEach((val, i) => {
const x = (i / (node.values.length - 1)) * w;
const y = h - (val / 2) * h;
if (i === 0) convCtx.moveTo(x, y);
else convCtx.lineTo(x, y);
});
convCtx.stroke();
});
// Combined line
convCtx.beginPath();
convCtx.strokeStyle = '#d4af37';
convCtx.lineWidth = 3;
const combined = generateCombinedConvergence();
const maxCombined = Math.floor(progress * combined.length);
combined.slice(0, maxCombined).forEach((val, i) => {
const x = (i / (combined.length - 1)) * w;
const y = h - (val / 2) * h;
if (i === 0) convCtx.moveTo(x, y);
else convCtx.lineTo(x, y);
});
convCtx.stroke();
}
function generateConvergence(start, end) {
const points = [];
for (let i = 0; i <= 50; i++) {
const t = i / 50;
const noise = Math.sin(i * 0.5) * 0.02 * (1 - t);
const value = start + (end - start) * (1 - Math.pow(1 - t, 2)) + noise;
points.push(value);
}
return points;
}
function generateCombinedConvergence() {
const points = [];
for (let i = 0; i <= 50; i++) {
const t = i / 50;
const noise = Math.sin(i * 0.8) * 0.05 * (1 - t);
const value = 0.4 + (PHI - 0.4) * (1 - Math.pow(1 - t, 3)) + noise;
points.push(value);
}
return points;
}
ScrollTrigger.create({
trigger: '.federation-section',
start: 'top 40%',
onEnter: () => {
if (!convAnimated) {
convAnimated = true;
let progress = 0;
function animate() {
progress += 0.015;
drawConvergence(Math.min(progress, 1));
if (progress < 1) {
requestAnimationFrame(animate);
}
// Animate federated phi
if (progress > 0.8) {
const phiDisplay = document.getElementById('federatedPhi');
const displayProgress = (progress - 0.8) / 0.2;
const value = 0.8 + (PHI - 0.8) * displayProgress;
phiDisplay.textContent = value.toFixed(6);
}
}
animate();
}
}
});
// ═══════════════════════════════════════════════════════════════
// REVEAL ANIMATIONS
// ═══════════════════════════════════════════════════════════════
document.querySelectorAll('.reveal').forEach(el => {
ScrollTrigger.create({
trigger: el,
start: 'top 80%',
onEnter: () => el.classList.add('visible')
});
});
// ═══════════════════════════════════════════════════════════════
// 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'
});
}
});
});
// Initial draw
setTimeout(() => {
resizeSpiralCanvas();
resizeConvergenceCanvas();
}, 100);
</script>
</body>
</html>