| <!DOCTYPE html> |
| <html lang="en"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> |
| <title>Vers3Dynamics Cymatics</title> |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/p5.min.js"></script> |
| <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.6.0/addons/p5.sound.min.js"></script> |
| <style> |
| body { |
| margin: 0; background: #050505; color: #ccc; |
| font-family: 'Courier New', Courier, monospace; overflow: hidden; |
| display: flex; flex-direction: column; align-items: center; justify-content: center; |
| height: 100vh; |
| |
| touch-action: none; |
| } |
| |
| canvas { |
| border: 1px solid #333; |
| box-shadow: 0 0 40px rgba(0, 255, 255, 0.05); |
| |
| margin-bottom: 0px; |
| } |
| |
| #ui-layer { |
| position: absolute; bottom: 20px; z-index: 10; |
| background: rgba(0, 0, 0, 0.9); backdrop-filter: blur(5px); |
| padding: 15px; border-radius: 12px; border: 1px solid #333; |
| display: flex; flex-direction: column; gap: 10px; width: 90%; max-width: 500px; |
| |
| touch-action: manipulation; |
| } |
| |
| |
| @media (max-width: 600px) { |
| body { |
| |
| |
| padding-bottom: 250px; |
| box-sizing: border-box; |
| } |
| #ui-layer { |
| bottom: 10px; |
| width: 95%; |
| padding: 10px; |
| } |
| button { |
| padding: 10px 5px; |
| } |
| } |
| |
| .row { display: flex; justify-content: space-between; align-items: center; gap: 8px; } |
| button { background: #111; color: cyan; border: 1px solid #333; padding: 8px 10px; cursor: pointer; border-radius: 4px; font-size: 11px; flex: 1; transition: all 0.2s; } |
| button:hover { border-color: cyan; background: #222; } |
| .active-btn { background: cyan; color: black; font-weight: bold; border-color: cyan; } |
| |
| #physics-info { |
| height: 30px; font-size: 10px; color: #00ff00; |
| border-top: 1px solid #333; padding-top: 10px; margin-top: 5px; text-align: center; |
| font-family: monospace; letter-spacing: 1px; |
| } |
| input[type="text"] { background: #000; border: 1px solid #333; color: cyan; padding: 10px; width: 100%; box-sizing: border-box; border-radius: 4px; text-align: center;} |
| </style> |
| </head> |
| <body> |
|
|
| <div id="ui-layer"> |
| <div class="row"> |
| <button id="textModeBtn" class="active-btn">🅰️ Intention</button> |
| <button id="audioModeBtn">🅱️ Acoustic Injection</button> |
| </div> |
|
|
| <div id="textSection" class="row"> |
| <input type="text" id="wordInput" placeholder="Type intention..."> |
| </div> |
|
|
| <div id="audioSection" class="row" style="display:none;"> |
| <input type="file" id="audioUpload" accept="audio/*" style="font-size:10px; color:#888;"> |
| <button id="playBtn" disabled>▶ Play</button> |
| </div> |
|
|
| <div class="row"> |
| <button id="physicsToggle">🛠️ Physics Sim</button> |
| <button id="freezeBtn">❄️ Freeze</button> |
| <button id="clearBtn">✨ Clear</button> |
| <button id="saveBtn">📸 Save</button> |
| </div> |
|
|
| <div id="physics-info"> |
| SYSTEM READY |
| </div> |
| </div> |
|
|
| <script> |
| let m = 5, n = 7; |
| let particles = 3000; |
| let sensitivity = 0.02; |
| let physicsMode = false; |
| let currentMode = 'text'; |
| let song, fft, isPlaying = false; |
| let frozenLayer, hasCheckpoint = false; |
| let canvasSize; |
| |
| function setup() { |
| calculateCanvasSize(); |
| let cnv = createCanvas(canvasSize, canvasSize); |
| pixelDensity(2); |
| |
| colorMode(HSB, 360, 100, 100, 100); |
| background(0); |
| |
| fft = new p5.FFT(0.8); |
| frozenLayer = createGraphics(width, height); |
| frozenLayer.colorMode(HSB, 360, 100, 100, 100); |
| |
| setupButtons(); |
| windowResized(); |
| } |
| |
| function calculateCanvasSize() { |
| |
| |
| if (windowWidth < 600) { |
| canvasSize = min(windowWidth * 0.95, windowHeight - 300); |
| } else { |
| canvasSize = min(windowWidth, windowHeight) * 0.9; |
| } |
| } |
| |
| function windowResized() { |
| calculateCanvasSize(); |
| resizeCanvas(canvasSize, canvasSize); |
| background(0); |
| } |
| |
| function setupButtons() { |
| select('#physicsToggle').mousePressed(() => { |
| physicsMode = !physicsMode; |
| let btn = select('#physicsToggle'); |
| if(physicsMode) { |
| btn.addClass('active-btn'); |
| btn.html("🛠️ Simulating..."); |
| } else { |
| btn.removeClass('active-btn'); |
| btn.html("🛠️ Physics Sim"); |
| } |
| updatePhysicsText(); |
| }); |
| |
| select('#wordInput').input(function() { |
| let word = this.value(); |
| if(word.length === 0) return; |
| let v1 = 0, v2 = 0; |
| for (let i = 0; i < word.length; i++) { |
| v1 += word.charCodeAt(i); v2 += word.charCodeAt(i) * (i + 1); |
| } |
| m = map(v1 % 100, 0, 100, 2, 12); |
| n = map(v2 % 100, 0, 100, 2, 12); |
| if(!hasCheckpoint) background(0); |
| }); |
| |
| select('#textModeBtn').mousePressed(() => switchMode('text')); |
| select('#audioModeBtn').mousePressed(() => switchMode('audio')); |
| |
| select('#audioUpload').elt.onchange = (e) => { |
| if(song) song.stop(); |
| song = loadSound(e.target.files[0], () => { |
| select('#playBtn').removeAttribute('disabled').html("▶ Play"); |
| select('#physics-info').html("AUDIO BUFFER LOADED"); |
| }); |
| }; |
| |
| select('#playBtn').mousePressed(() => { |
| if(song.isPlaying()) { song.pause(); isPlaying = false; select('#playBtn').html("▶ Play"); } |
| else { song.play(); isPlaying = true; select('#playBtn').html("⏸ Pause"); } |
| }); |
| |
| select('#freezeBtn').mousePressed(() => { |
| frozenLayer.clear(); |
| frozenLayer.image(get(), 0, 0, width, height); |
| hasCheckpoint = true; |
| select('#freezeBtn').html("❄️ Saved"); |
| setTimeout(() => select('#freezeBtn').html("❄️ Freeze"), 1000); |
| }); |
| |
| select('#clearBtn').mousePressed(() => { |
| if(hasCheckpoint) image(frozenLayer, 0, 0, width, height); |
| else background(0); |
| }); |
| |
| select('#saveBtn').mousePressed(() => saveCanvas('Vers3Dynamics_Blueprint', 'png')); |
| } |
| |
| function switchMode(m) { |
| currentMode = m; |
| select('#textSection').style('display', m === 'text' ? 'flex' : 'none'); |
| select('#audioSection').style('display', m === 'audio' ? 'flex' : 'none'); |
| select('#textModeBtn').toggleClass('active-btn', m === 'text'); |
| select('#audioModeBtn').toggleClass('active-btn', m === 'audio'); |
| } |
| |
| function updatePhysicsText() { |
| if (physicsMode) { |
| let traps = floor(m * n * 2); |
| let stability = ((m+n)/24*100).toFixed(1); |
| select('#physics-info').html(`LEVITATION TRAPS: ${traps} | PRESSURE: HIGH`); |
| } else { |
| select('#physics-info').html(":: VISUAL RESONANCE ENGINE ::"); |
| } |
| } |
| |
| function draw() { |
| if (currentMode === 'audio' && isPlaying) { |
| fft.analyze(); |
| m = lerp(m, map(fft.getEnergy("bass"), 0, 255, 2, 10), 0.05); |
| n = lerp(n, map(fft.getEnergy("treble"), 0, 255, 2, 14), 0.05); |
| background(0, 0, 0, 15); |
| } |
| |
| if (physicsMode) { |
| if (frameCount % 5 === 0) { |
| for(let k=0; k<10; k++) { |
| let px = random(width); |
| let py = random(height); |
| let lx = map(px, 0, width, -1, 1); |
| let ly = map(py, 0, height, -1, 1); |
| let pVal = cos(n * PI * lx / 2) * cos(m * PI * ly / 2) - cos(m * PI * lx / 2) * cos(n * PI * ly / 2); |
| if(abs(pVal) > 0.5) { |
| noFill(); stroke(0, 100, 100, 10); ellipse(px, py, 10 + abs(pVal)*20); |
| } |
| } |
| } |
| if (frameCount % 20 === 0) { |
| stroke(120, 100, 100, 40); strokeWeight(1); |
| let step = width/15; |
| for(let gx=0; gx<width; gx+=step) { |
| for(let gy=0; gy<height; gy+=step) { |
| let lx = map(gx, 0, width, -1, 1); |
| let ly = map(gy, 0, height, -1, 1); |
| let val = cos(n * PI * lx / 2) * cos(m * PI * ly / 2) - cos(m * PI * lx / 2) * cos(n * PI * ly / 2); |
| if(abs(val) < 0.05) { |
| line(gx-3, gy, gx+3, gy); line(gx, gy-3, gx, gy+3); |
| } |
| } |
| } |
| } |
| } |
| |
| if (frameCount % 30 === 0) updatePhysicsText(); |
| |
| for (let i = 0; i < particles; i++) { |
| let x = random(-1, 1), y = random(-1, 1); |
| let val = cos(n * PI * x / 2) * cos(m * PI * y / 2) - cos(m * PI * x / 2) * cos(n * PI * y / 2); |
| if (abs(val) < sensitivity) { |
| let sx = map(x, -1, 1, 0, width), sy = map(y, -1, 1, 0, height); |
| stroke(physicsMode ? color(120, 100, 100, 90) : color((frameCount * 0.5 + dist(0,0,x,y) * 100) % 360, 80, 100, 80)); |
| strokeWeight(1.5); |
| point(sx, sy); |
| } |
| } |
| } |
| </script> |
| </body> |
| </html> |