Skip to content

Instantly share code, notes, and snippets.

@gkucmierz
Created June 14, 2026 15:36
Show Gist options
  • Select an option

  • Save gkucmierz/7c4520dff8f475e126978f896db1a9f7 to your computer and use it in GitHub Desktop.

Select an option

Save gkucmierz/7c4520dff8f475e126978f896db1a9f7 to your computer and use it in GitHub Desktop.
Run this code instantly in your browser: https://instacode.app/gist/7c4520dff8f475e126978f896db1a9f7
import { getContext, onResize } from 'canvas';
// Obtain the 2D rendering context
const ctx = getContext('2d');
let width = 400;
let height = 400;
let theta = 0; // Current angle in radians
let animationSpeed = 0.015; // Speed of rotation
let isAnimating = true;
// Setup canvas resize event listener
onResize((w, h) => {
width = w;
height = h;
draw();
});
// Main animation loop
function animate() {
if (isAnimating) {
theta += animationSpeed;
if (theta >= Math.PI) {
theta = Math.PI;
isAnimating = false; // Stop at pi (Euler's identity)
// Pause at the end for 2 seconds, then restart the loop
setTimeout(() => {
theta = 0;
isAnimating = true;
animate(); // Safely restart the single animation loop
}, 2000);
}
}
draw();
// Only request next frame if we are actively animating!
// This prevents loop accumulation and saves CPU when paused.
if (isAnimating) {
requestAnimationFrame(animate);
}
}
// Draw the frame
function draw() {
// Clear canvas with a deep slate background
ctx.fillStyle = '#0f172a';
ctx.fillRect(0, 0, width, height);
const centerX = width / 2;
const centerY = height / 2 + 30; // Shift down slightly to fit the headers
const scale = Math.min(width, height) * 0.35; // Radius scale
// Set line styles
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
// 1. Draw Grid/Axes
ctx.strokeStyle = '#334155'; // Slate 700
ctx.lineWidth = 1.5;
// Real axis (Re)
ctx.beginPath();
ctx.moveTo(20, centerY);
ctx.lineTo(width - 20, centerY);
ctx.stroke();
// Imaginary axis (Im)
ctx.beginPath();
ctx.moveTo(centerX, 20);
ctx.lineTo(centerX, height - 20);
ctx.stroke();
// 2. Draw Unit Circle
ctx.strokeStyle = '#1e293b'; // Very dark slate
ctx.lineWidth = 2;
ctx.setLineDash([5, 5]); // Dotted line
ctx.beginPath();
ctx.arc(centerX, centerY, scale, 0, Math.PI, true); // Semicircle
ctx.stroke();
ctx.setLineDash([]); // Reset line dash
// 3. Draw Axis Labels
ctx.fillStyle = '#94a3b8'; // Slate 400
ctx.font = '14px sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
// Origin (0)
ctx.fillText('0', centerX - 15, centerY + 15);
// Scale labels
ctx.fillText('1', centerX + scale, centerY + 20);
ctx.fillText('-1', centerX - scale, centerY + 20);
ctx.fillText('Re', width - 35, centerY - 15);
// Imaginary labels
ctx.fillText('i', centerX - 15, centerY - scale);
ctx.fillText('Im', centerX + 25, 35);
// 4. Draw Rotating Vector (Euler line)
const px = centerX + Math.cos(theta) * scale;
const py = centerY - Math.sin(theta) * scale;
ctx.strokeStyle = '#6366f1'; // Indigo 500
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.lineTo(px, py);
ctx.stroke();
// Angle arc
ctx.strokeStyle = '#818cf8'; // Indigo 400
ctx.lineWidth = 1.5;
ctx.beginPath();
ctx.arc(centerX, centerY, scale * 0.2, 0, -theta, true);
ctx.stroke();
// 5. Draw Traced Semicircle
ctx.strokeStyle = '#38bdf8'; // Sky 400
ctx.lineWidth = 4;
ctx.beginPath();
ctx.arc(centerX, centerY, scale, 0, -theta, true);
ctx.stroke();
// 6. Draw Moving Point with Glow
ctx.fillStyle = '#38bdf8'; // Sky 400
ctx.shadowColor = '#38bdf8';
ctx.shadowBlur = 10;
ctx.beginPath();
ctx.arc(px, py, 7, 0, Math.PI * 2);
ctx.fill();
ctx.shadowBlur = 0; // Reset shadow blur to avoid performance drop on text
// 7. Draw Texts & Equations
ctx.fillStyle = '#f8fafc'; // White slate
ctx.font = 'bold 20px sans-serif';
ctx.textAlign = 'center';
ctx.fillText("Euler's Identity Visualization", width / 2, 40);
ctx.fillStyle = '#e2e8f0';
ctx.font = '16px monospace';
ctx.fillText(`theta = ${(theta / Math.PI).toFixed(2)} * pi rad`, width / 2, 80);
// Display Real and Imaginary parts dynamically
const cosVal = Math.cos(theta).toFixed(3);
const sinVal = Math.sin(theta).toFixed(3);
ctx.fillStyle = '#6366f1'; // Real part color (Indigo)
ctx.textAlign = 'right';
ctx.fillText(`e^(i * theta) = ${cosVal}`, centerX + 20, 110);
ctx.fillStyle = '#38bdf8'; // Imaginary part color (Sky)
ctx.textAlign = 'left';
ctx.fillText(` + ${sinVal}i`, centerX + 20, 110);
// Display the verified equation at the end of the rotation
if (theta === Math.PI) {
ctx.fillStyle = '#10b981'; // Emerald 500
ctx.font = 'bold 18px sans-serif';
ctx.textAlign = 'center';
ctx.fillText("Identity Verified: e^(i * pi) = -1", width / 2, 140);
}
}
// Start the animation loop
animate();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment