quant_Synth / visualization.html
Joe-C-Wales's picture
Agent training
954fb1d verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Visualization - Quantum Music</title>
<link rel="icon" type="image/x-icon" href="/static/favicon.ico">
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/animejs/lib/anime.iife.min.js"></script>
<script src="https://unpkg.com/feather-icons"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<style>
:root {
--quantum-purple: #6e45e2;
--quantum-teal: #88d3ce;
--quantum-pink: #ff2a6d;
--quantum-blue: #05d9e8;
--quantum-dark: #0c0f1f;
--quantum-darker: #080a1a;
}
.quantum-bg {
background: linear-gradient(135deg, var(--quantum-dark), var(--quantum-darker));
position: relative;
overflow: hidden;
}
.quantum-bg::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background:
radial-gradient(circle at 10% 20%, rgba(110, 69, 226, 0.1) 0%, transparent 20%),
radial-gradient(circle at 90% 80%, rgba(136, 211, 206, 0.1) 0%, transparent 20%),
radial-gradient(circle at 50% 50%, rgba(5, 217, 232, 0.05) 0%, transparent 30%);
z-index: 0;
}
.quantum-card {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 16px;
transition: all 0.3s ease;
}
.quantum-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(110, 69, 226, 0.2);
border-color: rgba(110, 69, 226, 0.3);
}
.quantum-header {
background: rgba(12, 15, 31, 0.8);
backdrop-filter: blur(10px);
position: sticky;
top: 0;
z-index: 100;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.quantum-nav a {
position: relative;
padding: 8px 0;
}
.quantum-nav a::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
width: 0;
height: 2px;
background: var(--quantum-blue);
transition: width 0.3s ease;
}
.quantum-nav a:hover::after {
width: 100%;
}
#visualization-container {
width: 100%;
height: 500px;
background: rgba(10, 12, 25, 0.7);
border-radius: 12px;
position: relative;
overflow: hidden;
border: 1px solid rgba(110, 69, 226, 0.2);
}
.control-panel {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 1.5rem;
}
.legend-item {
display: flex;
align-items: center;
margin-bottom: 1rem;
}
.legend-color {
width: 20px;
height: 20px;
border-radius: 4px;
margin-right: 10px;
}
.slider {
width: 100%;
height: 6px;
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
outline: none;
-webkit-appearance: none;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 18px;
height: 18px;
border-radius: 50%;
background: var(--quantum-purple);
cursor: pointer;
box-shadow: 0 0 10px rgba(110, 69, 226, 0.5);
}
.quantum-btn {
background: linear-gradient(45deg, var(--quantum-purple), var(--quantum-teal));
border: none;
border-radius: 30px;
padding: 10px 20px;
font-weight: 600;
transition: all 0.3s ease;
color: white;
width: 100%;
}
.quantum-btn:hover {
transform: translateY(-3px);
box-shadow: 0 5px 20px rgba(110, 69, 226, 0.4);
}
.note-detail {
background: rgba(110, 69, 226, 0.1);
border-left: 3px solid var(--quantum-purple);
padding: 12px;
border-radius: 0 8px 8px 0;
margin-bottom: 10px;
}
</style>
</head>
<body class="bg-gray-900 text-white min-h-screen">
<div class="quantum-bg min-h-screen">
<!-- Header -->
<header class="quantum-header container mx-auto py-4 px-4">
<div class="flex justify-between items-center">
<h1 class="text-3xl font-bold">Quantum Music Synthesizer</h1>
<nav class="quantum-nav">
<ul class="flex space-x-8">
<li><a href="index.html" class="hover:text-purple-300 font-medium">Home</a></li>
<li><a href="synthesizer.html" class="hover:text-purple-300 font-medium">Synthesizer</a></li>
<li><a href="quantum.html" class="hover:text-purple-300 font-medium">Quantum</a></li>
<li><a href="visualization.html" class="hover:text-purple-300 font-medium">Visualization</a></li>
<li><a href="about.html" class="hover:text-purple-300 font-medium">About</a></li>
<li><a href="api.html" class="hover:text-purple-300 font-medium">API</a></li>
<li><a href="agent.html" class="hover:text-purple-300 font-medium">Agent</a></li>
</ul>
</nav>
</div>
</header>
<!-- Visualization Section -->
<section class="container mx-auto py-16 px-4">
<h2 class="text-4xl font-bold text-center mb-12">3D Note Visualization</h2>
<div class="max-w-7xl mx-auto quantum-card p-8">
<div class="grid grid-cols-1 lg:grid-cols-4 gap-8 mb-8">
<div class="lg:col-span-3">
<div id="visualization-container"></div>
</div>
<div class="space-y-6">
<div class="control-panel">
<h3 class="text-xl font-bold mb-4">Controls</h3>
<div class="space-y-5">
<div>
<label class="block mb-2">Rotation Speed</label>
<input type="range" id="rotation-speed" min="0" max="2" step="0.1" value="0.5" class="slider">
</div>
<div>
<label class="block mb-2">Point Size</label>
<input type="range" id="point-size" min="1" max="10" step="0.5" value="3" class="slider">
</div>
<div>
<label class="block mb-2">Animation Speed</label>
<input type="range" id="animation-speed" min="0.1" max="2" step="0.1" value="1" class="slider">
</div>
<div>
<button id="reset-view" class="quantum-btn">
Reset View
</button>
</div>
</div>
</div>
<div class="control-panel">
<h3 class="text-xl font-bold mb-4">Selected Note</h3>
<div id="note-details">
<p class="text-gray-400">Click on a note to see details</p>
</div>
</div>
</div>
</div>
<div class="mt-8">
<h3 class="text-2xl font-bold mb-6">Visualization Legend</h3>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="legend-item">
<div class="legend-color" style="background: linear-gradient(to right, #6e45e2, #88d3ce);"></div>
<div>
<h4 class="font-bold">X-Axis: Frequency</h4>
<p class="text-sm text-gray-400">Position represents note frequency (Hz)</p>
</div>
</div>
<div class="legend-item">
<div class="legend-color" style="background: linear-gradient(to right, #ff2a6d, #d10068);"></div>
<div>
<h4 class="font-bold">Y-Axis: Amplitude</h4>
<p class="text-sm text-gray-400">Height represents note volume</p>
</div>
</div>
<div class="legend-item">
<div class="legend-color" style="background: linear-gradient(to right, #05d9e8, #00a8b5);"></div>
<div>
<h4 class="font-bold">Z-Axis: Time</h4>
<p class="text-sm text-gray-400">Depth represents note sequence timing</p>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Footer -->
<footer class="container mx-auto py-8 px-4 text-center border-t border-gray-800">
<p class="text-gray-400">Powered by QuantumToolbox.jl, Amazon Braket, and Lindblad Solvers</p>
</footer>
</div>
<script>
feather.replace();
// Initialize Three.js scene
let scene, camera, renderer, points;
let rotationSpeed = 0.5;
let pointSize = 3;
let animationSpeed = 1;
let noteData = [];
function init() {
// Create scene
scene = new THREE.Scene();
scene.background = new THREE.Color(0x0c0f1f);
// Create camera
camera = new THREE.PerspectiveCamera(75,
document.getElementById('visualization-container').clientWidth /
document.getElementById('visualization-container').clientHeight,
0.1, 1000);
camera.position.set(0, 15, 30);
// Create renderer
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(
document.getElementById('visualization-container').clientWidth,
document.getElementById('visualization-container').clientHeight
);
document.getElementById('visualization-container').appendChild(renderer.domElement);
// Add lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(20, 20, 20);
scene.add(directionalLight);
// Add subtle fog
scene.fog = new THREE.Fog(0x0c0f1f, 20, 100);
// Generate sample note data
generateNoteData();
// Create 3D points
createPoints();
// Add grid helper
const gridHelper = new THREE.GridHelper(40, 20, 0x444444, 0x222222);
gridHelper.position.y = -5;
scene.add(gridHelper);
// Add axes helper
const axesHelper = new THREE.AxesHelper(20);
scene.add(axesHelper);
// Add event listeners
setupEventListeners();
// Start animation
animate();
}
function generateNoteData() {
// Generate sample musical sequence data
const baseNotes = [261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25]; // C4 to C5
const durations = [0.5, 1.0, 1.5, 2.0];
for (let i = 0; i < 100; i++) {
noteData.push({
frequency: baseNotes[Math.floor(Math.random() * baseNotes.length)] + (Math.random() * 200),
amplitude: Math.random(),
duration: durations[Math.floor(Math.random() * durations.length)],
time: i * 0.3,
color: new THREE.Color(
0.5 + 0.5 * Math.sin(i * 0.1),
0.3 + 0.3 * Math.cos(i * 0.15),
0.7 + 0.3 * Math.sin(i * 0.2)
)
});
}
}
function createPoints() {
const positions = new Float32Array(noteData.length * 3);
const colors = new Float32Array(noteData.length * 3);
// Normalize data for visualization
const maxFreq = Math.max(...noteData.map(n => n.frequency));
const minFreq = Math.min(...noteData.map(n => n.frequency));
const maxTime = Math.max(...noteData.map(n => n.time));
const maxAmplitude = Math.max(...noteData.map(n => n.amplitude));
for (let i = 0; i < noteData.length; i++) {
// Map frequency to X-axis (-20 to 20)
positions[i * 3] = ((noteData[i].frequency - minFreq) / (maxFreq - minFreq)) * 40 - 20;
// Map amplitude to Y-axis (0 to 30)
positions[i * 3 + 1] = (noteData[i].amplitude / maxAmplitude) * 30;
// Map time to Z-axis (-20 to 20)
positions[i * 3 + 2] = (noteData[i].time / maxTime) * 40 - 20;
// Set colors
colors[i * 3] = noteData[i].color.r;
colors[i * 3 + 1] = noteData[i].color.g;
colors[i * 3 + 2] = noteData[i].color.b;
}
// Create geometry
const geometry = new THREE.BufferGeometry();
geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
// Create material
const material = new THREE.PointsMaterial({
size: pointSize,
vertexColors: true,
transparent: true,
opacity: 0.9,
sizeAttenuation: true
});
// Create points
points = new THREE.Points(geometry, material);
scene.add(points);
}
function setupEventListeners() {
// Rotation speed control
document.getElementById('rotation-speed').addEventListener('input', function() {
rotationSpeed = parseFloat(this.value);
});
// Point size control
document.getElementById('point-size').addEventListener('input', function() {
pointSize = parseFloat(this.value);
points.material.size = pointSize;
});
// Animation speed control
document.getElementById('animation-speed').addEventListener('input', function() {
animationSpeed = parseFloat(this.value);
});
// Reset view button
document.getElementById('reset-view').addEventListener('click', function() {
camera.position.set(0, 15, 30);
camera.lookAt(0, 0, 0);
});
// Handle window resize
window.addEventListener('resize', function() {
camera.aspect = document.getElementById('visualization-container').clientWidth /
document.getElementById('visualization-container').clientHeight;
camera.updateProjectionMatrix();
renderer.setSize(
document.getElementById('visualization-container').clientWidth,
document.getElementById('visualization-container').clientHeight
);
});
// Mouse interaction for note selection
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
document.getElementById('visualization-container').addEventListener('click', function(event) {
// Calculate mouse position in normalized device coordinates
const rect = renderer.domElement.getBoundingClientRect();
mouse.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
mouse.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
// Update the picking ray with the camera and mouse position
raycaster.setFromCamera(mouse, camera);
// Calculate objects intersecting the picking ray
const intersects = raycaster.intersectObject(points);
if (intersects.length > 0) {
const index = intersects[0].index;
const note = noteData[index];
document.getElementById('note-details').innerHTML = `
<div class="note-detail">
<p><strong>Frequency:</strong> ${note.frequency.toFixed(2)} Hz</p>
</div>
<div class="note-detail">
<p><strong>Amplitude:</strong> ${(note.amplitude * 100).toFixed(0)}%</p>
</div>
<div class="note-detail">
<p><strong>Duration:</strong> ${note.duration} seconds</p>
</div>
<div class="note-detail">
<p><strong>Time:</strong> ${note.time.toFixed(1)} seconds</p>
</div>
`;
}
});
}
function animate() {
requestAnimationFrame(animate);
// Rotate the entire scene
if (points) {
points.rotation.y += 0.005 * rotationSpeed * animationSpeed;
}
// Add subtle floating animation to points
if (points) {
const positions = points.geometry.attributes.position.array;
for (let i = 1; i < positions.length; i += 3) {
positions[i] += Math.sin(Date.now() * 0.001 + i) * 0.01 * animationSpeed;
}
points.geometry.attributes.position.needsUpdate = true;
}
renderer.render(scene, camera);
}
// Initialize when page loads
window.addEventListener('load', init);
</script>
</body>
</html>