anycoder-c4ec69de / index.html
andorxotnot's picture
Upload folder using huggingface_hub
d555bfd verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Complex Stable Life 3D</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;500;700&display=swap" rel="stylesheet">
<style>
:root {
--primary: #00d2d3; /* Cyan/Teal for a sci-fi biological look */
--glass-bg: rgba(10, 15, 20, 0.8);
--glass-border: rgba(255, 255, 255, 0.08);
--text: #f1f5f9;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
user-select: none;
}
body {
overflow: hidden;
background-color: #050505;
font-family: 'Inter', sans-serif;
color: var(--text);
}
/* Canvas */
#canvas-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
background: radial-gradient(circle at center, #111 0%, #000 100%);
}
/* Header Link */
.brand-link {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
z-index: 100;
color: var(--text);
text-decoration: none;
font-weight: 600;
font-size: 0.85rem;
background: var(--glass-bg);
padding: 8px 20px;
border-radius: 30px;
border: 1px solid var(--glass-border);
backdrop-filter: blur(12px);
transition: all 0.3s ease;
letter-spacing: 0.5px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
}
.brand-link:hover {
background: rgba(255, 255, 255, 0.1);
border-color: rgba(255, 255, 255, 0.3);
box-shadow: 0 0 15px var(--primary);
}
/* UI Overlay */
.ui-panel {
position: fixed;
top: 20px;
right: 20px;
width: 340px;
background: var(--glass-bg);
backdrop-filter: blur(16px);
-webkit-backdrop-filter: blur(16px);
border: 1px solid var(--glass-border);
border-radius: 16px;
padding: 24px;
z-index: 10;
display: flex;
flex-direction: column;
gap: 16px;
box-shadow: 0 20px 40px rgba(0,0,0,0.4);
max-height: 90vh;
overflow-y: auto;
transition: transform 0.3s ease;
}
.panel-header h1 {
font-size: 1.2rem;
font-weight: 700;
background: linear-gradient(135deg, #fff, var(--primary));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 4px;
}
.panel-header p {
font-size: 0.75rem;
color: #94a3b8;
}
.control-group {
display: flex;
flex-direction: column;
gap: 8px;
}
label {
font-size: 0.75rem;
color: #cbd5e1;
display: flex;
justify-content: space-between;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.value-tag {
color: var(--primary);
font-family: monospace;
font-size: 0.85rem;
}
input[type="range"] {
-webkit-appearance: none;
width: 100%;
height: 4px;
background: rgba(255,255,255,0.1);
border-radius: 2px;
outline: none;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 14px;
height: 14px;
border-radius: 50%;
background: var(--primary);
cursor: pointer;
transition: transform 0.2s;
box-shadow: 0 0 10px rgba(0, 210, 211, 0.5);
}
input[type="range"]::-webkit-slider-thumb:hover {
transform: scale(1.2);
}
.btn-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
}
button {
background: rgba(255,255,255,0.03);
border: 1px solid var(--glass-border);
color: #e2e8f0;
padding: 10px;
border-radius: 8px;
cursor: pointer;
font-weight: 600;
font-size: 0.8rem;
transition: all 0.2s ease;
font-family: 'Inter', sans-serif;
}
button:hover {
background: rgba(255,255,255,0.08);
border-color: rgba(255,255,255,0.2);
}
button.primary {
background: var(--primary);
color: #000;
border: none;
box-shadow: 0 4px 12px rgba(0, 210, 211, 0.3);
}
button.primary:hover {
background: #48dbfb;
transform: translateY(-1px);
}
.checkbox-group {
display: flex;
align-items: center;
gap: 10px;
font-size: 0.75rem;
color: #94a3b8;
cursor: pointer;
padding: 5px 0;
}
.checkbox-group input {
accent-color: var(--primary);
width: 14px;
height: 14px;
}
.stats {
font-size: 0.7rem;
color: #576574;
text-align: center;
padding-top: 10px;
border-top: 1px solid var(--glass-border);
font-family: monospace;
}
/* Loading overlay */
#loading {
position: fixed;
top: 0; left: 0; width: 100%; height: 100%;
background: #000;
z-index: 200;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: var(--primary);
transition: opacity 0.8s ease-out;
pointer-events: none;
font-weight: 300;
letter-spacing: 2px;
}
@media (max-width: 600px) {
.ui-panel {
width: calc(100% - 30px);
right: 15px;
bottom: 20px;
top: auto;
max-height: 55vh;
}
.brand-link {
top: 10px;
padding: 6px 16px;
}
}
</style>
<script type="importmap">
{
"imports": {
"three": "https://unpkg.com/three@0.160.0/build/three.module.js",
"three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/"
}
}
</script>
</head>
<body>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank" class="brand-link">Built with anycoder</a>
<div id="loading">
<div>GENERATING COMPLEXITY</div>
</div>
<div id="canvas-container"></div>
<div class="ui-panel" id="uiPanel">
<div class="panel-header">
<h1>Complex Life Engine</h1>
<p>Large Scale Structure Simulation</p>
</div>
<div class="control-group">
<label>Particles <span id="val-count" class="value-tag">1400</span></label>
<input type="range" id="inp-count" min="500" max="2500" step="100" value="1400">
</div>
<div class="control-group">
<label>Interaction Radius <span id="val-radius" class="value-tag">80</span></label>
<input type="range" id="inp-radius" min="30" max="150" value="80">
</div>
<div class="control-group">
<label>Force Strength <span id="val-force" class="value-tag">0.6</span></label>
<input type="range" id="inp-force" min="0.1" max="3.0" step="0.1" value="0.6">
</div>
<div class="control-group">
<label>Friction (Stability) <span id="val-friction" class="value-tag">0.88</span></label>
<input type="range" id="inp-friction" min="0.50" max="0.98" step="0.01" value="0.88">
</div>
<label class="checkbox-group">
<input type="checkbox" id="inp-symmetric" checked>
Symmetric Rules (Physics Law)
</label>
<button id="btn-randomize" class="primary">🎲 Evolve New Rules</button>
<div class="btn-grid">
<button id="btn-complex">🧬 Complex</button>
<button id="btn-membranes">🕸️ Membranes</button>
</div>
<div class="btn-grid">
<button id="btn-snake">🐍 Snake</button>
<button id="btn-cells">🦠 Cells</button>
</div>
<div class="stats" id="stats">
Initializing...
</div>
</div>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/addons/postprocessing/RenderPass.js';
import { UnrealBloomPass } from 'three/addons/postprocessing/UnrealBloomPass.js';
// --- Configuration ---
const CONFIG = {
particleCount: 1400,
types: 6,
radius: 80, // High radius for larger structures
forceFactor: 0.6, // Lower force to balance high radius
friction: 0.88, // High friction to stabilize large structures
worldSize: 300, // Larger world
symmetric: true,
maxSpeed: 2.5,
repulsionRadius: 0.3 // Distance where particles strongly push apart
};
// --- State ---
let particles = [];
let rules = [];
let typeColors = [];
// --- Three.js Setup ---
const container = document.getElementById('canvas-container');
const scene = new THREE.Scene();
scene.fog = new THREE.FogExp2(0x000000, 0.0015);
const camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1500);
camera.position.set(0, 200, 400);
const renderer = new THREE.WebGLRenderer({ antialias: false, powerPreference: "high-performance" });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
container.appendChild(renderer.domElement);
// Post-processing
const renderScene = new RenderPass(scene, camera);
const bloomPass = new UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);
bloomPass.threshold = 0.1;
bloomPass.strength = 0.8; // Stronger bloom for sci-fi effect
bloomPass.radius = 0.5;
const composer = new EffectComposer(renderer);
composer.addPass(renderScene);
composer.addPass(bloomPass);
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.autoRotate = true;
controls.autoRotateSpeed = 0.3;
// Lights
const ambientLight = new THREE.AmbientLight(0x222222);
scene.add(ambientLight);
const lights = [];
const lightColors = [0x00d2d3, 0xff9ff3, 0xfeca57];
for(let i=0; i<3; i++) {
const l = new THREE.PointLight(lightColors[i], 1, 500);
l.position.set(
(Math.random()-0.5)*300,
(Math.random()-0.5)*300,
(Math.random()-0.5)*300
);
scene.add(l);
lights.push(l);
}
// --- Particle System ---
const geometry = new THREE.SphereGeometry(1, 8, 8); // Low poly is fine with bloom
const material = new THREE.MeshBasicMaterial({ color: 0xffffff }); // Basic material is faster
let instancedMesh;
const dummy = new THREE.Object3D();
const _color = new THREE.Color();
// --- Logic ---
function initSystem() {
if (instancedMesh) {
scene.remove(instancedMesh);
instancedMesh.dispose();
}
// Distinct color palette
typeColors = [
new THREE.Color(0x00d2d3), // Cyan
new THREE.Color(0xff6b6b), // Red
new THREE.Color(0xfeca57), // Yellow
new THREE.Color(0x5f27cd), // Purple
new THREE.Color(0x54a0ff), // Blue
new THREE.Color(0x1dd1a1) // Green
];
particles = new Float32Array(CONFIG.particleCount * 8);
for (let i = 0; i < CONFIG.particleCount; i++) {
const i8 = i * 8;
particles[i8] = (Math.random() - 0.5) * CONFIG.worldSize;
particles[i8+1] = (Math.random() - 0.5) * CONFIG.worldSize;
particles[i8+2] = (Math.random() - 0.5) * CONFIG.worldSize;
particles[i8+3] = 0; // vx
particles[i8+4] = 0; // vy
particles[i8+5] = 0; // vz
particles[i8+6] = Math.floor(Math.random() * CONFIG.types); // type
particles[i8+7] = 1.0; // Scale placeholder
}
instancedMesh = new THREE.InstancedMesh(geometry, material, CONFIG.particleCount);
instancedMesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
scene.add(instancedMesh);
randomizeRules();
setTimeout(() => {
document.getElementById('loading').style.opacity = 0;
}, 500);
}
function randomizeRules(mode = 'random') {
rules = [];
for (let i = 0; i < CONFIG.types; i++) {
rules[i] = [];
for (let j = 0; j < CONFIG.types; j++) {
if (mode === 'discrete') {
// Discrete steps create sharper structures
const steps = [-1.0, -0.5, 0.0, 0.2, 0.5, 0.8];
rules[i][j] = steps[Math.floor(Math.random() * steps.length)];
} else {
rules[i][j] = Math.random() * 2 - 1;
}
}
}
if (CONFIG.symmetric) {
for (let i = 0; i < CONFIG.types; i++) {
for (let j = i + 1; j < CONFIG.types; j++) {
rules[j][i] = rules[i][j];
}
// Self-interaction usually needs to be slightly repulsive or weakly attractive for volume
rules[i][i] = Math.max(-1.0, Math.min(0.5, rules[i][i]));
}
}
}
function setPreset(name) {
// Base settings for stability
CONFIG.symmetric = true;
document.getElementById('inp-symmetric').checked = true;
if (name === 'complex') {
// Large, slow-moving complex structures
CONFIG.radius = 90;
CONFIG.friction = 0.88;
CONFIG.forceFactor = 0.5;
CONFIG.maxSpeed = 2.0;
CONFIG.repulsionRadius = 0.3;
randomizeRules('discrete');
} else if (name === 'membranes') {
// Sheet-like structures
CONFIG.radius = 70;
CONFIG.friction = 0.82;
CONFIG.forceFactor = 0.8;
CONFIG.maxSpeed = 3.0;
CONFIG.repulsionRadius = 0.25;
// Generate specific membrane rules
randomizeRules();
// Hack: enforce some strong chains
for(let i=0; i<CONFIG.types; i++) {
rules[i][i] = 0.6; // Like self
rules[i][(i+1)%CONFIG.types] = 0.2;
}
} else if (name === 'snake') {
CONFIG.radius = 60;
CONFIG.friction = 0.85;
CONFIG.forceFactor = 1.2;
randomizeRules();
} else if (name === 'cells') {
// High repulsion short range, high attraction long range
CONFIG.radius = 100;
CONFIG.friction = 0.90; // Very stable
CONFIG.forceFactor = 0.4;
randomizeRules('discrete');
}
updateUiValues();
}
// --- Physics Loop ---
function updatePhysics() {
const count = CONFIG.particleCount;
const rMax = CONFIG.radius;
const rMaxSq = rMax * rMax;
const forceFactor = CONFIG.forceFactor;
const friction = CONFIG.friction;
const worldSize = CONFIG.worldSize;
const halfWorld = worldSize / 2;
const maxSpeed = CONFIG.maxSpeed;
const repulsionRad = CONFIG.repulsionRadius; // 0.0 to 1.0 of rMax
for (let i = 0; i < count; i++) {
const i8 = i * 8;
let fx = 0, fy = 0, fz = 0;
const typeI = particles[i8+6];
const px = particles[i8];
const py = particles[i8+1];
const pz = particles[i8+2];
for (let j = 0; j < count; j++) {
if (i === j) continue;
const j8 = j * 8;
let dx = particles[j8] - px;
let dy = particles[j8+1] - py;
let dz = particles[j8+2] - pz;
// Toroidal Wrap
if (dx > halfWorld) dx -= worldSize;
else if (dx < -halfWorld) dx += worldSize;
if (dy > halfWorld) dy -= worldSize;
else if (dy < -halfWorld) dy += worldSize;
if (dz > halfWorld) dz -= worldSize;
else if (dz < -halfWorld) dz += worldSize;
const distSq = dx*dx + dy*dy + dz*dz;
if (distSq > 0.01 && distSq < rMaxSq) {
const dist = Math.sqrt(distSq);
const q = dist / rMax;
const typeJ = particles[j8+6];
let f = 0;
// STABILITY LOGIC:
// 1. Strong Repulsion Zone (The Core)
if (q < repulsionRad) {
// Normalize q to 0..1 within the repulsion zone
const subQ = q / repulsionRad;
// Force scales up massively as we get closer to 0
f = (subQ - 1.0) * 2.0;
} else {
// 2. Interaction Zone
// Normalize q to 0..1 within interaction zone
const subQ = (q - repulsionRad) / (1.0 - repulsionRad);
// Peak curve: 0 at edges, 1 in middle
const strength = rules[typeI][typeJ];
// Smooth transition curve
f = strength * (1.0 - Math.abs(2.0 * subQ - 1.0));
// Alternative: Linear falloff
// f = strength * (1.0 - subQ);
}
// Apply force
const fScaled = (f * forceFactor) / dist;
fx += dx * fScaled;
fy += dy * fScaled;
fz += dz * fScaled;
}
}
// Integration
particles[i8+3] = (particles[i8+3] + fx) * friction;
particles[i8+4] = (particles[i8+4] + fy) * friction;
particles[i8+5] = (particles[i8+5] + fz) * friction;
// Velocity Cap
const vx = particles[i8+3];
const vy = particles[i8+4];
const vz = particles[i8+5];
const speedSq = vx*vx + vy*vy + vz*vz;
if (speedSq > maxSpeed * maxSpeed) {
const scale = maxSpeed / Math.sqrt(speedSq);
particles[i8+3] *= scale;
particles[i8+4] *= scale;
particles[i8+5] *= scale;
}
// Position Update
particles[i8] += particles[i8+3];
particles[i8+1] += particles[i8+4];
particles[i8+2] += particles[i8+5];
// Boundary Wrap
if (particles[i8] <= -halfWorld) particles[i8] += worldSize;
if (particles[i8] >= halfWorld) particles[i8] -= worldSize;
if (particles[i8+1] <= -halfWorld) particles[i8+1] += worldSize;
if (particles[i8+1] >= halfWorld) particles[i8+1] -= worldSize;
if (particles[i8+2] <= -halfWorld) particles[i8+2] += worldSize;
if (particles[i8+2] >= halfWorld) particles[i8+2] -= worldSize;
}
}
function updateVisuals() {
const count = CONFIG.particleCount;
const rMax = CONFIG.radius;
for (let i = 0; i < count; i++) {
const i8 = i * 8;
dummy.position.set(
particles[i8],
particles[i8+1],
particles[i8+2]
);
// Dynamic sizing based on neighbors/density could be cool,
// but for now let's scale based on interaction radius to keep it looking "structural"
// Smaller particles look better for large structures
const scale = rMax / 35.0;
dummy.scale.set(scale, scale, scale);
dummy.updateMatrix();
instancedMesh.setMatrixAt(i, dummy.matrix);
const type = particles[i8+6];
_color.copy(typeColors[type]);
instancedMesh.setColorAt(i, _color);
}
instancedMesh.instanceMatrix.needsUpdate = true;
if(instancedMesh.instanceColor) instancedMesh.instanceColor.needsUpdate = true;
}
// --- Loop ---
const statsEl = document.getElementById('stats');
let frames = 0;
let lastTime = 0;
function animate(time) {
requestAnimationFrame(animate);
frames++;
if (time - lastTime > 1000) {
statsEl.innerText = `FPS: ${frames} | Radius: ${CONFIG.radius} | Friction: ${CONFIG.friction}`;
frames = 0;
lastTime = time;
}
updatePhysics();
updateVisuals();
controls.update();
composer.render();
}
// --- UI Handlers ---
document.getElementById('inp-count').addEventListener('change', (e) => {
CONFIG.particleCount = parseInt(e.target.value);
document.getElementById('val-count').innerText = CONFIG.particleCount;
initSystem();
});
document.getElementById('inp-radius').addEventListener('input', (e) => {
CONFIG.radius = parseInt(e.target.value);
document.getElementById('val-radius').innerText = CONFIG.radius;
});
document.getElementById('inp-force').addEventListener('input', (e) => {
CONFIG.forceFactor = parseFloat(e.target.value);
document.getElementById('val-force').innerText = CONFIG.forceFactor;
});
document.getElementById('inp-friction').addEventListener('input', (e) => {
CONFIG.friction = parseFloat(e.target.value);
document.getElementById('val-friction').innerText = CONFIG.friction;
});
document.getElementById('inp-symmetric').addEventListener('change', (e) => {
CONFIG.symmetric = e.target.checked;
});
document.getElementById('btn-randomize').addEventListener('click', () => {
randomizeRules('discrete');
});
document.getElementById('btn-complex').addEventListener('click', () => setPreset('complex'));
document.getElementById('btn-membranes').addEventListener('click', () => setPreset('membranes'));
document.getElementById('btn-snake').addEventListener('click', () => setPreset('snake'));
document.getElementById('btn-cells').addEventListener('click', () => setPreset('cells'));
function updateUiValues() {
document.getElementById('inp-friction').value = CONFIG.friction;
document.getElementById('val-friction').innerText = CONFIG.friction;
document.getElementById('inp-force').value = CONFIG.forceFactor;
document.getElementById('val-force').innerText = CONFIG.forceFactor;
document.getElementById('inp-radius').value = CONFIG.radius;
document.getElementById('val-radius').innerText = CONFIG.radius;
}
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
composer.setSize(window.innerWidth, window.innerHeight);
});
// Initial Boot
initSystem();
// Set initial complex preset
setPreset('complex');
animate(0);
</script>
</body>
</html>