Custom Code Experiment •
Calabi-Yau 2
Source Code View HTML / CSS / JavaScript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
background: #000;
overflow: hidden;
font-family: 'Courier New', monospace;
touch-action: none;
position: fixed;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
canvas {
display: block;
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
}
.controls {
position: fixed;
top: 20px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 12px;
z-index: 10;
padding: 10px;
background: rgba(0, 0, 0, 0.6);
border-radius: 35px;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
}
.btn {
width: 50px;
height: 50px;
border-radius: 50%;
border: 2px solid rgba(255, 255, 255, 0.3);
background: rgba(0, 0, 0, 0.5);
cursor: pointer;
transition: all 0.3s;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
color: rgba(255, 255, 255, 0.7);
-webkit-tap-highlight-color: transparent;
}
.btn:hover {
border-color: rgba(255, 255, 255, 0.8);
background: rgba(255, 255, 255, 0.1);
transform: scale(1.1);
}
.btn.active {
border-color: #0ff;
background: rgba(0, 255, 255, 0.2);
color: #0ff;
}
@media (max-width: 768px), (max-height: 600px) {
.controls {
top: 10px;
gap: 8px;
padding: 6px;
background: rgba(0, 0, 0, 0.75);
max-width: 95vw;
}
.btn {
width: 40px;
height: 40px;
font-size: 16px;
}
}
@media (max-width: 480px), (max-height: 500px) {
.controls {
top: 8px;
gap: 6px;
padding: 5px;
background: rgba(0, 0, 0, 0.8);
max-width: 98vw;
}
.btn {
width: 36px;
height: 36px;
font-size: 14px;
}
}
@media (max-height: 400px) {
.controls {
top: 5px;
gap: 4px;
padding: 4px;
}
.btn {
width: 32px;
height: 32px;
font-size: 12px;
}
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<div class="controls">
<button class="btn active" data-manifold="0">●</button>
<button class="btn" data-manifold="1">●</button>
<button class="btn" data-manifold="2">●</button>
<button class="btn" data-manifold="3">●</button>
<button class="btn" data-manifold="4">●</button>
</div>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
let w, h;
function resize() {
w = canvas.width = window.innerWidth;
h = canvas.height = window.innerHeight;
}
resize();
window.addEventListener('resize', resize);
let t = 0;
let currentManifold = 0;
let rotation = { x: 0, y: 0 };
document.querySelectorAll('.btn').forEach(btn => {
btn.addEventListener('click', () => {
document.querySelectorAll('.btn').forEach(b => b.classList.remove('active'));
btn.classList.add('active');
currentManifold = parseInt(btn.dataset.manifold);
});
});
function project(x, y, z, w4d) {
const scale = 1125 / (4 - w4d * 0.5);
const rx = x, ry = y, rz = z, rw = w4d;
const c1 = Math.cos(rotation.y), s1 = Math.sin(rotation.y);
const c2 = Math.cos(rotation.x), s2 = Math.sin(rotation.x);
const x1 = rx * c1 - rz * s1;
const z1 = rx * s1 + rz * c1;
const y1 = ry * c2 - z1 * s2;
const z2 = ry * s2 + z1 * c2;
return {
x: w / 2 + x1 * scale,
y: h / 2 + y1 * scale,
z: z2,
brightness: (z2 + 2) / 4
};
}
function manifold0(u, v, t) {
const r1 = 0.5 + 0.3 * Math.cos(3 * v + t);
const r2 = 0.5 + 0.3 * Math.sin(2 * u + t);
return {
x: r1 * Math.cos(u) * Math.cos(v),
y: r1 * Math.cos(u) * Math.sin(v),
z: r1 * Math.sin(u),
w: r2 * Math.sin(u + v)
};
}
function manifold1(u, v, t) {
const k = 0.3;
const a = Math.cos(u) + k * Math.cos(3 * u + t * 0.5);
const b = Math.sin(u) + k * Math.sin(3 * u + t * 0.5);
return {
x: a * Math.cos(v),
y: a * Math.sin(v),
z: b * Math.cos(v + t),
w: b * Math.sin(v + t)
};
}
function manifold2(u, v, t) {
const twist = Math.sin(u * 2 + t) * 0.3;
return {
x: Math.cos(u) * (1 + 0.3 * Math.cos(v + twist)),
y: Math.sin(u) * (1 + 0.3 * Math.cos(v + twist)),
z: 0.3 * Math.sin(v + twist),
w: Math.sin(u * 3 + v * 2 + t)
};
}
function manifold3(u, v, t) {
const r = 0.8 + 0.2 * Math.sin(4 * u + t);
const s = 0.8 + 0.2 * Math.cos(4 * v + t);
return {
x: r * Math.cos(u) * Math.cos(v),
y: r * Math.cos(u) * Math.sin(v),
z: s * Math.sin(u),
w: Math.sin(2 * u) * Math.cos(2 * v)
};
}
function manifold4(u, v, t) {
const p = 2, q = 3;
return {
x: Math.cos(p * u + t) * Math.cos(v),
y: Math.cos(p * u + t) * Math.sin(v),
z: Math.sin(q * u + t * 0.7) * Math.cos(v),
w: Math.sin(q * u + t * 0.7) * Math.sin(v)
};
}
const manifolds = [manifold0, manifold1, manifold2, manifold3, manifold4];
function draw() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.15)';
ctx.fillRect(0, 0, w, h);
const points = [];
const res = 40;
for (let i = 0; i <= res; i++) {
for (let j = 0; j <= res; j++) {
const u = (i / res) * Math.PI * 2;
const v = (j / res) * Math.PI * 2;
const p = manifolds[currentManifold](u, v, t);
const proj = project(p.x, p.y, p.z, p.w);
points.push({ ...proj, u: i, v: j });
}
}
points.sort((a, b) => a.z - b.z);
for (const p of points) {
if (p.brightness > 0) {
const hue = (p.u * 10 + p.v * 10 + t * 20) % 360;
const alpha = p.brightness * 0.8;
ctx.fillStyle = `hsla(${hue}, 70%, 60%, ${alpha})`;
ctx.beginPath();
ctx.arc(p.x, p.y, 2.5, 0, Math.PI * 2);
ctx.fill();
}
}
for (let i = 0; i < res; i++) {
for (let j = 0; j < res; j++) {
const idx = i * (res + 1) + j;
const p1 = points[idx];
const p2 = points[idx + 1];
const p3 = points[idx + res + 1];
if (p1 && p2 && p1.brightness > 0.2 && p2.brightness > 0.2) {
ctx.strokeStyle = `rgba(100, 200, 255, ${Math.min(p1.brightness, p2.brightness) * 0.3})`;
ctx.lineWidth = 0.5;
ctx.beginPath();
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p2.x, p2.y);
ctx.stroke();
}
if (p1 && p3 && p1.brightness > 0.2 && p3.brightness > 0.2) {
ctx.strokeStyle = `rgba(100, 200, 255, ${Math.min(p1.brightness, p3.brightness) * 0.3})`;
ctx.lineWidth = 0.5;
ctx.beginPath();
ctx.moveTo(p1.x, p1.y);
ctx.lineTo(p3.x, p3.y);
ctx.stroke();
}
}
}
t += 0.01;
rotation.y += 0.003;
requestAnimationFrame(draw);
}
draw();
</script>
</body>
</html>