|
|
document.addEventListener('DOMContentLoaded', function() { |
|
|
|
|
|
const canvas = document.getElementById('canvas'); |
|
|
const ctx = canvas.getContext('2d'); |
|
|
|
|
|
|
|
|
canvas.width = window.innerWidth; |
|
|
canvas.height = window.innerHeight; |
|
|
|
|
|
|
|
|
let centerX = canvas.width / 2; |
|
|
let centerY = canvas.height / 2; |
|
|
|
|
|
|
|
|
let animationRunning = true; |
|
|
let showParticles = true; |
|
|
let showConnections = true; |
|
|
|
|
|
|
|
|
let brainwaveState = "alpha"; |
|
|
let frequencyMultiplier = 1.0; |
|
|
let amplitudeMultiplier = 1.0; |
|
|
let coherenceMultiplier = 1.0; |
|
|
|
|
|
|
|
|
let activeHarmonics = null; |
|
|
|
|
|
|
|
|
let aiThoughts = []; |
|
|
let aiResponseLastUpdate = 0; |
|
|
|
|
|
|
|
|
const config = { |
|
|
|
|
|
brainRadius: Math.min(canvas.width, canvas.height) * 0.05, |
|
|
brainColor: '#2271ff', |
|
|
brainPulseSpeed: 0.005, |
|
|
brainPulseRange: 0.3, |
|
|
|
|
|
|
|
|
fieldCount: 5, |
|
|
fieldLayers: 3, |
|
|
fieldWaveCount: 8, |
|
|
fieldMaxRadius: Math.min(canvas.width, canvas.height) * 0.4, |
|
|
fieldBaseOpacity: 0.15, |
|
|
fieldColors: ['#4e95ff', '#19d4ff', '#00c8ff', '#0096ff', '#0073ff'], |
|
|
fieldWaveSpeed: 0.6, |
|
|
|
|
|
|
|
|
particleCount: 150, |
|
|
particleRadius: 2, |
|
|
particleBaseColor: '#ffffff', |
|
|
particleSpeed: 0.5, |
|
|
particleInfluenceThreshold: 100, |
|
|
particleInfluenceStrength: 0.015, |
|
|
|
|
|
|
|
|
connectionOpacity: 0.15, |
|
|
connectionThreshold: 100, |
|
|
maxConnections: 3, |
|
|
|
|
|
|
|
|
brainwaves: { |
|
|
delta: { |
|
|
pulseSpeed: 0.002, |
|
|
pulseRange: 0.5, |
|
|
waveSpeed: 0.3, |
|
|
particleInfluence: 0.01, |
|
|
color: '#3a5ad9', |
|
|
particleBehavior: 'slow', |
|
|
aiDescription: "Deep, unconscious processing. Particles move slowly in predictable patterns." |
|
|
}, |
|
|
theta: { |
|
|
pulseSpeed: 0.004, |
|
|
pulseRange: 0.4, |
|
|
waveSpeed: 0.5, |
|
|
particleInfluence: 0.015, |
|
|
color: '#4f7ff5', |
|
|
particleBehavior: 'meditative', |
|
|
aiDescription: "Meditative state. Particles form flowing circular patterns." |
|
|
}, |
|
|
alpha: { |
|
|
pulseSpeed: 0.006, |
|
|
pulseRange: 0.3, |
|
|
waveSpeed: 0.7, |
|
|
particleInfluence: 0.02, |
|
|
color: '#2271ff', |
|
|
particleBehavior: 'calm', |
|
|
aiDescription: "Relaxed, creative state. Balanced particle movement with emerging patterns." |
|
|
}, |
|
|
beta: { |
|
|
pulseSpeed: 0.01, |
|
|
pulseRange: 0.2, |
|
|
waveSpeed: 1.0, |
|
|
particleInfluence: 0.03, |
|
|
color: '#008aff', |
|
|
particleBehavior: 'active', |
|
|
aiDescription: "Active thinking state. Particles move rapidly with clear structured connections." |
|
|
}, |
|
|
gamma: { |
|
|
pulseSpeed: 0.015, |
|
|
pulseRange: 0.15, |
|
|
waveSpeed: 1.5, |
|
|
particleInfluence: 0.04, |
|
|
color: '#00c8ff', |
|
|
particleBehavior: 'hyperactive', |
|
|
aiDescription: "Higher consciousness state. Rapid particle movement forms complex geometric patterns." |
|
|
} |
|
|
}, |
|
|
|
|
|
|
|
|
harmonics: { |
|
|
fibonacci: { |
|
|
sequence: [1, 1, 2, 3, 5, 8, 13, 21], |
|
|
description: "Particles organizing into spiral patterns", |
|
|
color: '#ffd700' |
|
|
}, |
|
|
goldenRatio: { |
|
|
ratio: 1.618, |
|
|
description: "Particles forming balanced, proportional structures", |
|
|
color: '#ff9d00' |
|
|
}, |
|
|
prime: { |
|
|
sequence: [2, 3, 5, 7, 11, 13, 17, 19], |
|
|
description: "Particles arranging in prime-based geometrical structures", |
|
|
color: '#ff5e00' |
|
|
} |
|
|
} |
|
|
}; |
|
|
|
|
|
|
|
|
let brain = { |
|
|
pulsePhase: 0 |
|
|
}; |
|
|
|
|
|
let fields = []; |
|
|
let particles = []; |
|
|
|
|
|
|
|
|
for (let i = 0; i < config.fieldCount; i++) { |
|
|
const field = { |
|
|
id: i, |
|
|
color: config.fieldColors[i % config.fieldColors.length], |
|
|
waves: [], |
|
|
angle: (Math.PI * 2 / config.fieldCount) * i, |
|
|
phase: Math.random() * Math.PI * 2 |
|
|
}; |
|
|
|
|
|
|
|
|
for (let j = 0; j < config.fieldWaveCount; j++) { |
|
|
field.waves.push({ |
|
|
progress: j / config.fieldWaveCount, |
|
|
speed: config.fieldWaveSpeed * (0.8 + Math.random() * 0.4), |
|
|
amplitude: 0.5 + Math.random() * 0.5 |
|
|
}); |
|
|
} |
|
|
|
|
|
fields.push(field); |
|
|
} |
|
|
|
|
|
|
|
|
for (let i = 0; i < config.particleCount; i++) { |
|
|
particles.push({ |
|
|
x: Math.random() * canvas.width, |
|
|
y: Math.random() * canvas.height, |
|
|
radius: config.particleRadius * (0.5 + Math.random()), |
|
|
baseSpeed: config.particleSpeed * (0.5 + Math.random()), |
|
|
angle: Math.random() * Math.PI * 2, |
|
|
color: config.particleBaseColor, |
|
|
influenced: false, |
|
|
influenceFactor: 0, |
|
|
|
|
|
age: 0, |
|
|
evolution: 0, |
|
|
harmonicFactor: 0, |
|
|
structureRole: null |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
function setupControls() { |
|
|
|
|
|
document.getElementById('deltaBrain').addEventListener('click', () => setBrainwaveState('delta')); |
|
|
document.getElementById('thetaBrain').addEventListener('click', () => setBrainwaveState('theta')); |
|
|
document.getElementById('alphaBrain').addEventListener('click', () => setBrainwaveState('alpha')); |
|
|
document.getElementById('betaBrain').addEventListener('click', () => setBrainwaveState('beta')); |
|
|
document.getElementById('gammaBrain').addEventListener('click', () => setBrainwaveState('gamma')); |
|
|
|
|
|
|
|
|
document.getElementById('frequencySlider').addEventListener('input', function() { |
|
|
frequencyMultiplier = parseFloat(this.value); |
|
|
document.getElementById('frequencyValue').textContent = frequencyMultiplier.toFixed(1); |
|
|
updateAIResponse(); |
|
|
}); |
|
|
|
|
|
document.getElementById('amplitudeSlider').addEventListener('input', function() { |
|
|
amplitudeMultiplier = parseFloat(this.value); |
|
|
document.getElementById('amplitudeValue').textContent = amplitudeMultiplier.toFixed(1); |
|
|
updateAIResponse(); |
|
|
}); |
|
|
|
|
|
document.getElementById('coherenceSlider').addEventListener('input', function() { |
|
|
coherenceMultiplier = parseFloat(this.value); |
|
|
document.getElementById('coherenceValue').textContent = coherenceMultiplier.toFixed(1); |
|
|
updateAIResponse(); |
|
|
}); |
|
|
|
|
|
|
|
|
document.getElementById('fibonacciButton').addEventListener('click', function() { |
|
|
toggleHarmonic('fibonacci'); |
|
|
}); |
|
|
|
|
|
document.getElementById('goldenRatioButton').addEventListener('click', function() { |
|
|
toggleHarmonic('goldenRatio'); |
|
|
}); |
|
|
|
|
|
document.getElementById('primeButton').addEventListener('click', function() { |
|
|
toggleHarmonic('prime'); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
function setBrainwaveState(state) { |
|
|
brainwaveState = state; |
|
|
|
|
|
|
|
|
const brainwaveConfig = config.brainwaves[state]; |
|
|
config.brainPulseSpeed = brainwaveConfig.pulseSpeed; |
|
|
config.brainPulseRange = brainwaveConfig.pulseRange; |
|
|
config.fieldWaveSpeed = brainwaveConfig.waveSpeed; |
|
|
config.particleInfluenceStrength = brainwaveConfig.particleInfluence; |
|
|
config.brainColor = brainwaveConfig.color; |
|
|
|
|
|
|
|
|
document.querySelectorAll('.brainwave-buttons button').forEach(btn => { |
|
|
btn.style.backgroundColor = '#2a2a2a'; |
|
|
btn.style.color = 'white'; |
|
|
}); |
|
|
|
|
|
|
|
|
const activeBtn = document.getElementById(state + 'Brain'); |
|
|
if (activeBtn) { |
|
|
activeBtn.style.backgroundColor = brainwaveConfig.color; |
|
|
activeBtn.style.color = 'black'; |
|
|
} |
|
|
|
|
|
updateAIResponse(); |
|
|
} |
|
|
|
|
|
|
|
|
function toggleHarmonic(harmonic) { |
|
|
if (activeHarmonics === harmonic) { |
|
|
|
|
|
activeHarmonics = null; |
|
|
document.querySelectorAll('.harmonics-section button').forEach(btn => { |
|
|
btn.style.backgroundColor = '#2a2a2a'; |
|
|
btn.style.color = 'white'; |
|
|
}); |
|
|
} else { |
|
|
|
|
|
activeHarmonics = harmonic; |
|
|
|
|
|
|
|
|
document.querySelectorAll('.harmonics-section button').forEach(btn => { |
|
|
btn.style.backgroundColor = '#2a2a2a'; |
|
|
btn.style.color = 'white'; |
|
|
}); |
|
|
|
|
|
|
|
|
const harmonicConfig = config.harmonics[harmonic]; |
|
|
const btnId = harmonic + 'Button'; |
|
|
const btn = document.getElementById(btnId); |
|
|
if (btn) { |
|
|
btn.style.backgroundColor = harmonicConfig.color; |
|
|
btn.style.color = 'black'; |
|
|
} |
|
|
} |
|
|
|
|
|
updateAIResponse(); |
|
|
} |
|
|
|
|
|
|
|
|
document.getElementById('togglePlay').addEventListener('click', function() { |
|
|
animationRunning = !animationRunning; |
|
|
this.textContent = animationRunning ? 'Pause' : 'Play'; |
|
|
if (animationRunning) animate(); |
|
|
}); |
|
|
|
|
|
document.getElementById('toggleParticles').addEventListener('click', function() { |
|
|
showParticles = !showParticles; |
|
|
}); |
|
|
|
|
|
document.getElementById('toggleConnections').addEventListener('click', function() { |
|
|
showConnections = !showConnections; |
|
|
}); |
|
|
|
|
|
|
|
|
window.addEventListener('resize', function() { |
|
|
canvas.width = window.innerWidth; |
|
|
canvas.height = window.innerHeight; |
|
|
config.brainRadius = Math.min(canvas.width, canvas.height) * 0.05; |
|
|
config.fieldMaxRadius = Math.min(canvas.width, canvas.height) * 0.4; |
|
|
centerX = canvas.width / 2; |
|
|
centerY = canvas.height / 2; |
|
|
}); |
|
|
|
|
|
|
|
|
function drawBrain() { |
|
|
const brainwaveConfig = config.brainwaves[brainwaveState]; |
|
|
const adjustedPulseSpeed = config.brainPulseSpeed * frequencyMultiplier; |
|
|
const adjustedPulseRange = config.brainPulseRange * amplitudeMultiplier; |
|
|
|
|
|
brain.pulsePhase += adjustedPulseSpeed; |
|
|
const pulseFactor = 1 + Math.sin(brain.pulsePhase) * adjustedPulseRange; |
|
|
|
|
|
|
|
|
const gradient = ctx.createRadialGradient( |
|
|
centerX, centerY, 0, |
|
|
centerX, centerY, config.brainRadius * pulseFactor |
|
|
); |
|
|
gradient.addColorStop(0, 'rgba(255, 255, 255, 1)'); |
|
|
gradient.addColorStop(0.7, config.brainColor); |
|
|
gradient.addColorStop(1, 'rgba(34, 113, 255, 0)'); |
|
|
|
|
|
|
|
|
ctx.beginPath(); |
|
|
ctx.arc(centerX, centerY, config.brainRadius * pulseFactor, 0, Math.PI * 2); |
|
|
ctx.fillStyle = gradient; |
|
|
ctx.fill(); |
|
|
|
|
|
|
|
|
ctx.beginPath(); |
|
|
ctx.arc(centerX, centerY, config.brainRadius * 0.6 * pulseFactor, 0, Math.PI * 2); |
|
|
ctx.fillStyle = 'rgba(255, 255, 255, 0.3)'; |
|
|
ctx.fill(); |
|
|
|
|
|
|
|
|
if (activeHarmonics) { |
|
|
drawHarmonicPatterns(pulseFactor); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function drawHarmonicPatterns(pulseFactor) { |
|
|
const harmonicConfig = config.harmonics[activeHarmonics]; |
|
|
ctx.strokeStyle = harmonicConfig.color; |
|
|
ctx.lineWidth = 1; |
|
|
|
|
|
if (activeHarmonics === 'fibonacci') { |
|
|
|
|
|
const a = config.brainRadius * 0.1; |
|
|
let fib1 = 1; |
|
|
let fib2 = 1; |
|
|
|
|
|
ctx.beginPath(); |
|
|
for (let i = 0; i < 7; i++) { |
|
|
const nextFib = fib1 + fib2; |
|
|
const radius = a * fib2 / 5 * pulseFactor; |
|
|
ctx.arc(centerX, centerY, radius, 0, Math.PI / 2); |
|
|
ctx.translate(radius, 0); |
|
|
ctx.rotate(Math.PI / 2); |
|
|
fib1 = fib2; |
|
|
fib2 = nextFib; |
|
|
} |
|
|
ctx.stroke(); |
|
|
} |
|
|
else if (activeHarmonics === 'goldenRatio') { |
|
|
|
|
|
const maxRadius = config.brainRadius * pulseFactor; |
|
|
const b = 0.4; |
|
|
|
|
|
ctx.beginPath(); |
|
|
for (let theta = 0; theta < 8 * Math.PI; theta += 0.1) { |
|
|
const r = maxRadius * Math.pow(Math.E, b * theta) / (8 * Math.PI); |
|
|
const x = centerX + r * Math.cos(theta); |
|
|
const y = centerY + r * Math.sin(theta); |
|
|
|
|
|
if (theta === 0) { |
|
|
ctx.moveTo(x, y); |
|
|
} else { |
|
|
ctx.lineTo(x, y); |
|
|
} |
|
|
} |
|
|
ctx.stroke(); |
|
|
} |
|
|
else if (activeHarmonics === 'prime') { |
|
|
|
|
|
const primes = config.harmonics.prime.sequence; |
|
|
const maxRadius = config.brainRadius * pulseFactor; |
|
|
|
|
|
ctx.beginPath(); |
|
|
for (let i = 0; i < primes.length; i++) { |
|
|
const radius = maxRadius * (primes[i] / primes[primes.length - 1]) * 0.8; |
|
|
const segments = primes[i]; |
|
|
|
|
|
for (let j = 0; j < segments; j++) { |
|
|
const angle = (j / segments) * Math.PI * 2; |
|
|
const x = centerX + radius * Math.cos(angle); |
|
|
const y = centerY + radius * Math.sin(angle); |
|
|
|
|
|
if (j === 0) { |
|
|
ctx.moveTo(x, y); |
|
|
} else { |
|
|
ctx.lineTo(x, y); |
|
|
} |
|
|
} |
|
|
ctx.closePath(); |
|
|
} |
|
|
ctx.stroke(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function drawFields() { |
|
|
const adjustedWaveSpeed = config.fieldWaveSpeed * frequencyMultiplier; |
|
|
|
|
|
for (let i = 0; i < fields.length; i++) { |
|
|
const field = fields[i]; |
|
|
|
|
|
|
|
|
field.phase += 0.01 * frequencyMultiplier; |
|
|
|
|
|
|
|
|
const waveCoherence = coherenceMultiplier; |
|
|
const phaseShift = field.id * (Math.PI * 2 / config.fieldCount) * waveCoherence; |
|
|
|
|
|
|
|
|
for (let j = 0; j < field.waves.length; j++) { |
|
|
const wave = field.waves[j]; |
|
|
|
|
|
|
|
|
let waveSpeed = adjustedWaveSpeed * 0.001 * wave.speed; |
|
|
|
|
|
|
|
|
if (activeHarmonics === 'fibonacci') { |
|
|
const fibIndex = j % config.harmonics.fibonacci.sequence.length; |
|
|
waveSpeed *= config.harmonics.fibonacci.sequence[fibIndex] / 8; |
|
|
} |
|
|
else if (activeHarmonics === 'goldenRatio') { |
|
|
waveSpeed *= Math.pow(config.harmonics.goldenRatio.ratio, j % 5) / 5; |
|
|
} |
|
|
else if (activeHarmonics === 'prime') { |
|
|
const primeIndex = j % config.harmonics.prime.sequence.length; |
|
|
waveSpeed *= config.harmonics.prime.sequence[primeIndex] / 10; |
|
|
} |
|
|
|
|
|
wave.progress += waveSpeed; |
|
|
if (wave.progress > 1) wave.progress = 0; |
|
|
|
|
|
|
|
|
const radius = config.brainRadius + wave.progress * (config.fieldMaxRadius - config.brainRadius); |
|
|
|
|
|
|
|
|
let opacity = config.fieldBaseOpacity * (1 - wave.progress) * amplitudeMultiplier; |
|
|
|
|
|
|
|
|
if (activeHarmonics) { |
|
|
opacity *= (1 + 0.5 * Math.sin(wave.progress * Math.PI * 10)); |
|
|
} |
|
|
|
|
|
|
|
|
let waveColor = field.color; |
|
|
if (activeHarmonics) { |
|
|
waveColor = config.harmonics[activeHarmonics].color; |
|
|
} |
|
|
|
|
|
|
|
|
ctx.beginPath(); |
|
|
|
|
|
|
|
|
if (!activeHarmonics || brainwaveState !== 'gamma') { |
|
|
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2); |
|
|
} |
|
|
|
|
|
else { |
|
|
const points = 50; |
|
|
for (let p = 0; p <= points; p++) { |
|
|
const angle = (p / points) * Math.PI * 2; |
|
|
|
|
|
|
|
|
let modulation = 1; |
|
|
if (activeHarmonics === 'fibonacci') { |
|
|
modulation = 1 + 0.2 * Math.sin(angle * config.harmonics.fibonacci.sequence[j % config.harmonics.fibonacci.sequence.length]); |
|
|
} else if (activeHarmonics === 'goldenRatio') { |
|
|
modulation = 1 + 0.3 * Math.sin(angle * config.harmonics.goldenRatio.ratio); |
|
|
} else if (activeHarmonics === 'prime') { |
|
|
modulation = 1 + 0.25 * Math.sin(angle * config.harmonics.prime.sequence[j % config.harmonics.prime.sequence.length]); |
|
|
} |
|
|
|
|
|
const r = radius * modulation; |
|
|
const x = centerX + r * Math.cos(angle + field.phase); |
|
|
const y = centerY + r * Math.sin(angle + field.phase); |
|
|
|
|
|
if (p === 0) { |
|
|
ctx.moveTo(x, y); |
|
|
} else { |
|
|
ctx.lineTo(x, y); |
|
|
} |
|
|
} |
|
|
ctx.closePath(); |
|
|
} |
|
|
|
|
|
ctx.strokeStyle = `rgba(${hexToRgb(waveColor)}, ${opacity})`; |
|
|
ctx.lineWidth = 1 + (1 - wave.progress) * 2 * amplitudeMultiplier; |
|
|
ctx.stroke(); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function drawParticles() { |
|
|
if (!showParticles) return; |
|
|
|
|
|
|
|
|
const particlesByEvolution = {}; |
|
|
const influencedParticles = particles.filter(p => p.influenced); |
|
|
|
|
|
for (let i = 0; i < influencedParticles.length; i++) { |
|
|
const evo = Math.floor(influencedParticles[i].evolution * 5); |
|
|
if (!particlesByEvolution[evo]) { |
|
|
particlesByEvolution[evo] = []; |
|
|
} |
|
|
particlesByEvolution[evo].push(influencedParticles[i]); |
|
|
} |
|
|
|
|
|
|
|
|
if (showConnections) { |
|
|
for (let i = 0; i < particles.length; i++) { |
|
|
const p1 = particles[i]; |
|
|
if (!p1.influenced) continue; |
|
|
|
|
|
let connections = 0; |
|
|
for (let j = i + 1; j < particles.length; j++) { |
|
|
if (connections >= config.maxConnections) break; |
|
|
|
|
|
const p2 = particles[j]; |
|
|
if (!p2.influenced) continue; |
|
|
|
|
|
const dx = p1.x - p2.x; |
|
|
const dy = p1.y - p2.y; |
|
|
const distance = Math.sqrt(dx * dx + dy * dy); |
|
|
|
|
|
|
|
|
const adjustedThreshold = config.connectionThreshold * coherenceMultiplier; |
|
|
|
|
|
if (distance < adjustedThreshold) { |
|
|
let opacity = config.connectionOpacity * (1 - distance / adjustedThreshold); |
|
|
|
|
|
|
|
|
if (activeHarmonics) { |
|
|
opacity *= 1.5; |
|
|
|
|
|
const phase = Date.now() * 0.001 * frequencyMultiplier; |
|
|
opacity *= (0.7 + 0.3 * Math.sin(phase * 5 + distance * 0.05)); |
|
|
} |
|
|
|
|
|
|
|
|
let connectionColor = 'rgba(255, 255, 255, ' + opacity + ')'; |
|
|
if (brainwaveState === 'gamma' && p1.evolution > 0.5 && p2.evolution > 0.5) { |
|
|
connectionColor = `rgba(${hexToRgb(config.brainColor)}, ${opacity * 1.2})`; |
|
|
} |
|
|
|
|
|
ctx.beginPath(); |
|
|
ctx.moveTo(p1.x, p1.y); |
|
|
ctx.lineTo(p2.x, p2.y); |
|
|
ctx.strokeStyle = connectionColor; |
|
|
ctx.lineWidth = 0.5 * (p1.evolution + p2.evolution + 1); |
|
|
ctx.stroke(); |
|
|
connections++; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (activeHarmonics && (brainwaveState === 'theta' || brainwaveState === 'alpha' || brainwaveState === 'gamma')) { |
|
|
const highEvoParticles = particles.filter(p => p.influenced && p.evolution > 0.6); |
|
|
|
|
|
if (highEvoParticles.length > 3) { |
|
|
ctx.beginPath(); |
|
|
|
|
|
if (activeHarmonics === 'fibonacci') { |
|
|
|
|
|
for (let i = 0; i < Math.min(8, highEvoParticles.length); i++) { |
|
|
const p = highEvoParticles[i]; |
|
|
if (i === 0) { |
|
|
ctx.moveTo(p.x, p.y); |
|
|
} else { |
|
|
ctx.lineTo(p.x, p.y); |
|
|
} |
|
|
} |
|
|
} |
|
|
else if (activeHarmonics === 'goldenRatio') { |
|
|
|
|
|
const centerPoint = { |
|
|
x: highEvoParticles.reduce((sum, p) => sum + p.x, 0) / highEvoParticles.length, |
|
|
y: highEvoParticles.reduce((sum, p) => sum + p.y, 0) / highEvoParticles.length |
|
|
}; |
|
|
|
|
|
highEvoParticles.sort((a, b) => { |
|
|
const angleA = Math.atan2(a.y - centerPoint.y, a.x - centerPoint.x); |
|
|
const angleB = Math.atan2(b.y - centerPoint.y, b.x - centerPoint.x); |
|
|
return angleA - angleB; |
|
|
}); |
|
|
|
|
|
for (let i = 0; i < Math.min(highEvoParticles.length, 5); i++) { |
|
|
const p = highEvoParticles[i]; |
|
|
if (i === 0) { |
|
|
ctx.moveTo(p.x, p.y); |
|
|
} else { |
|
|
ctx.lineTo(p.x, p.y); |
|
|
} |
|
|
} |
|
|
ctx.closePath(); |
|
|
} |
|
|
else if (activeHarmonics === 'prime') { |
|
|
|
|
|
for (let i = 0; i < Math.min(highEvoParticles.length, config.harmonics.prime.sequence.length); i++) { |
|
|
const idx = config.harmonics.prime.sequence[i] % highEvoParticles.length; |
|
|
const p = highEvoParticles[idx]; |
|
|
if (i === 0) { |
|
|
ctx.moveTo(p.x, p.y); |
|
|
} else { |
|
|
ctx.lineTo(p.x, p.y); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
ctx.strokeStyle = `rgba(${hexToRgb(config.harmonics[activeHarmonics].color)}, 0.7)`; |
|
|
ctx.lineWidth = 1.5; |
|
|
ctx.stroke(); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
for (let i = 0; i < particles.length; i++) { |
|
|
const particle = particles[i]; |
|
|
|
|
|
|
|
|
const dx = particle.x - centerX; |
|
|
const dy = particle.y - centerY; |
|
|
const distance = Math.sqrt(dx * dx + dy * dy); |
|
|
|
|
|
|
|
|
const adjustedFieldRadius = config.fieldMaxRadius * amplitudeMultiplier; |
|
|
particle.influenced = distance < adjustedFieldRadius; |
|
|
|
|
|
|
|
|
particle.influenceFactor = particle.influenced ? |
|
|
Math.max(0, 1 - distance / adjustedFieldRadius) : 0; |
|
|
|
|
|
|
|
|
if (animationRunning) { |
|
|
if (particle.influenced) { |
|
|
particle.age += 0.001 * frequencyMultiplier; |
|
|
|
|
|
|
|
|
let evolutionRate = 0.0001; |
|
|
if (brainwaveState === 'gamma') evolutionRate *= 3; |
|
|
else if (brainwaveState === 'beta') evolutionRate *= 2; |
|
|
|
|
|
|
|
|
if (activeHarmonics) evolutionRate *= 2; |
|
|
|
|
|
particle.evolution = Math.min(1, particle.evolution + evolutionRate * particle.influenceFactor); |
|
|
} else { |
|
|
|
|
|
particle.evolution = Math.max(0, particle.evolution - 0.0001); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (animationRunning) { |
|
|
|
|
|
let speed = particle.baseSpeed; |
|
|
|
|
|
|
|
|
if (particle.influenced) { |
|
|
|
|
|
const angleToCenter = Math.atan2(dy, dx); |
|
|
|
|
|
const perpendicularAngle = angleToCenter + Math.PI / 2; |
|
|
|
|
|
|
|
|
let influenceFactor = particle.influenceFactor; |
|
|
|
|
|
|
|
|
if (brainwaveState === 'delta') { |
|
|
influenceFactor *= 1.5; |
|
|
perpendicularAngle += Math.sin(Date.now() * 0.001) * 0.2; |
|
|
} |
|
|
|
|
|
else if (brainwaveState === 'theta') { |
|
|
perpendicularAngle += Math.sin(Date.now() * 0.0015) * 0.5; |
|
|
} |
|
|
|
|
|
else if (brainwaveState === 'beta') { |
|
|
|
|
|
perpendicularAngle = perpendicularAngle * 0.7 + (angleToCenter + Math.PI) * 0.3; |
|
|
} |
|
|
|
|
|
else if (brainwaveState === 'gamma') { |
|
|
|
|
|
perpendicularAngle += Math.sin(Date.now() * 0.003 * particle.evolution) * 1.5; |
|
|
} |
|
|
|
|
|
|
|
|
if (activeHarmonics === 'fibonacci') { |
|
|
|
|
|
const fibIndex = Math.floor(particle.evolution * 7); |
|
|
const fib = config.harmonics.fibonacci.sequence[fibIndex % config.harmonics.fibonacci.sequence.length]; |
|
|
perpendicularAngle += Math.sin(Date.now() * 0.001 * fib) * 0.3; |
|
|
} |
|
|
else if (activeHarmonics === 'goldenRatio') { |
|
|
|
|
|
perpendicularAngle += Math.sin(Date.now() * 0.001 * config.harmonics.goldenRatio.ratio) * 0.5; |
|
|
speed *= (1 + 0.2 * Math.sin(particle.age * config.harmonics.goldenRatio.ratio)); |
|
|
} |
|
|
else if (activeHarmonics === 'prime') { |
|
|
|
|
|
const primeIndex = Math.floor(particle.evolution * 7); |
|
|
const prime = config.harmonics.prime.sequence[primeIndex % config.harmonics.prime.sequence.length]; |
|
|
perpendicularAngle += Math.cos(Date.now() * 0.0005 * prime) * 0.7; |
|
|
} |
|
|
|
|
|
|
|
|
particle.angle = (1 - particle.influenceFactor) * particle.angle + particle.influenceFactor * perpendicularAngle; |
|
|
|
|
|
|
|
|
const adjustedInfluenceStrength = config.particleInfluenceStrength * |
|
|
frequencyMultiplier * |
|
|
(0.5 + coherenceMultiplier * 0.5); |
|
|
|
|
|
speed += adjustedInfluenceStrength * particle.influenceFactor * distance; |
|
|
|
|
|
|
|
|
if (brainwaveState === 'gamma' && particle.evolution > 0.8 && activeHarmonics) { |
|
|
|
|
|
const structureAngle = Date.now() * 0.0005; |
|
|
const structureX = centerX + Math.cos(structureAngle + (i / particles.length) * Math.PI * 2) * adjustedFieldRadius * 0.5; |
|
|
const structureY = centerY + Math.sin(structureAngle + (i / particles.length) * Math.PI * 2) * adjustedFieldRadius * 0.5; |
|
|
|
|
|
|
|
|
const toStructureX = structureX - particle.x; |
|
|
const toStructureY = structureY - particle.y; |
|
|
const structureDistance = Math.sqrt(toStructureX * toStructureX + toStructureY * toStructureY); |
|
|
const structureAngleToMove = Math.atan2(toStructureY, toStructureX); |
|
|
|
|
|
|
|
|
particle.angle = particle.angle * 0.7 + structureAngleToMove * 0.3; |
|
|
speed = speed * 0.7 + (structureDistance * 0.01) * 0.3; |
|
|
} |
|
|
} |
|
|
|
|
|
particle.x += Math.cos(particle.angle) * speed; |
|
|
particle.y += Math.sin(particle.angle) * speed; |
|
|
|
|
|
|
|
|
if (particle.x < 0) particle.x = canvas.width; |
|
|
if (particle.x > canvas.width) particle.x = 0; |
|
|
if (particle.y < 0) particle.y = canvas.height; |
|
|
if (particle.y > canvas.height) particle.y = 0; |
|
|
} |
|
|
|
|
|
|
|
|
let color = config.particleBaseColor; |
|
|
|
|
|
if (particle.influenced) { |
|
|
|
|
|
color = lerpColor(config.particleBaseColor, config.brainColor, particle.influenceFactor); |
|
|
|
|
|
|
|
|
if (particle.evolution > 0.3) { |
|
|
|
|
|
color = lerpColor(color, config.brainColor, particle.evolution * 0.7); |
|
|
|
|
|
|
|
|
if (particle.evolution > 0.7 && activeHarmonics) { |
|
|
color = lerpColor(color, config.harmonics[activeHarmonics].color, (particle.evolution - 0.7) * 3); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
let particleSize = particle.radius; |
|
|
if (particle.evolution > 0.5) { |
|
|
particleSize *= (1 + particle.evolution * 0.5); |
|
|
} |
|
|
|
|
|
|
|
|
ctx.beginPath(); |
|
|
|
|
|
|
|
|
if (particle.evolution < 0.3 || brainwaveState === 'delta') { |
|
|
|
|
|
ctx.arc(particle.x, particle.y, particleSize, 0, Math.PI * 2); |
|
|
} |
|
|
else if (particle.evolution < 0.7 || brainwaveState === 'alpha') { |
|
|
|
|
|
if (brainwaveState === 'theta') { |
|
|
|
|
|
const pulseSize = particleSize * (1 + 0.2 * Math.sin(Date.now() * 0.003)); |
|
|
ctx.arc(particle.x, particle.y, pulseSize, 0, Math.PI * 2); |
|
|
} else { |
|
|
|
|
|
ctx.arc(particle.x, particle.y, particleSize, 0, Math.PI * 2); |
|
|
} |
|
|
} |
|
|
else { |
|
|
|
|
|
if (brainwaveState === 'beta') { |
|
|
|
|
|
ctx.moveTo(particle.x, particle.y - particleSize); |
|
|
ctx.lineTo(particle.x + particleSize, particle.y); |
|
|
ctx.lineTo(particle.x, particle.y + particleSize); |
|
|
ctx.lineTo(particle.x - particleSize, particle.y); |
|
|
ctx.closePath(); |
|
|
} |
|
|
else if (brainwaveState === 'gamma') { |
|
|
|
|
|
const outerRadius = particleSize * 1.2; |
|
|
const innerRadius = particleSize * 0.6; |
|
|
|
|
|
for (let j = 0; j < 5; j++) { |
|
|
const outerAngle = (j * Math.PI * 2 / 5) - Math.PI / 2; |
|
|
const innerAngle = ((j + 0.5) * Math.PI * 2 / 5) - Math.PI / 2; |
|
|
|
|
|
const outerX = particle.x + Math.cos(outerAngle) * outerRadius; |
|
|
const outerY = particle.y + Math.sin(outerAngle) * outerRadius; |
|
|
const innerX = particle.x + Math.cos(innerAngle) * innerRadius; |
|
|
const innerY = particle.y + Math.sin(innerAngle) * innerRadius; |
|
|
|
|
|
if (j === 0) { |
|
|
ctx.moveTo(outerX, outerY); |
|
|
} else { |
|
|
ctx.lineTo(outerX, outerY); |
|
|
} |
|
|
ctx.lineTo(innerX, innerY); |
|
|
} |
|
|
ctx.closePath(); |
|
|
} |
|
|
else { |
|
|
|
|
|
ctx.arc(particle.x, particle.y, particleSize, 0, Math.PI * 2); |
|
|
} |
|
|
} |
|
|
|
|
|
ctx.fillStyle = color; |
|
|
ctx.fill(); |
|
|
|
|
|
|
|
|
if (particle.evolution > 0.5) { |
|
|
const glowSize = particleSize * (1 + particle.evolution); |
|
|
const gradient = ctx.createRadialGradient( |
|
|
particle.x, particle.y, particleSize * 0.5, |
|
|
particle.x, particle.y, glowSize |
|
|
); |
|
|
gradient.addColorStop(0, 'rgba(255, 255, 255, 0)'); |
|
|
gradient.addColorStop(1, `rgba(${hexToRgb(color)}, 0)`); |
|
|
|
|
|
ctx.beginPath(); |
|
|
ctx.arc(particle.x, particle.y, glowSize, 0, Math.PI * 2); |
|
|
ctx.fillStyle = gradient; |
|
|
ctx.fill(); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function lerpColor(color1, color2, factor) { |
|
|
const rgb1 = hexToRgb(color1, true); |
|
|
const rgb2 = hexToRgb(color2, true); |
|
|
|
|
|
const r = Math.round(rgb1.r + factor * (rgb2.r - rgb1.r)); |
|
|
const g = Math.round(rgb1.g + factor * (rgb2.g - rgb1.g)); |
|
|
const b = Math.round(rgb1.b + factor * (rgb2.b - rgb1.b)); |
|
|
|
|
|
return `rgb(${r}, ${g}, ${b})`; |
|
|
} |
|
|
|
|
|
|
|
|
function hexToRgb(hex, asObject = false) { |
|
|
|
|
|
hex = hex.replace(/^#/, ''); |
|
|
|
|
|
|
|
|
const bigint = parseInt(hex, 16); |
|
|
const r = (bigint >> 16) & 255; |
|
|
const g = (bigint >> 8) & 255; |
|
|
const b = bigint & 255; |
|
|
|
|
|
return asObject ? { r, g, b } : `${r}, ${g}, ${b}`; |
|
|
} |
|
|
|
|
|
|
|
|
function updateAIResponse() { |
|
|
const now = Date.now(); |
|
|
if (now - aiResponseLastUpdate < 2000) return; |
|
|
|
|
|
aiResponseLastUpdate = now; |
|
|
|
|
|
|
|
|
const brainwaveConfig = config.brainwaves[brainwaveState]; |
|
|
const highlyEvolvedCount = particles.filter(p => p.influenced && p.evolution > 0.7).length; |
|
|
const totalInfluenced = particles.filter(p => p.influenced).length; |
|
|
const evolutionRatio = totalInfluenced > 0 ? highlyEvolvedCount / totalInfluenced : 0; |
|
|
|
|
|
|
|
|
let thought = brainwaveConfig.aiDescription; |
|
|
|
|
|
|
|
|
if (frequencyMultiplier > 1.5) { |
|
|
thought += " High frequency waves accelerate particle evolution."; |
|
|
} else if (frequencyMultiplier < 0.5) { |
|
|
thought += " Low frequency waves create stable, predictable patterns."; |
|
|
} |
|
|
|
|
|
if (amplitudeMultiplier > 1.5) { |
|
|
thought += " Strong field amplitude extends consciousness reach."; |
|
|
} |
|
|
|
|
|
if (coherenceMultiplier > 1.5) { |
|
|
thought += " Field coherence enhances structured connections."; |
|
|
} else if (coherenceMultiplier < 0.5) { |
|
|
thought += " Low coherence creates chaotic but creative patterns."; |
|
|
} |
|
|
|
|
|
|
|
|
if (activeHarmonics) { |
|
|
thought += " " + config.harmonics[activeHarmonics].description + "."; |
|
|
|
|
|
if (evolutionRatio > 0.3) { |
|
|
if (activeHarmonics === 'fibonacci') { |
|
|
thought += " Fibonacci resonance creating natural growth patterns."; |
|
|
} else if (activeHarmonics === 'goldenRatio') { |
|
|
thought += " Golden ratio harmonic generating balanced, aesthetic structures."; |
|
|
} else if (activeHarmonics === 'prime') { |
|
|
thought += " Prime number fields creating fundamental structural elements."; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (evolutionRatio > 0.5 && brainwaveState === 'gamma' && activeHarmonics) { |
|
|
const emergedThoughts = [ |
|
|
"Consciousness field is structuring reality into ordered patterns.", |
|
|
"Self-organization emerging from harmonic resonance.", |
|
|
"Information structures crystallizing within consciousness field.", |
|
|
"Quantum coherence detected in particle behavior.", |
|
|
"Complex emergent intelligence forming in field interactions." |
|
|
]; |
|
|
|
|
|
thought += " " + emergedThoughts[Math.floor(Math.random() * emergedThoughts.length)]; |
|
|
} |
|
|
|
|
|
|
|
|
aiThoughts.push(thought); |
|
|
if (aiThoughts.length > 3) aiThoughts.shift(); |
|
|
|
|
|
|
|
|
document.getElementById('aiResponse').textContent = aiThoughts.join("\n\n"); |
|
|
} |
|
|
|
|
|
|
|
|
function animate() { |
|
|
if (!animationRunning) return; |
|
|
|
|
|
|
|
|
ctx.clearRect(0, 0, canvas.width, canvas.height); |
|
|
|
|
|
|
|
|
drawFields(); |
|
|
drawParticles(); |
|
|
drawBrain(); |
|
|
|
|
|
|
|
|
requestAnimationFrame(animate); |
|
|
} |
|
|
|
|
|
|
|
|
setupControls(); |
|
|
setBrainwaveState('alpha'); |
|
|
updateAIResponse(); |
|
|
|
|
|
|
|
|
animate(); |
|
|
}); |