|
<!DOCTYPE html> |
|
<html lang="en"> |
|
<head> |
|
<meta charset="UTF-8"> |
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
|
<title>Advanced Particle Accelerator</title> |
|
<style> |
|
* { |
|
margin: 0; |
|
padding: 0; |
|
box-sizing: border-box; |
|
} |
|
|
|
body { |
|
background: #000; |
|
color: #00ff00; |
|
font-family: monospace; |
|
overflow: hidden; |
|
} |
|
|
|
canvas { |
|
position: fixed; |
|
} |
|
|
|
.controls { |
|
position: fixed; |
|
top: 10px; |
|
left: 10px; |
|
background: rgba(0, 20, 0, 0.8); |
|
padding: 15px; |
|
border: 1px solid #00ff00; |
|
z-index: 100; |
|
} |
|
|
|
.data { |
|
position: fixed; |
|
top: 10px; |
|
right: 10px; |
|
background: rgba(0, 20, 0, 0.8); |
|
padding: 15px; |
|
border: 1px solid #00ff00; |
|
z-index: 100; |
|
} |
|
|
|
button { |
|
background: #001400; |
|
color: #00ff00; |
|
border: 1px solid #00ff00; |
|
padding: 5px 10px; |
|
margin: 5px; |
|
cursor: pointer; |
|
font-family: monospace; |
|
transition: all 0.3s; |
|
} |
|
|
|
button:hover { |
|
background: #00ff00; |
|
color: #000; |
|
} |
|
|
|
.separator { |
|
height: 1px; |
|
background: #00ff00; |
|
margin: 10px 0; |
|
} |
|
|
|
.detector { |
|
position: fixed; |
|
border: 1px solid #00ff00; |
|
pointer-events: none; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<canvas id="mainCanvas"></canvas> |
|
<canvas id="effectCanvas"></canvas> |
|
|
|
<div class="controls"> |
|
<button onclick="initializeAccelerator()">Initialize</button> |
|
<button onclick="injectParticles()">Inject Particles</button> |
|
<button onclick="toggleAcceleration()">Toggle Acceleration</button> |
|
<button onclick="toggleCollisions()">Toggle Collisions</button> |
|
<div class="separator"></div> |
|
<div>Energy Level: <span id="energyLevel">0</span> TeV</div> |
|
<div>Collisions: <span id="collisionCount">0</span></div> |
|
<div>Particles: <span id="particleCount">0</span></div> |
|
</div> |
|
|
|
<div class="data"> |
|
<div>Detector Data:</div> |
|
<div id="detectorData"></div> |
|
</div> |
|
|
|
<script> |
|
const mainCanvas = document.getElementById('mainCanvas'); |
|
const effectCanvas = document.getElementById('effectCanvas'); |
|
const mainCtx = mainCanvas.getContext('2d'); |
|
const effectCtx = effectCanvas.getContext('2d'); |
|
|
|
|
|
function resizeCanvases() { |
|
mainCanvas.width = window.innerWidth; |
|
mainCanvas.height = window.innerHeight; |
|
effectCanvas.width = window.innerWidth; |
|
effectCanvas.height = window.innerHeight; |
|
} |
|
resizeCanvases(); |
|
window.addEventListener('resize', resizeCanvases); |
|
|
|
|
|
const state = { |
|
particles: [], |
|
detectors: [], |
|
collisions: [], |
|
acceleratorActive: false, |
|
collisionsEnabled: false, |
|
collisionCount: 0, |
|
maxEnergy: 13, |
|
centerX: window.innerWidth / 2, |
|
centerY: window.innerHeight / 2, |
|
ringRadius: Math.min(window.innerWidth, window.innerHeight) * 0.35, |
|
time: 0 |
|
}; |
|
|
|
class Particle { |
|
constructor(clockwise = true) { |
|
this.clockwise = clockwise; |
|
this.angle = clockwise ? 0 : Math.PI; |
|
this.energy = 0.1; |
|
this.velocity = 0.01; |
|
this.radius = state.ringRadius; |
|
this.size = 3; |
|
this.trail = []; |
|
this.maxTrailLength = 50; |
|
this.collided = false; |
|
this.updatePosition(); |
|
this.detectedBy = new Set(); |
|
} |
|
|
|
updatePosition() { |
|
this.x = state.centerX + Math.cos(this.angle) * this.radius; |
|
this.y = state.centerY + Math.sin(this.angle) * this.radius; |
|
|
|
this.trail.push({ x: this.x, y: this.y }); |
|
if (this.trail.length > this.maxTrailLength) { |
|
this.trail.shift(); |
|
} |
|
} |
|
|
|
accelerate() { |
|
if (state.acceleratorActive && this.energy < state.maxEnergy) { |
|
this.energy += 0.01; |
|
this.velocity = 0.01 + (this.energy / state.maxEnergy) * 0.04; |
|
} |
|
} |
|
|
|
update() { |
|
this.accelerate(); |
|
this.angle += this.clockwise ? this.velocity : -this.velocity; |
|
this.updatePosition(); |
|
this.checkDetectors(); |
|
} |
|
|
|
checkDetectors() { |
|
state.detectors.forEach(detector => { |
|
if (!this.detectedBy.has(detector) && |
|
this.x > detector.x && |
|
this.x < detector.x + detector.width && |
|
this.y > detector.y && |
|
this.y < detector.y + detector.height) { |
|
|
|
this.detectedBy.add(detector); |
|
detector.detect(this); |
|
} |
|
}); |
|
} |
|
|
|
draw(ctx) { |
|
|
|
ctx.beginPath(); |
|
ctx.strokeStyle = this.clockwise ? |
|
`rgba(0, ${155 + this.energy * 10}, 255, 0.5)` : |
|
`rgba(255, ${155 + this.energy * 10}, 0, 0.5)`; |
|
ctx.lineWidth = 2; |
|
|
|
for (let i = 0; i < this.trail.length; i++) { |
|
if (i === 0) { |
|
ctx.moveTo(this.trail[i].x, this.trail[i].y); |
|
} else { |
|
ctx.lineTo(this.trail[i].x, this.trail[i].y); |
|
} |
|
} |
|
ctx.stroke(); |
|
|
|
|
|
ctx.beginPath(); |
|
ctx.fillStyle = this.clockwise ? '#00ffff' : '#ff9900'; |
|
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); |
|
ctx.fill(); |
|
|
|
|
|
ctx.beginPath(); |
|
ctx.strokeStyle = `rgba(255, 255, 255, ${this.energy / state.maxEnergy})`; |
|
ctx.arc(this.x, this.y, this.size + 3, 0, Math.PI * 2); |
|
ctx.stroke(); |
|
} |
|
} |
|
|
|
class Detector { |
|
constructor(x, y, width, height) { |
|
this.x = x; |
|
this.y = y; |
|
this.width = width; |
|
this.height = height; |
|
this.detections = []; |
|
this.element = document.createElement('div'); |
|
this.element.className = 'detector'; |
|
this.element.style.left = `${x}px`; |
|
this.element.style.top = `${y}px`; |
|
this.element.style.width = `${width}px`; |
|
this.element.style.height = `${height}px`; |
|
document.body.appendChild(this.element); |
|
} |
|
|
|
detect(particle) { |
|
this.detections.push({ |
|
time: state.time, |
|
energy: particle.energy, |
|
direction: particle.clockwise ? 'clockwise' : 'counterclockwise' |
|
}); |
|
this.element.style.backgroundColor = 'rgba(0, 255, 0, 0.2)'; |
|
setTimeout(() => { |
|
this.element.style.backgroundColor = 'transparent'; |
|
}, 100); |
|
} |
|
} |
|
|
|
function createDetectors() { |
|
const detectorSize = 40; |
|
const positions = [ |
|
{ angle: 0, label: 'East' }, |
|
{ angle: Math.PI / 2, label: 'South' }, |
|
{ angle: Math.PI, label: 'West' }, |
|
{ angle: 3 * Math.PI / 2, label: 'North' } |
|
]; |
|
|
|
positions.forEach(pos => { |
|
const x = state.centerX + Math.cos(pos.angle) * state.ringRadius - detectorSize/2; |
|
const y = state.centerY + Math.sin(pos.angle) * state.ringRadius - detectorSize/2; |
|
state.detectors.push(new Detector(x, y, detectorSize, detectorSize)); |
|
}); |
|
} |
|
|
|
function drawAccelerator() { |
|
mainCtx.beginPath(); |
|
mainCtx.strokeStyle = '#333'; |
|
mainCtx.lineWidth = 20; |
|
mainCtx.arc(state.centerX, state.centerY, state.ringRadius, 0, Math.PI * 2); |
|
mainCtx.stroke(); |
|
|
|
|
|
for (let i = 0; i < 8; i++) { |
|
const angle = (i / 8) * Math.PI * 2; |
|
mainCtx.beginPath(); |
|
mainCtx.strokeStyle = '#0f0'; |
|
mainCtx.lineWidth = 2; |
|
const x = state.centerX + Math.cos(angle) * state.ringRadius; |
|
const y = state.centerY + Math.sin(angle) * state.ringRadius; |
|
mainCtx.arc(x, y, 10, 0, Math.PI * 2); |
|
mainCtx.stroke(); |
|
} |
|
} |
|
|
|
function checkCollisions() { |
|
if (!state.collisionsEnabled) return; |
|
|
|
for (let i = 0; i < state.particles.length; i++) { |
|
for (let j = i + 1; j < state.particles.length; j++) { |
|
const p1 = state.particles[i]; |
|
const p2 = state.particles[j]; |
|
|
|
if (p1.clockwise !== p2.clockwise) { |
|
const dx = p1.x - p2.x; |
|
const dy = p1.y - p2.y; |
|
const distance = Math.sqrt(dx * dx + dy * dy); |
|
|
|
if (distance < 10 && p1.energy > 1 && p2.energy > 1) { |
|
createCollisionEffect(p1.x, p1.y, p1.energy + p2.energy); |
|
p1.collided = true; |
|
p2.collided = true; |
|
state.collisionCount++; |
|
} |
|
} |
|
} |
|
} |
|
|
|
state.particles = state.particles.filter(p => !p.collided); |
|
} |
|
|
|
function createCollisionEffect(x, y, energy) { |
|
const particles = 50; |
|
const speed = 5; |
|
|
|
for (let i = 0; i < particles; i++) { |
|
const angle = (i / particles) * Math.PI * 2; |
|
const velocity = { |
|
x: Math.cos(angle) * speed * (Math.random() + 0.5), |
|
y: Math.sin(angle) * speed * (Math.random() + 0.5) |
|
}; |
|
state.collisions.push({ |
|
x, y, |
|
velocity, |
|
life: 1, |
|
color: `hsl(${Math.random() * 60 + 30}, 100%, 50%)` |
|
}); |
|
} |
|
} |
|
|
|
function updateCollisionEffects() { |
|
state.collisions.forEach(p => { |
|
p.x += p.velocity.x; |
|
p.y += p.velocity.y; |
|
p.life -= 0.02; |
|
}); |
|
|
|
state.collisions = state.collisions.filter(p => p.life > 0); |
|
} |
|
|
|
function drawCollisionEffects() { |
|
effectCtx.clearRect(0, 0, effectCanvas.width, effectCanvas.height); |
|
|
|
state.collisions.forEach(p => { |
|
effectCtx.beginPath(); |
|
effectCtx.fillStyle = p.color.replace(')', `, ${p.life})`); |
|
effectCtx.arc(p.x, p.y, 2, 0, Math.PI * 2); |
|
effectCtx.fill(); |
|
}); |
|
} |
|
|
|
function updateUI() { |
|
document.getElementById('energyLevel').textContent = |
|
state.particles.length > 0 ? |
|
state.particles[0].energy.toFixed(2) : '0.00'; |
|
document.getElementById('collisionCount').textContent = state.collisionCount; |
|
document.getElementById('particleCount').textContent = state.particles.length; |
|
|
|
|
|
const detectorData = state.detectors.map((detector, i) => { |
|
const recent = detector.detections.slice(-3); |
|
return `Detector ${i + 1}: ${recent.length} recent detections`; |
|
}).join('<br>'); |
|
document.getElementById('detectorData').innerHTML = detectorData; |
|
} |
|
|
|
|
|
function initializeAccelerator() { |
|
state.particles = []; |
|
state.collisions = []; |
|
state.collisionCount = 0; |
|
state.detectors.forEach(d => d.detections = []); |
|
} |
|
|
|
function injectParticles() { |
|
state.particles.push(new Particle(true)); |
|
state.particles.push(new Particle(false)); |
|
} |
|
|
|
function toggleAcceleration() { |
|
state.acceleratorActive = !state.acceleratorActive; |
|
} |
|
|
|
function toggleCollisions() { |
|
state.collisionsEnabled = !state.collisionsEnabled; |
|
} |
|
|
|
function animate() { |
|
state.time++; |
|
|
|
|
|
mainCtx.fillStyle = 'rgba(0, 0, 0, 0.1)'; |
|
mainCtx.fillRect(0, 0, mainCanvas.width, mainCanvas.height); |
|
|
|
drawAccelerator(); |
|
|
|
state.particles.forEach(particle => { |
|
particle.update(); |
|
particle.draw(mainCtx); |
|
}); |
|
|
|
checkCollisions(); |
|
updateCollisionEffects(); |
|
drawCollisionEffects(); |
|
updateUI(); |
|
|
|
requestAnimationFrame(animate); |
|
} |
|
|
|
|
|
createDetectors(); |
|
animate(); |
|
</script> |
|
</body> |
|
</html> |