infinite-agents-public/threejs_viz/threejs_viz_3.html

310 lines
10 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Three.js Particle Universe</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
overflow: hidden;
background: #000;
}
#canvas-container {
width: 100vw;
height: 100vh;
display: block;
}
#info {
position: absolute;
top: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.8);
color: #fff;
padding: 20px;
border-radius: 10px;
font-size: 14px;
max-width: 350px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
}
#info h1 {
margin: 0 0 15px 0;
font-size: 24px;
color: #4fc3f7;
text-shadow: 0 0 10px rgba(79, 195, 247, 0.5);
}
#info p {
margin: 8px 0;
line-height: 1.6;
}
#info strong {
color: #81c784;
}
#info a {
color: #4fc3f7;
text-decoration: none;
}
#info a:hover {
text-decoration: underline;
}
.label {
color: #90caf9;
font-weight: 600;
}
</style>
</head>
<body>
<div id="canvas-container"></div>
<div id="info">
<h1>Particle Universe</h1>
<p><span class="label">Technique:</span> GPU-accelerated particle system</p>
<p><span class="label">Learning:</span> BufferGeometry with Points for efficient particle rendering</p>
<p><span class="label">Features:</span> 10,000 particles with color gradients, pulsing animation, and orbital camera</p>
<p><span class="label">Web Source:</span> <a href="https://threejs.org/examples/?q=points" target="_blank">Three.js Points Examples</a></p>
</div>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.164.1/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.164.1/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Scene setup
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x000510);
scene.fog = new THREE.FogExp2(0x000510, 0.0008);
// Camera setup
const camera = new THREE.PerspectiveCamera(
75,
window.innerWidth / window.innerHeight,
0.1,
1000
);
camera.position.set(0, 50, 150);
// Renderer setup
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.getElementById('canvas-container').appendChild(renderer.domElement);
// Controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.autoRotate = true;
controls.autoRotateSpeed = 0.5;
controls.minDistance = 50;
controls.maxDistance = 300;
// Create particle system
const particleCount = 10000;
const particles = new THREE.BufferGeometry();
const positions = new Float32Array(particleCount * 3);
const colors = new Float32Array(particleCount * 3);
const sizes = new Float32Array(particleCount);
const velocities = new Float32Array(particleCount * 3);
// Color palette for gradient effect
const color1 = new THREE.Color(0x4fc3f7); // Cyan
const color2 = new THREE.Color(0x9c27b0); // Purple
const color3 = new THREE.Color(0xff6b9d); // Pink
const color4 = new THREE.Color(0xffd54f); // Gold
// Initialize particle attributes
for (let i = 0; i < particleCount; i++) {
const i3 = i * 3;
// Create spherical distribution with varying density
const radius = Math.random() * 100 + 50;
const theta = Math.random() * Math.PI * 2;
const phi = Math.acos(Math.random() * 2 - 1);
positions[i3] = radius * Math.sin(phi) * Math.cos(theta);
positions[i3 + 1] = radius * Math.sin(phi) * Math.sin(theta);
positions[i3 + 2] = radius * Math.cos(phi);
// Assign colors based on position for gradient effect
const colorMix = Math.random();
let particleColor;
if (colorMix < 0.25) {
particleColor = color1.clone();
} else if (colorMix < 0.5) {
particleColor = color2.clone();
} else if (colorMix < 0.75) {
particleColor = color3.clone();
} else {
particleColor = color4.clone();
}
// Add some color variation
particleColor.offsetHSL(Math.random() * 0.1 - 0.05, 0, 0);
colors[i3] = particleColor.r;
colors[i3 + 1] = particleColor.g;
colors[i3 + 2] = particleColor.b;
// Varying particle sizes for depth effect
sizes[i] = Math.random() * 3 + 0.5;
// Random velocities for floating animation
velocities[i3] = (Math.random() - 0.5) * 0.02;
velocities[i3 + 1] = (Math.random() - 0.5) * 0.02;
velocities[i3 + 2] = (Math.random() - 0.5) * 0.02;
}
particles.setAttribute('position', new THREE.BufferAttribute(positions, 3));
particles.setAttribute('color', new THREE.BufferAttribute(colors, 3));
particles.setAttribute('size', new THREE.BufferAttribute(sizes, 1));
// Custom shader material for enhanced particle rendering
const particleMaterial = new THREE.ShaderMaterial({
uniforms: {
time: { value: 0 },
pixelRatio: { value: renderer.getPixelRatio() }
},
vertexShader: `
attribute float size;
attribute vec3 color;
varying vec3 vColor;
uniform float time;
uniform float pixelRatio;
void main() {
vColor = color;
vec4 mvPosition = modelViewMatrix * vec4(position, 1.0);
// Pulsing effect
float pulse = sin(time * 2.0 + position.x * 0.01) * 0.3 + 1.0;
gl_PointSize = size * pulse * pixelRatio * (300.0 / -mvPosition.z);
gl_Position = projectionMatrix * mvPosition;
}
`,
fragmentShader: `
varying vec3 vColor;
void main() {
// Create circular particles with soft edges
vec2 center = gl_PointCoord - vec2(0.5);
float dist = length(center);
if (dist > 0.5) discard;
// Soft glow effect
float alpha = 1.0 - smoothstep(0.0, 0.5, dist);
alpha = pow(alpha, 2.0);
// Add glow
vec3 glow = vColor * (1.0 + alpha * 0.5);
gl_FragColor = vec4(glow, alpha * 0.8);
}
`,
transparent: true,
depthWrite: false,
blending: THREE.AdditiveBlending
});
const particleSystem = new THREE.Points(particles, particleMaterial);
scene.add(particleSystem);
// Add ambient light for scene
const ambientLight = new THREE.AmbientLight(0x404040, 0.5);
scene.add(ambientLight);
// Add some accent lights
const light1 = new THREE.PointLight(0x4fc3f7, 1, 200);
light1.position.set(50, 50, 50);
scene.add(light1);
const light2 = new THREE.PointLight(0x9c27b0, 1, 200);
light2.position.set(-50, -50, -50);
scene.add(light2);
// Animation variables
let time = 0;
// Animation loop
function animate() {
requestAnimationFrame(animate);
time += 0.01;
particleMaterial.uniforms.time.value = time;
// Animate particle positions with floating motion
const positions = particles.attributes.position.array;
for (let i = 0; i < particleCount; i++) {
const i3 = i * 3;
// Floating motion
positions[i3] += velocities[i3];
positions[i3 + 1] += velocities[i3 + 1];
positions[i3 + 2] += velocities[i3 + 2];
// Boundary check - reverse direction if too far
const distance = Math.sqrt(
positions[i3] ** 2 +
positions[i3 + 1] ** 2 +
positions[i3 + 2] ** 2
);
if (distance > 200 || distance < 30) {
velocities[i3] *= -1;
velocities[i3 + 1] *= -1;
velocities[i3 + 2] *= -1;
}
}
particles.attributes.position.needsUpdate = true;
// Rotate entire particle system slowly
particleSystem.rotation.y += 0.0005;
particleSystem.rotation.x = Math.sin(time * 0.1) * 0.1;
// Update controls
controls.update();
// Render scene
renderer.render(scene, camera);
}
// Handle window resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
// Start animation
animate();
</script>
</body>
</html>