A Pen by Bob Wright on CodePen.
Created
February 3, 2026 07:59
-
-
Save Bob-Wright-the-reactor/21eaccb0de8d2b358fad66c5ab53fa9a to your computer and use it in GitHub Desktop.
Mochizuki Equations Bouncing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>IUT Frequency Resonator</title> | |
| <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js" async></script> | |
| <style> | |
| :root { | |
| --lapis: #26619C; | |
| --gold-leaf: #D4AF37; | |
| --void: #02040a; | |
| } | |
| body { | |
| margin: 0; | |
| overflow: hidden; | |
| background: #000000; | |
| font-family: 'Courier New', Courier, monospace; | |
| color: var(--lapis); | |
| user-select: none; | |
| } | |
| #toggle-controls { | |
| position: absolute; | |
| top: 10px; | |
| left: 10px; | |
| z-index: 101; | |
| background: var(--lapis); | |
| color: white; | |
| border: none; | |
| padding: 5px 10px; | |
| cursor: pointer; | |
| font-size: 0.8rem; | |
| text-transform: uppercase; | |
| } | |
| #ui-layer { | |
| display: none; | |
| position: absolute; | |
| top: 40px; | |
| left: 10px; | |
| z-index: 100; | |
| background: rgba(0, 0, 0, 0.7); | |
| padding: 10px; | |
| border: 1px solid var(--lapis); | |
| box-shadow: 0 0 10px var(--lapis); | |
| width: 200px; | |
| } | |
| .control-group { | |
| margin-bottom: 10px; | |
| } | |
| label { | |
| display: block; | |
| font-size: 0.7rem; | |
| color: var(--gold-leaf); | |
| margin-bottom: 3px; | |
| } | |
| input[type="number"], | |
| input[type="text"] { | |
| background: #000; | |
| color: var(--lapis); | |
| border: 1px solid var(--lapis); | |
| padding: 3px; | |
| width: 180px; | |
| } | |
| button { | |
| background: var(--lapis); | |
| color: white; | |
| border: none; | |
| padding: 5px 10px; | |
| cursor: pointer; | |
| font-weight: bold; | |
| text-transform: uppercase; | |
| width: 100%; | |
| } | |
| button:active { | |
| filter: brightness(1.2); | |
| } | |
| .volume-control { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| } | |
| .volume-btn { | |
| width: 30px; | |
| height: 30px; | |
| font-size: 1rem; | |
| padding: 0; | |
| margin: 0 5px; | |
| } | |
| .volume-display { | |
| background: #000; | |
| color: var(--lapis); | |
| border: 1px solid var(--lapis); | |
| padding: 3px; | |
| width: 50px; | |
| text-align: center; | |
| } | |
| .floating-eq { | |
| position: absolute; | |
| white-space: nowrap; | |
| font-weight: bold; | |
| font-size: 1.2rem; | |
| text-shadow: 0 0 10px var(--gold-leaf); | |
| cursor: pointer; | |
| padding: 10px; | |
| animation: pulse 2s infinite ease-in-out; | |
| color: var(--gold-leaf); | |
| } | |
| @keyframes pulse { | |
| 0% { | |
| opacity: 0.8; | |
| } | |
| 50% { | |
| opacity: 1; | |
| text-shadow: 0 0 25px var(--gold-leaf); | |
| } | |
| 100% { | |
| opacity: 0.8; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <button id="toggle-controls">Show Controls</button> | |
| <div id="ui-layer"> | |
| <div class="control-group"> | |
| <label>SYSTEM FREQUENCY (Hz)</label> | |
| <input type="number" id="freqInput" value="1506" step="1"> | |
| </div> | |
| <div class="control-group"> | |
| <button id="toggleBtn">START RESONANCE</button> | |
| </div> | |
| <div class="control-group"> | |
| <label>VOLUME (0-100)</label> | |
| <div class="volume-control"> | |
| <button class="volume-btn" id="volMinus">-</button> | |
| <span class="volume-display" id="volDisplay">2</span> | |
| <button class="volume-btn" id="volPlus">+</button> | |
| </div> | |
| </div> | |
| <div class="control-group"> | |
| <label>EQUATION SPEED</label> | |
| <input type="range" id="speedInput" min="0.5" max="3" step="0.1" value="1"> | |
| </div> | |
| <div class="control-group"> | |
| <button id="pauseBtn">PAUSE MOVEMENT</button> | |
| </div> | |
| <div class="control-group"> | |
| <label>NEW EQUATION (LaTeX)</label> | |
| <input type="text" id="newEqInput" placeholder="e.g., E=mc^2"> | |
| </div> | |
| <div class="control-group"> | |
| <button id="addEqBtn">ADD EQUATION</button> | |
| </div> | |
| <div class="control-group"> | |
| <button id="resetBtn">RESET ALL EQUATIONS</button> | |
| </div> | |
| </div> | |
| <script> | |
| const originalEquations = [ | |
| "-\\deg_{\\mathrm{fps}}(\\underline{q}) \\leq \\sum \\mathrm{vol}_v", | |
| "\\Theta: \\{a_j\\} \\mapsto q^{\\frac{j^2}{2l}}", | |
| "\\mathfrak{log}: \\mathcal{O}_v^\\times \\to K_v", | |
| "\\mathrm{indet}_{\\Theta} + \\mathrm{indet}_{\\mathfrak{log}}", | |
| "\\Pi_{X} \\to \\mathrm{Aut}(\\overline{K}/K)" | |
| ]; | |
| let elements = []; | |
| const screenWidth = window.innerWidth; | |
| const screenHeight = window.innerHeight; | |
| let speedFactor = 1; | |
| let isMoving = true; | |
| let dragging = null; | |
| let offsetX = 0; | |
| let offsetY = 0; | |
| let volume = 50; | |
| let intervalId = null; | |
| // Audio Context Setup | |
| let audioCtx; | |
| let oscillator; | |
| let gainNode; | |
| let isPlaying = false; | |
| function initAudio() { | |
| audioCtx = new(window.AudioContext || window.webkitAudioContext)(); | |
| gainNode = audioCtx.createGain(); | |
| gainNode.connect(audioCtx.destination); | |
| } | |
| document.getElementById('toggleBtn').addEventListener('click', () => { | |
| if (!audioCtx) initAudio(); | |
| if (!isPlaying) { | |
| oscillator = audioCtx.createOscillator(); | |
| oscillator.type = 'sine'; | |
| oscillator.frequency.setValueAtTime(document.getElementById('freqInput').value, audioCtx.currentTime); | |
| oscillator.connect(gainNode); | |
| oscillator.start(); | |
| document.getElementById('toggleBtn').textContent = "STOP RESONANCE"; | |
| isPlaying = true; | |
| } else { | |
| oscillator.stop(); | |
| document.getElementById('toggleBtn').textContent = "START RESONANCE"; | |
| isPlaying = false; | |
| } | |
| }); | |
| document.getElementById('freqInput').addEventListener('input', (e) => { | |
| const val = e.target.value; | |
| if (oscillator) oscillator.frequency.setTargetAtTime(val, audioCtx.currentTime, 0.05); | |
| document.body.style.filter = `hue-rotate(${val % 360}deg)`; | |
| }); | |
| function updateVolume() { | |
| const gainValue = volume / 200; | |
| if (gainNode) gainNode.gain.setTargetAtTime(gainValue, audioCtx ? audioCtx.currentTime : 0, 0.05); | |
| document.getElementById('volDisplay').textContent = volume; | |
| } | |
| function changeVolume(delta) { | |
| volume = Math.max(0, Math.min(100, volume + delta)); | |
| updateVolume(); | |
| } | |
| function startChangingVolume(delta) { | |
| changeVolume(delta); | |
| intervalId = setInterval(() => changeVolume(delta), 80); | |
| } | |
| function stopChangingVolume() { | |
| if (intervalId) { | |
| clearInterval(intervalId); | |
| intervalId = null; | |
| } | |
| } | |
| document.getElementById('volPlus').addEventListener('mousedown', () => startChangingVolume(1)); | |
| document.getElementById('volPlus').addEventListener('mouseup', stopChangingVolume); | |
| document.getElementById('volPlus').addEventListener('mouseleave', stopChangingVolume); | |
| document.getElementById('volPlus').addEventListener('touchstart', (e) => { | |
| e.preventDefault(); | |
| startChangingVolume(1); | |
| }); | |
| document.getElementById('volPlus').addEventListener('touchend', stopChangingVolume); | |
| document.getElementById('volMinus').addEventListener('mousedown', () => startChangingVolume(-1)); | |
| document.getElementById('volMinus').addEventListener('mouseup', stopChangingVolume); | |
| document.getElementById('volMinus').addEventListener('mouseleave', stopChangingVolume); | |
| document.getElementById('volMinus').addEventListener('touchstart', (e) => { | |
| e.preventDefault(); | |
| startChangingVolume(-1); | |
| }); | |
| document.getElementById('volMinus').addEventListener('touchend', stopChangingVolume); | |
| document.getElementById('speedInput').addEventListener('input', (e) => { | |
| speedFactor = parseFloat(e.target.value); | |
| }); | |
| document.getElementById('pauseBtn').addEventListener('click', () => { | |
| isMoving = !isMoving; | |
| document.getElementById('pauseBtn').textContent = isMoving ? "PAUSE MOVEMENT" : "RESUME MOVEMENT"; | |
| elements.forEach(p => { | |
| p.el.style.pointerEvents = isMoving ? 'none' : 'auto'; | |
| }); | |
| }); | |
| document.getElementById('toggle-controls').addEventListener('click', () => { | |
| const uiLayer = document.getElementById('ui-layer'); | |
| const toggleBtn = document.getElementById('toggle-controls'); | |
| uiLayer.style.display = uiLayer.style.display === 'block' ? 'none' : 'block'; | |
| toggleBtn.textContent = uiLayer.style.display === 'block' ? 'Hide Controls' : 'Show Controls'; | |
| }); | |
| function resetEquations() { | |
| // Remove all existing equation elements from DOM | |
| elements.forEach(p => { | |
| document.body.removeChild(p.el); | |
| }); | |
| elements = []; | |
| // Recreate original equations | |
| originalEquations.forEach((text) => { | |
| const el = document.createElement('div'); | |
| el.className = 'floating-eq'; | |
| el.textContent = `\\(${text}\\)`; | |
| document.body.appendChild(el); | |
| const data = { | |
| el: el, | |
| x: Math.random() * (window.innerWidth - 220) + 20, | |
| y: Math.random() * (window.innerHeight - 80) + 20, | |
| vx: (Math.random() - 0.5) * 4, | |
| vy: (Math.random() - 0.5) * 4 | |
| }; | |
| elements.push(data); | |
| el.style.pointerEvents = isMoving ? 'none' : 'auto'; | |
| el.addEventListener('mousedown', (e) => { | |
| if (!isMoving) { | |
| dragging = data; | |
| offsetX = e.clientX - data.x; | |
| offsetY = e.clientY - data.y; | |
| e.preventDefault(); | |
| } | |
| }); | |
| el.addEventListener('touchstart', (e) => { | |
| if (!isMoving) { | |
| const touch = e.touches[0]; | |
| dragging = data; | |
| offsetX = touch.clientX - data.x; | |
| offsetY = touch.clientY - data.y; | |
| e.preventDefault(); | |
| } | |
| }, { | |
| passive: false | |
| }); | |
| }); | |
| if (window.MathJax) MathJax.typesetPromise(); | |
| } | |
| document.getElementById('resetBtn').addEventListener('click', resetEquations); | |
| document.getElementById('addEqBtn').addEventListener('click', () => { | |
| const value = document.getElementById('newEqInput').value.trim(); | |
| if (!value) return; | |
| const el = document.createElement('div'); | |
| el.className = 'floating-eq'; | |
| el.textContent = `\\(${value}\\)`; | |
| document.body.appendChild(el); | |
| const data = { | |
| el: el, | |
| x: Math.random() * (window.innerWidth - 220) + 20, | |
| y: Math.random() * (window.innerHeight - 80) + 20, | |
| vx: (Math.random() - 0.5) * 4, | |
| vy: (Math.random() - 0.5) * 4 | |
| }; | |
| elements.push(data); | |
| el.style.pointerEvents = isMoving ? 'none' : 'auto'; | |
| el.addEventListener('mousedown', (e) => { | |
| if (!isMoving) { | |
| dragging = data; | |
| offsetX = e.clientX - data.x; | |
| offsetY = e.clientY - data.y; | |
| e.preventDefault(); | |
| } | |
| }); | |
| el.addEventListener('touchstart', (e) => { | |
| if (!isMoving) { | |
| const touch = e.touches[0]; | |
| dragging = data; | |
| offsetX = touch.clientX - data.x; | |
| offsetY = touch.clientY - data.y; | |
| e.preventDefault(); | |
| } | |
| }, { | |
| passive: false | |
| }); | |
| if (window.MathJax) MathJax.typesetPromise([el]); | |
| document.getElementById('newEqInput').value = ''; | |
| }); | |
| document.addEventListener('mousemove', (e) => { | |
| if (dragging) { | |
| dragging.x = e.clientX - offsetX; | |
| dragging.y = e.clientY - offsetY; | |
| dragging.el.style.left = dragging.x + 'px'; | |
| dragging.el.style.top = dragging.y + 'px'; | |
| } | |
| }); | |
| document.addEventListener('mouseup', () => dragging = null); | |
| document.addEventListener('touchmove', (e) => { | |
| if (dragging) { | |
| const touch = e.touches[0]; | |
| dragging.x = touch.clientX - offsetX; | |
| dragging.y = touch.clientY - offsetY; | |
| dragging.el.style.left = dragging.x + 'px'; | |
| dragging.el.style.top = dragging.y + 'px'; | |
| e.preventDefault(); | |
| } | |
| }, { | |
| passive: false | |
| }); | |
| document.addEventListener('touchend', () => dragging = null); | |
| // Initial population of equations | |
| resetEquations(); // Start with original set | |
| function bounceOffRect(p, rect) { | |
| if (!rect) return; | |
| const eqW = p.el.offsetWidth || 100; // fallback if not yet measured | |
| const eqH = p.el.offsetHeight || 40; | |
| const eqRect = { | |
| left: p.x, | |
| right: p.x + eqW, | |
| top: p.y, | |
| bottom: p.y + eqH | |
| }; | |
| if (eqRect.right > rect.left && eqRect.left < rect.right && | |
| eqRect.bottom > rect.top && eqRect.top < rect.bottom) { | |
| const oLeft = eqRect.right - rect.left; | |
| const oRight = rect.right - eqRect.left; | |
| const oTop = eqRect.bottom - rect.top; | |
| const oBottom = rect.bottom - eqRect.top; | |
| if (Math.min(oLeft, oRight) < Math.min(oTop, oBottom)) { | |
| if (oLeft < oRight) { | |
| p.vx = -Math.abs(p.vx) * 1.05; | |
| p.x = rect.left - eqW - 5; | |
| } else { | |
| p.vx = Math.abs(p.vx) * 1.05; | |
| p.x = rect.right + 5; | |
| } | |
| } else { | |
| if (oTop < oBottom) { | |
| p.vy = -Math.abs(p.vy) * 1.05; | |
| p.y = rect.top - eqH - 5; | |
| } else { | |
| p.vy = Math.abs(p.vy) * 1.05; | |
| p.y = rect.bottom + 5; | |
| } | |
| } | |
| } | |
| } | |
| function animate() { | |
| if (isMoving) { | |
| const toggleRect = document.getElementById('toggle-controls').getBoundingClientRect(); | |
| const uiLayer = document.getElementById('ui-layer'); | |
| const uiRect = uiLayer.style.display === 'block' ? uiLayer.getBoundingClientRect() : null; | |
| elements.forEach(p => { | |
| p.x += p.vx * speedFactor; | |
| p.y += p.vy * speedFactor; | |
| // Edge bounce + hard clamp | |
| if (p.x < 0) { | |
| p.x = 0; | |
| p.vx = Math.abs(p.vx); | |
| } | |
| if (p.x > window.innerWidth - (p.el.offsetWidth || 100)) { | |
| p.x = window.innerWidth - (p.el.offsetWidth || 100); | |
| p.vx = -Math.abs(p.vx); | |
| } | |
| if (p.y < 0) { | |
| p.y = 0; | |
| p.vy = Math.abs(p.vy); | |
| } | |
| if (p.y > window.innerHeight - (p.el.offsetHeight || 40)) { | |
| p.y = window.innerHeight - (p.el.offsetHeight || 40); | |
| p.vy = -Math.abs(p.vy); | |
| } | |
| bounceOffRect(p, toggleRect); | |
| if (uiRect) bounceOffRect(p, uiRect); | |
| p.el.style.left = p.x + 'px'; | |
| p.el.style.top = p.y + 'px'; | |
| }); | |
| } | |
| requestAnimationFrame(animate); | |
| } | |
| updateVolume(); | |
| animate(); | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment