Custom Code Experiment •
Calabi-Yau 1
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">
<title>Calabi-Yau Manifold Animation</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: #0a0a0a;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
overflow: hidden;
padding-top: 80px;
}
#animation-container {
position: relative;
width: 100%;
height: calc(100vh - 80px);
}
canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: block;
}
.manifold-selector {
position: fixed;
top: 0;
left: 0;
width: 100%;
background: rgba(15, 15, 20, 0.95);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
padding: 15px;
z-index: 100;
display: flex;
justify-content: center;
align-items: center;
}
.selector-container {
display: flex;
gap: 8px;
max-width: 500px;
width: 100%;
flex-wrap: wrap;
justify-content: center;
}
.manifold-btn {
flex: 1;
min-width: 100px;
max-width: 120px;
background: rgba(255, 255, 255, 0.08);
color: rgba(255, 255, 255, 0.8);
border: none;
padding: 12px 16px;
border-radius: 12px;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
letter-spacing: 0.3px;
}
.manifold-btn:hover {
background: rgba(255, 255, 255, 0.12);
transform: translateY(-1px);
}
.manifold-btn.active {
background: linear-gradient(135deg, #4a4af0 0%, #5a5aff 100%);
color: white;
box-shadow: 0 4px 20px rgba(74, 74, 240, 0.3);
}
.manifold-btn.active:hover {
background: linear-gradient(135deg, #5a5aff 0%, #6a6aff 100%);
box-shadow: 0 6px 24px rgba(74, 74, 240, 0.4);
}
.manifold-indicator {
width: 6px;
height: 6px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
transition: background 0.3s;
}
.manifold-btn.active .manifold-indicator {
background: rgba(255, 255, 255, 0.9);
box-shadow: 0 0 8px rgba(255, 255, 255, 0.5);
}
.reset-notice {
position: fixed;
bottom: 20px;
right: 20px;
background: rgba(255, 74, 141, 0.2);
color: #ff4a8d;
padding: 10px 16px;
border-radius: 8px;
font-size: 13px;
opacity: 0;
transition: opacity 0.3s, transform 0.3s;
transform: translateY(10px);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid rgba(255, 74, 141, 0.2);
z-index: 100;
}
.reset-notice.visible {
opacity: 1;
transform: translateY(0);
}
/* Mobile optimizations */
@media (max-width: 768px) {
body {
padding-top: 70px;
}
#animation-container {
height: calc(100vh - 70px);
}
.manifold-selector {
padding: 12px;
}
.selector-container {
gap: 6px;
}
.manifold-btn {
min-width: calc(50% - 6px);
max-width: calc(50% - 6px);
padding: 10px 12px;
font-size: 13px;
border-radius: 10px;
}
.manifold-indicator {
width: 5px;
height: 5px;
}
}
@media (max-width: 480px) {
.manifold-selector {
padding: 10px;
}
.selector-container {
gap: 5px;
}
.manifold-btn {
min-width: calc(50% - 5px);
max-width: calc(50% - 5px);
padding: 10px 8px;
font-size: 12px;
}
.reset-notice {
bottom: 10px;
right: 10px;
left: 10px;
text-align: center;
font-size: 12px;
padding: 8px 12px;
}
}
@media (max-width: 320px) {
.manifold-btn {
min-width: 100%;
max-width: 100%;
flex-direction: row;
justify-content: center;
gap: 8px;
}
.manifold-indicator {
order: -1;
}
}
</style>
</head>
<body>
<div class="manifold-selector">
<div class="selector-container">
<button class="manifold-btn active" data-manifold="1">
<span class="manifold-indicator"></span>
<span>Manifold 1</span>
</button>
<button class="manifold-btn" data-manifold="2">
<span class="manifold-indicator"></span>
<span>Manifold 2</span>
</button>
<button class="manifold-btn" data-manifold="3">
<span class="manifold-indicator"></span>
<span>Manifold 3</span>
</button>
<button class="manifold-btn" data-manifold="4">
<span class="manifold-indicator"></span>
<span>Manifold 4</span>
</button>
</div>
</div>
<div id="animation-container">
<canvas id="calabi-canvas"></canvas>
</div>
<div class="reset-notice" id="reset-notice">Animation Reset</div>
<script>
// Canvas setup
const canvas = document.getElementById('calabi-canvas');
const ctx = canvas.getContext('2d');
let animationId = null;
// Animation parameters
let time = 0;
let manifoldType = 1;
// Resize management
let resizeTimeout;
let isResetting = false;
// Set canvas size
function setCanvasSize() {
const container = document.getElementById('animation-container');
canvas.width = container.clientWidth * window.devicePixelRatio;
canvas.height = container.clientHeight * window.devicePixelRatio;
// Scale context for retina displays
ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
console.log(`Canvas resized to: ${canvas.width / window.devicePixelRatio}x${canvas.height / window.devicePixelRatio}`);
}
// Show reset notice
function showResetNotice() {
const notice = document.getElementById('reset-notice');
notice.classList.add('visible');
setTimeout(() => {
notice.classList.remove('visible');
}, 1000);
}
// Clear and reset animation
function resetAnimation() {
if (isResetting) return;
isResetting = true;
// Clear any existing animation frame
if (animationId) {
cancelAnimationFrame(animationId);
}
// Reset canvas size
setCanvasSize();
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Reset time for animation continuity
time = 0;
// Restart animation
animate();
// Show notice
showResetNotice();
console.log('Animation reset complete');
isResetting = false;
}
// Animation loop
function animate() {
// Clear canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw Calabi-Yau manifold based on selected type
drawManifold();
// Increment time
time += 0.01;
// Continue animation loop
animationId = requestAnimationFrame(animate);
}
// Draw Calabi-Yau manifold
function drawManifold() {
const centerX = canvas.width / (2 * window.devicePixelRatio);
const centerY = canvas.height / (2 * window.devicePixelRatio);
const scale = Math.min(centerX, centerY) * 0.4;
// Common parameters
const detail = 100;
const radius = scale * 0.8;
// Set line style
ctx.lineWidth = 2;
ctx.strokeStyle = '#4a4af0';
ctx.fillStyle = 'rgba(74, 74, 240, 0.1)';
// Draw based on manifold type
switch(manifoldType) {
case 1:
drawManifold1(centerX, centerY, radius, detail);
break;
case 2:
drawManifold2(centerX, centerY, radius, detail);
break;
case 3:
drawManifold3(centerX, centerY, radius, detail);
break;
case 4:
drawManifold4(centerX, centerY, radius, detail);
break;
}
}
// Manifold 1: Basic torus with ripple
function drawManifold1(centerX, centerY, radius, detail) {
const tubeRadius = radius * 0.3;
ctx.beginPath();
for (let i = 0; i <= detail; i++) {
const u = (i / detail) * Math.PI * 2;
const ripple = Math.sin(u * 5 + time * 2) * 0.2;
for (let j = 0; j <= detail; j++) {
const v = (j / detail) * Math.PI * 2;
const x = (radius + tubeRadius * Math.cos(v + time)) * Math.cos(u + time);
const y = (radius + tubeRadius * Math.cos(v + time)) * Math.sin(u + time);
const z = tubeRadius * Math.sin(v + time) + ripple * radius;
const scale = 1 + z / (radius * 2);
const screenX = centerX + x * scale;
const screenY = centerY + y * scale;
if (j === 0) {
ctx.moveTo(screenX, screenY);
} else {
ctx.lineTo(screenX, screenY);
}
}
}
ctx.stroke();
}
// Manifold 2: Klein bottle-like surface
function drawManifold2(centerX, centerY, radius, detail) {
ctx.strokeStyle = '#ff4a8d';
ctx.fillStyle = 'rgba(255, 74, 141, 0.1)';
ctx.beginPath();
for (let i = 0; i <= detail; i++) {
const u = (i / detail) * Math.PI * 2;
for (let j = 0; j <= detail; j++) {
const v = (j / detail) * Math.PI * 2;
const x = radius * (Math.cos(u) * (1 + Math.cos(v)) +
Math.sin(u) * Math.cos(u) * Math.sin(v));
const y = radius * (Math.sin(u) * (1 + Math.cos(v)) -
Math.cos(u) * Math.cos(u) * Math.sin(v));
const z = radius * Math.sin(v) * Math.sin(u/2) + Math.sin(time) * radius * 0.3;
const rotation = time * 0.5;
const rotatedX = x * Math.cos(rotation) - z * Math.sin(rotation);
const rotatedZ = x * Math.sin(rotation) + z * Math.cos(rotation);
const screenX = centerX + rotatedX;
const screenY = centerY + y + rotatedZ * 0.5;
if (j === 0) {
ctx.moveTo(screenX, screenY);
} else {
ctx.lineTo(screenX, screenY);
}
}
}
ctx.stroke();
}
// Manifold 3: Complex harmonic surface
function drawManifold3(centerX, centerY, radius, detail) {
ctx.strokeStyle = '#4affa3';
ctx.fillStyle = 'rgba(74, 255, 163, 0.1)';
ctx.beginPath();
for (let i = 0; i <= detail; i++) {
const u = (i / detail) * Math.PI * 2;
for (let j = 0; j <= detail; j++) {
const v = (j / detail) * Math.PI * 2;
// Complex harmonic function
const harmonic = Math.sin(3 * u + time) * Math.cos(2 * v + time) *
Math.sin(u + v + time * 0.5);
const x = radius * Math.cos(u) * (1 + 0.5 * harmonic);
const y = radius * Math.sin(u) * (1 + 0.5 * harmonic);
const z = radius * Math.sin(v) * (1 + 0.3 * Math.cos(2 * u + time));
const scale = 1.2 + Math.sin(time + u) * 0.3;
const screenX = centerX + (x + z * 0.3) * scale;
const screenY = centerY + (y + z * 0.5) * scale;
if (j === 0) {
ctx.moveTo(screenX, screenY);
} else {
ctx.lineTo(screenX, screenY);
}
}
}
ctx.stroke();
}
// Manifold 4: Quantum foam-like structure
function drawManifold4(centerX, centerY, radius, detail) {
ctx.strokeStyle = '#ffa34a';
ctx.fillStyle = 'rgba(255, 163, 74, 0.1)';
ctx.beginPath();
for (let i = 0; i <= detail; i++) {
const u = (i / detail) * Math.PI * 2;
for (let j = 0; j <= detail; j++) {
const v = (j / detail) * Math.PI * 2;
// Quantum foam perturbation
const foam = Math.sin(5 * u + time * 3) *
Math.cos(4 * v + time * 2) *
Math.sin(2 * u * v + time);
const x = radius * Math.cos(u + foam * 0.3) *
(1 + 0.4 * Math.sin(2 * v + time));
const y = radius * Math.sin(u + foam * 0.3) *
(1 + 0.4 * Math.cos(2 * v + time));
const z = radius * foam * 0.5;
const twist = time * 0.3;
const twistedX = x * Math.cos(twist) - y * Math.sin(twist);
const twistedY = x * Math.sin(twist) + y * Math.cos(twist);
const screenX = centerX + twistedX + z * Math.cos(time);
const screenY = centerY + twistedY + z * Math.sin(time);
if (j === 0) {
ctx.moveTo(screenX, screenY);
} else {
ctx.lineTo(screenX, screenY);
}
}
}
ctx.stroke();
}
// Debounced resize handler
function handleResize() {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(() => {
resetAnimation();
}, 250); // Debounce delay of 250ms
}
// Initialize
function init() {
// Set initial canvas size
setCanvasSize();
// Start animation
animate();
// Add event listeners
window.addEventListener('resize', handleResize);
// Control buttons
document.querySelectorAll('.manifold-btn').forEach(button => {
button.addEventListener('click', function() {
// Update active button
document.querySelectorAll('.manifold-btn').forEach(btn => {
btn.classList.remove('active');
});
this.classList.add('active');
// Update manifold type
manifoldType = parseInt(this.dataset.manifold);
});
});
// Handle page visibility change
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
// Page is hidden, stop animation to save resources
if (animationId) {
cancelAnimationFrame(animationId);
animationId = null;
}
} else {
// Page is visible again, restart animation
if (!animationId) {
animate();
}
}
});
console.log('Calabi-Yau manifold animation initialized');
}
// Start everything
window.addEventListener('load', init);
</script>
</body>
</html>