|
<!DOCTYPE html> |
|
<html> |
|
<head> |
|
<style> |
|
body { margin: 0; overflow: hidden; background: #000; } |
|
#ui { |
|
position: fixed; |
|
top: 10px; |
|
left: 10px; |
|
color: #0f0; |
|
background: rgba(0,20,0,0.7); |
|
padding: 15px; |
|
border: 1px solid #0f0; |
|
font-family: monospace; |
|
z-index: 100; |
|
} |
|
.control { margin: 10px 0; } |
|
#matrix { |
|
position: fixed; |
|
top: 0; |
|
left: 0; |
|
z-index: -1; |
|
color: #0f0; |
|
font-family: monospace; |
|
font-size: 12px; |
|
opacity: 0.2; |
|
} |
|
</style> |
|
</head> |
|
<body> |
|
<div id="ui"> |
|
<div class="control"> |
|
<button onclick="initAudio()">Start Audio</button> |
|
</div> |
|
<div class="control"> |
|
<label>Particle Speed: <input type="range" id="speed" min="1" max="200" value="100"></label> |
|
</div> |
|
<div class="control"> |
|
<label>Energy Level: <input type="range" id="energy" min="1" max="100" value="50"></label> |
|
</div> |
|
<div class="control"> |
|
<label>Power: <input type="range" id="power" min="1" max="100" value="75"></label> |
|
</div> |
|
<div class="control"> |
|
<button onclick="addParticle()">Add Particle</button> |
|
<button onclick="addDarkMatter()">Add Dark Matter</button> |
|
</div> |
|
<div>Particles: <span id="particleCount">0</span></div> |
|
</div> |
|
<div id="matrix"></div> |
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script> |
|
<script> |
|
let scene, camera, renderer, particles = [], darkMatter = [], plasmaParticles = []; |
|
let audioContext; |
|
const TUBE_RADIUS = 20; |
|
|
|
function initAudio() { |
|
audioContext = new (window.AudioContext || window.webkitAudioContext)(); |
|
} |
|
|
|
function playCollisionSound() { |
|
const oscillator1 = audioContext.createOscillator(); |
|
const oscillator2 = audioContext.createOscillator(); |
|
const gainNode = audioContext.createGain(); |
|
|
|
oscillator1.connect(gainNode); |
|
oscillator2.connect(gainNode); |
|
gainNode.connect(audioContext.destination); |
|
|
|
oscillator1.frequency.setValueAtTime(440 + Math.random() * 220, audioContext.currentTime); |
|
oscillator2.frequency.setValueAtTime(220 + Math.random() * 110, audioContext.currentTime); |
|
|
|
oscillator1.type = 'sine'; |
|
oscillator2.type = 'square'; |
|
|
|
gainNode.gain.setValueAtTime(0.2, audioContext.currentTime); |
|
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.3); |
|
|
|
oscillator1.start(); |
|
oscillator2.start(); |
|
oscillator1.stop(audioContext.currentTime + 0.3); |
|
oscillator2.stop(audioContext.currentTime + 0.3); |
|
} |
|
|
|
function init() { |
|
initAudio(); |
|
scene = new THREE.Scene(); |
|
camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); |
|
renderer = new THREE.WebGLRenderer({ antialias: true }); |
|
renderer.setSize(window.innerWidth, window.innerHeight); |
|
document.body.appendChild(renderer.domElement); |
|
|
|
|
|
const tubeGeometry = new THREE.TorusGeometry(TUBE_RADIUS, 2, 32, 100); |
|
const tubeMaterial = new THREE.MeshPhongMaterial({ |
|
color: 0x00ff00, |
|
transparent: true, |
|
opacity: 0.3, |
|
wireframe: true |
|
}); |
|
const tube = new THREE.Mesh(tubeGeometry, tubeMaterial); |
|
scene.add(tube); |
|
|
|
|
|
const light = new THREE.PointLight(0xffffff, 1); |
|
light.position.set(0, 0, 50); |
|
scene.add(light); |
|
scene.add(new THREE.AmbientLight(0x404040)); |
|
|
|
camera.position.z = 50; |
|
|
|
|
|
initMatrix(); |
|
} |
|
|
|
function initMatrix() { |
|
const matrix = document.getElementById('matrix'); |
|
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@#$%^&*()"; |
|
setInterval(() => { |
|
let str = ''; |
|
for(let i = 0; i < 50; i++) { |
|
for(let j = 0; j < 100; j++) { |
|
str += chars[Math.floor(Math.random() * chars.length)]; |
|
} |
|
str += '\n'; |
|
} |
|
matrix.textContent = str; |
|
}, 50); |
|
} |
|
|
|
function addParticle() { |
|
const geometry = new THREE.SphereGeometry(0.3, 16, 16); |
|
const material = new THREE.MeshPhongMaterial({ |
|
color: 0x00ff00, |
|
emissive: 0x00ff00, |
|
emissiveIntensity: 0.5 |
|
}); |
|
|
|
const particle = new THREE.Mesh(geometry, material); |
|
particle.userData = { |
|
angle: Math.random() * Math.PI * 2, |
|
speed: Math.random() * 0.02 + 0.01, |
|
direction: Math.random() > 0.5 ? 1 : -1, |
|
phase: Math.random() * Math.PI * 2, |
|
energy: 100 |
|
}; |
|
|
|
particles.push(particle); |
|
scene.add(particle); |
|
updateParticleCount(); |
|
} |
|
|
|
function addDarkMatter() { |
|
const geometry = new THREE.SphereGeometry(1, 32, 32); |
|
const material = new THREE.MeshPhongMaterial({ |
|
color: 0x000066, |
|
transparent: true, |
|
opacity: 0.3 |
|
}); |
|
|
|
const dm = new THREE.Mesh(geometry, material); |
|
dm.position.set( |
|
(Math.random() - 0.5) * TUBE_RADIUS * 2, |
|
(Math.random() - 0.5) * TUBE_RADIUS * 2, |
|
(Math.random() - 0.5) * TUBE_RADIUS * 2 |
|
); |
|
|
|
darkMatter.push(dm); |
|
scene.add(dm); |
|
} |
|
|
|
function createPlasmaExplosion(position) { |
|
const particleCount = 30; |
|
for(let i = 0; i < particleCount; i++) { |
|
const geometry = new THREE.SphereGeometry(0.1, 8, 8); |
|
const material = new THREE.MeshPhongMaterial({ |
|
color: 0x00ff00, |
|
emissive: 0x00ff00, |
|
emissiveIntensity: 1 |
|
}); |
|
|
|
const plasma = new THREE.Mesh(geometry, material); |
|
plasma.position.copy(position); |
|
|
|
const velocity = new THREE.Vector3( |
|
(Math.random() - 0.5) * 0.5, |
|
(Math.random() - 0.5) * 0.5, |
|
(Math.random() - 0.5) * 0.5 |
|
); |
|
|
|
plasma.userData = { |
|
velocity: velocity, |
|
lifetime: 100, |
|
maxLifetime: 100 |
|
}; |
|
|
|
plasmaParticles.push(plasma); |
|
scene.add(plasma); |
|
} |
|
} |
|
|
|
function updateParticles() { |
|
const speed = document.getElementById('speed').value / 50; |
|
const energy = document.getElementById('energy').value / 100; |
|
const power = document.getElementById('power').value / 100; |
|
|
|
|
|
particles.forEach((particle, index) => { |
|
particle.userData.angle += particle.userData.speed * speed * particle.userData.direction; |
|
|
|
particle.position.x = Math.cos(particle.userData.angle) * TUBE_RADIUS; |
|
particle.position.y = Math.sin(particle.userData.angle) * TUBE_RADIUS; |
|
particle.position.z = Math.sin(particle.userData.phase) * 2; |
|
|
|
particle.userData.phase += 0.01 * particle.userData.direction; |
|
|
|
|
|
for(let i = index + 1; i < particles.length; i++) { |
|
const other = particles[i]; |
|
if(particle.position.distanceTo(other.position) < 0.6) { |
|
createPlasmaExplosion(particle.position); |
|
particle.userData.energy -= power * 10; |
|
other.userData.energy -= power * 10; |
|
playCollisionSound(); |
|
} |
|
} |
|
|
|
if(particle.userData.energy <= 0) { |
|
scene.remove(particle); |
|
particles.splice(index, 1); |
|
updateParticleCount(); |
|
} |
|
}); |
|
|
|
|
|
plasmaParticles.forEach((plasma, index) => { |
|
plasma.position.add(plasma.userData.velocity); |
|
plasma.userData.lifetime--; |
|
plasma.material.opacity = plasma.userData.lifetime / plasma.userData.maxLifetime; |
|
|
|
if(plasma.userData.lifetime <= 0) { |
|
scene.remove(plasma); |
|
plasmaParticles.splice(index, 1); |
|
} |
|
}); |
|
} |
|
|
|
function updateParticleCount() { |
|
document.getElementById('particleCount').textContent = particles.length; |
|
} |
|
|
|
function animate() { |
|
requestAnimationFrame(animate); |
|
updateParticles(); |
|
renderer.render(scene, camera); |
|
} |
|
|
|
init(); |
|
animate(); |
|
</script> |
|
</body> |
|
</html> |