Last active
May 6, 2025 15:42
-
-
Save TomWhitwell/48cefdd751ad5afcd8fac66f6b6762af to your computer and use it in GitHub Desktop.
GPT Visualisation MIDI code
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
<!-- | |
Prompt used to generate this code: | |
Create an HTML file that shows rhythmic pulsing retro wireframe visuals that can be controlled using 8 MIDI CCs 35–41. Return the full code. | |
--> | |
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title>Retro Wireframe MIDI Visuals</title> | |
<style> | |
body { margin: 0; overflow: hidden; background: black; } | |
canvas { display: block; } | |
</style> | |
</head> | |
<body> | |
<script src="https://cdn.jsdelivr.net/npm/[email protected]/build/three.min.js"></script> | |
<script> | |
let scene, camera, renderer, grid; | |
let clock = new THREE.Clock(); | |
let params = { | |
pulseSpeed: 1.0, // CC 35 | |
gridSpacing: 10, // CC 36 | |
gridSize: 500, // CC 37 | |
colorHue: 0.6, // CC 38 | |
waveAmount: 0.5, // CC 39 | |
waveSpeed: 1.0, // CC 40 | |
lineThickness: 1.0 // CC 41 (not literal, affects line scale) | |
}; | |
function init() { | |
scene = new THREE.Scene(); | |
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000); | |
camera.position.set(0, 50, 100); | |
camera.lookAt(0, 0, 0); | |
renderer = new THREE.WebGLRenderer({ antialias: true }); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
document.body.appendChild(renderer.domElement); | |
createGrid(); | |
animate(); | |
} | |
function createGrid() { | |
if (grid) { | |
scene.remove(grid); | |
} | |
const geometry = new THREE.PlaneGeometry(params.gridSize, params.gridSize, params.gridSpacing, params.gridSpacing); | |
const material = new THREE.MeshBasicMaterial({ | |
color: new THREE.Color().setHSL(params.colorHue, 1, 0.5), | |
wireframe: true | |
}); | |
grid = new THREE.Mesh(geometry, material); | |
grid.rotation.x = -Math.PI / 2; | |
scene.add(grid); | |
} | |
function animate() { | |
requestAnimationFrame(animate); | |
const t = clock.getElapsedTime(); | |
if (grid.geometry && grid.geometry.attributes.position) { | |
const pos = grid.geometry.attributes.position; | |
for (let i = 0; i < pos.count; i++) { | |
let x = pos.getX(i); | |
let y = pos.getY(i); | |
let z = Math.sin((x + t * params.waveSpeed * 5) * 0.1) * params.waveAmount * 10 + | |
Math.cos((y + t * params.waveSpeed * 5) * 0.1) * params.waveAmount * 10; | |
pos.setZ(i, z); | |
} | |
pos.needsUpdate = true; | |
} | |
grid.material.color.setHSL(params.colorHue, 1, 0.5); | |
grid.scale.setScalar(1 + Math.sin(t * params.pulseSpeed) * 0.1 * params.lineThickness); | |
renderer.render(scene, camera); | |
} | |
// MIDI setup | |
function onMIDIMessage(message) { | |
const [status, cc, value] = message.data; | |
if (status === 0xB0) { // MIDI CC message | |
const normalized = value / 127; | |
switch (cc) { | |
case 35: params.pulseSpeed = 0.1 + normalized * 5; break; | |
case 36: params.gridSpacing = Math.round(5 + normalized * 50); createGrid(); break; | |
case 37: params.gridSize = Math.round(100 + normalized * 1000); createGrid(); break; | |
case 38: params.colorHue = normalized; break; | |
case 39: params.waveAmount = normalized * 2; break; | |
case 40: params.waveSpeed = 0.1 + normalized * 4; break; | |
case 41: params.lineThickness = 0.5 + normalized * 30; break; | |
} | |
} | |
} | |
function onMIDISuccess(midiAccess) { | |
for (let input of midiAccess.inputs.values()) { | |
input.onmidimessage = onMIDIMessage; | |
} | |
} | |
function onMIDIFailure() { | |
console.warn("Could not access your MIDI devices."); | |
} | |
if (navigator.requestMIDIAccess) { | |
navigator.requestMIDIAccess().then(onMIDISuccess, onMIDIFailure); | |
} else { | |
alert("Web MIDI is not supported in this browser."); | |
} | |
window.addEventListener('resize', () => { | |
camera.aspect = window.innerWidth / window.innerHeight; | |
camera.updateProjectionMatrix(); | |
renderer.setSize(window.innerWidth, window.innerHeight); | |
}); | |
init(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Amazing 🤩