infinite-agents-public/legacy/src/ui_innovation_7.html

785 lines
29 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>UI Innovation: HarmonyProgress - Musical Progress Visualization</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #0a0a0a;
color: #e0e0e0;
line-height: 1.6;
overflow-x: hidden;
}
header {
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
padding: 3rem 2rem;
text-align: center;
border-bottom: 2px solid #3a3a5a;
}
header h1 {
font-size: 2.5rem;
background: linear-gradient(45deg, #ff6b6b, #4ecdc4, #45b7d1);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-bottom: 1rem;
animation: shimmer 3s ease-in-out infinite;
}
@keyframes shimmer {
0%, 100% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
}
.innovation-meta {
display: flex;
gap: 2rem;
justify-content: center;
flex-wrap: wrap;
margin-top: 1rem;
}
.innovation-meta p {
background: rgba(255, 255, 255, 0.05);
padding: 0.5rem 1.5rem;
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
main {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
section {
margin-bottom: 4rem;
background: rgba(255, 255, 255, 0.02);
border-radius: 15px;
padding: 2rem;
border: 1px solid rgba(255, 255, 255, 0.05);
}
h2 {
font-size: 2rem;
margin-bottom: 1.5rem;
color: #4ecdc4;
}
h3 {
font-size: 1.5rem;
margin-bottom: 1rem;
color: #45b7d1;
}
/* HarmonyProgress Styles */
.harmony-progress {
position: relative;
width: 100%;
height: 300px;
background: linear-gradient(180deg, #0a0a0a 0%, #1a1a2e 100%);
border-radius: 20px;
overflow: hidden;
margin: 2rem 0;
border: 2px solid rgba(78, 205, 196, 0.3);
box-shadow: 0 0 30px rgba(78, 205, 196, 0.2);
}
.harmony-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.harmony-info {
position: absolute;
top: 20px;
left: 20px;
z-index: 10;
background: rgba(0, 0, 0, 0.6);
padding: 10px 20px;
border-radius: 10px;
backdrop-filter: blur(10px);
}
.harmony-percentage {
font-size: 2rem;
font-weight: bold;
background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.harmony-status {
font-size: 0.9rem;
opacity: 0.8;
margin-top: 5px;
}
.control-panel {
display: flex;
gap: 1rem;
margin-top: 2rem;
flex-wrap: wrap;
justify-content: center;
}
.control-btn {
padding: 0.75rem 1.5rem;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
border-radius: 10px;
color: white;
font-size: 1rem;
cursor: pointer;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.control-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 20px rgba(102, 126, 234, 0.4);
}
.control-btn:active {
transform: translateY(0);
}
.control-btn::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 0;
height: 0;
border-radius: 50%;
background: rgba(255, 255, 255, 0.3);
transform: translate(-50%, -50%);
transition: width 0.6s, height 0.6s;
}
.control-btn:active::after {
width: 300px;
height: 300px;
}
/* Traditional Progress Bar */
.traditional-progress {
width: 100%;
height: 30px;
background: #2a2a2a;
border-radius: 15px;
overflow: hidden;
margin: 2rem 0;
border: 1px solid #3a3a3a;
}
.traditional-bar {
height: 100%;
background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);
width: 0%;
transition: width 0.3s ease;
display: flex;
align-items: center;
justify-content: flex-end;
padding-right: 10px;
color: white;
font-weight: bold;
}
/* Comparison Grid */
.comparison-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
margin-top: 2rem;
}
@media (max-width: 768px) {
.comparison-grid {
grid-template-columns: 1fr;
}
}
.comparison-item {
background: rgba(255, 255, 255, 0.03);
padding: 2rem;
border-radius: 15px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
/* Documentation Styles */
.doc-section {
background: rgba(255, 255, 255, 0.03);
padding: 1.5rem;
border-radius: 10px;
margin-bottom: 1.5rem;
border-left: 3px solid #4ecdc4;
}
.doc-section p {
opacity: 0.9;
line-height: 1.8;
}
.doc-section ul {
margin-left: 2rem;
margin-top: 0.5rem;
}
.doc-section li {
margin-bottom: 0.5rem;
}
/* Sound Controls */
.sound-toggle {
position: absolute;
top: 20px;
right: 20px;
z-index: 10;
background: rgba(0, 0, 0, 0.6);
padding: 10px;
border-radius: 50%;
cursor: pointer;
transition: all 0.3s ease;
backdrop-filter: blur(10px);
}
.sound-toggle:hover {
background: rgba(78, 205, 196, 0.3);
transform: scale(1.1);
}
.sound-toggle svg {
width: 24px;
height: 24px;
fill: #4ecdc4;
}
/* Loading States */
.loading-message {
text-align: center;
padding: 2rem;
opacity: 0.7;
}
/* Frequency Bars */
.frequency-bar {
position: absolute;
bottom: 0;
width: 2px;
background: linear-gradient(to top, #ff6b6b, #4ecdc4);
transition: height 0.1s ease-out;
opacity: 0.8;
}
</style>
</head>
<body>
<!-- Documentation Header -->
<header>
<h1>UI Innovation: HarmonyProgress</h1>
<div class="innovation-meta">
<p><strong>Replaces:</strong> Traditional Progress Bars</p>
<p><strong>Innovation:</strong> Musical & Visual Sound Wave Progress Visualization</p>
</div>
</header>
<!-- Interactive Demo Section -->
<main>
<section class="demo-container">
<h2>Interactive Demo</h2>
<div class="harmony-progress" id="harmonyProgress" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
<canvas class="harmony-canvas" id="waveCanvas"></canvas>
<div class="harmony-info">
<div class="harmony-percentage" id="progressPercentage">0%</div>
<div class="harmony-status" id="progressStatus">Ready to begin</div>
</div>
<button class="sound-toggle" id="soundToggle" aria-label="Toggle sound">
<svg viewBox="0 0 24 24">
<path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/>
</svg>
</button>
</div>
<div class="control-panel">
<button class="control-btn" onclick="startProgress()">Start Progress</button>
<button class="control-btn" onclick="pauseProgress()">Pause</button>
<button class="control-btn" onclick="resumeProgress()">Resume</button>
<button class="control-btn" onclick="resetProgress()">Reset</button>
<button class="control-btn" onclick="completeProgress()">Complete Instantly</button>
</div>
</section>
<!-- Traditional Comparison -->
<section class="comparison">
<h2>Traditional vs Innovation</h2>
<div class="comparison-grid">
<div class="comparison-item">
<h3>Traditional Progress Bar</h3>
<div class="traditional-progress">
<div class="traditional-bar" id="traditionalBar">0%</div>
</div>
<p>Simple visual representation with linear fill animation. Silent, predictable, and purely visual feedback.</p>
</div>
<div class="comparison-item">
<h3>HarmonyProgress Innovation</h3>
<p>Multi-sensory experience combining:</p>
<ul>
<li>Dynamic sound wave visualization</li>
<li>Musical tones that evolve with progress</li>
<li>Frequency spectrum analysis</li>
<li>Rhythmic patterns for different states</li>
<li>Synaesthetic feedback loop</li>
</ul>
</div>
</div>
</section>
<!-- Design Documentation -->
<section class="documentation">
<h2>Design Documentation</h2>
<div class="doc-section">
<h3>Interaction Model</h3>
<p>HarmonyProgress transforms progress monitoring into a musical performance. As tasks progress, users experience:</p>
<ul>
<li><strong>Visual Waveforms:</strong> Real-time sound wave visualization that dances with the generated audio</li>
<li><strong>Musical Progression:</strong> Tones that rise in pitch and complexity as progress increases</li>
<li><strong>Frequency Spectrum:</strong> Visual representation of audio frequencies creating a unique pattern for each progress state</li>
<li><strong>Rhythmic States:</strong> Different rhythmic patterns indicate loading, processing, paused, and completed states</li>
<li><strong>Interactive Control:</strong> Users can mute/unmute and control the progress flow</li>
</ul>
</div>
<div class="doc-section">
<h3>Technical Implementation</h3>
<p>Built using native Web APIs for maximum compatibility and performance:</p>
<ul>
<li><strong>Web Audio API:</strong> Generates real-time audio synthesis with oscillators and gain nodes</li>
<li><strong>Canvas API:</strong> Renders smooth waveform visualizations at 60fps</li>
<li><strong>RequestAnimationFrame:</strong> Ensures smooth animation performance</li>
<li><strong>AudioContext:</strong> Creates a complete audio processing graph</li>
<li><strong>AnalyserNode:</strong> Extracts frequency and time-domain data for visualization</li>
</ul>
</div>
<div class="doc-section">
<h3>Accessibility Features</h3>
<p>Designed to be inclusive and accessible to all users:</p>
<ul>
<li><strong>ARIA Attributes:</strong> Full progressbar role implementation with live values</li>
<li><strong>Sound Toggle:</strong> Respects user preferences with easy mute option</li>
<li><strong>Visual-Only Mode:</strong> Works perfectly without sound for hearing-impaired users</li>
<li><strong>Keyboard Navigation:</strong> All controls accessible via keyboard</li>
<li><strong>Screen Reader Support:</strong> Progress updates announced to assistive technologies</li>
<li><strong>High Contrast:</strong> Clear visual indicators work in various lighting conditions</li>
</ul>
</div>
<div class="doc-section">
<h3>Evolution Opportunities</h3>
<p>Future enhancements could explore:</p>
<ul>
<li><strong>Custom Sound Themes:</strong> User-selectable musical scales and instruments</li>
<li><strong>Collaborative Symphony:</strong> Multiple progress bars creating harmonious compositions</li>
<li><strong>Biometric Integration:</strong> Adapt tempo to user's heart rate or stress levels</li>
<li><strong>3D Visualization:</strong> WebGL-powered three-dimensional frequency landscapes</li>
<li><strong>AI Composition:</strong> Machine learning to generate unique progress melodies</li>
<li><strong>Haptic Feedback:</strong> Vibration patterns synchronized with audio rhythms</li>
</ul>
</div>
</section>
</main>
<script>
// Audio Context and Nodes
let audioContext;
let oscillator;
let gainNode;
let analyser;
let dataArray;
let bufferLength;
// Canvas Context
let canvas;
let ctx;
let animationId;
// Progress State
let currentProgress = 0;
let targetProgress = 0;
let progressInterval;
let isPaused = false;
let isCompleted = false;
let soundEnabled = true;
// Initialize on page load
window.addEventListener('load', () => {
canvas = document.getElementById('waveCanvas');
ctx = canvas.getContext('2d');
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// Initialize audio context on first user interaction
document.addEventListener('click', initAudio, { once: true });
// Start visualization even without audio
startVisualization();
});
function resizeCanvas() {
canvas.width = canvas.offsetWidth * window.devicePixelRatio;
canvas.height = canvas.offsetHeight * window.devicePixelRatio;
ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
}
function initAudio() {
if (!audioContext) {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
analyser = audioContext.createAnalyser();
analyser.fftSize = 256;
bufferLength = analyser.frequencyBinCount;
dataArray = new Uint8Array(bufferLength);
}
}
function createOscillator() {
if (!audioContext || !soundEnabled) return;
// Create nodes
oscillator = audioContext.createOscillator();
gainNode = audioContext.createGain();
// Connect nodes
oscillator.connect(gainNode);
gainNode.connect(analyser);
if (soundEnabled) {
gainNode.connect(audioContext.destination);
}
// Set initial values
oscillator.type = 'sine';
oscillator.frequency.setValueAtTime(200, audioContext.currentTime);
gainNode.gain.setValueAtTime(0, audioContext.currentTime);
// Start oscillator
oscillator.start();
// Fade in
gainNode.gain.linearRampToValueAtTime(0.1, audioContext.currentTime + 0.1);
}
function updateSound() {
if (!oscillator || !audioContext || !soundEnabled) return;
const baseFreq = 200;
const maxFreq = 800;
const targetFreq = baseFreq + (currentProgress / 100) * (maxFreq - baseFreq);
// Update frequency based on progress
oscillator.frequency.linearRampToValueAtTime(targetFreq, audioContext.currentTime + 0.1);
// Add rhythmic modulation
if (!isPaused && !isCompleted) {
const modulation = Math.sin(audioContext.currentTime * 5) * 20;
oscillator.frequency.setValueAtTime(targetFreq + modulation, audioContext.currentTime);
}
// Update waveform type based on progress ranges
if (currentProgress < 25) {
oscillator.type = 'sine';
} else if (currentProgress < 50) {
oscillator.type = 'triangle';
} else if (currentProgress < 75) {
oscillator.type = 'sawtooth';
} else {
oscillator.type = 'square';
}
}
function stopOscillator() {
if (oscillator) {
gainNode.gain.linearRampToValueAtTime(0, audioContext.currentTime + 0.2);
setTimeout(() => {
oscillator.stop();
oscillator.disconnect();
gainNode.disconnect();
oscillator = null;
gainNode = null;
}, 200);
}
}
function startVisualization() {
function draw() {
animationId = requestAnimationFrame(draw);
const width = canvas.offsetWidth;
const height = canvas.offsetHeight;
// Clear canvas
ctx.fillStyle = 'rgba(10, 10, 10, 0.1)';
ctx.fillRect(0, 0, width, height);
// Draw waveform
if (analyser && dataArray) {
analyser.getByteTimeDomainData(dataArray);
ctx.lineWidth = 2;
ctx.strokeStyle = `hsl(${180 + currentProgress * 1.8}, 70%, 50%)`;
ctx.beginPath();
const sliceWidth = width / bufferLength;
let x = 0;
for (let i = 0; i < bufferLength; i++) {
const v = dataArray[i] / 128.0;
const y = v * height / 2;
if (i === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
x += sliceWidth;
}
ctx.lineTo(width, height / 2);
ctx.stroke();
// Draw frequency bars
analyser.getByteFrequencyData(dataArray);
const barWidth = width / bufferLength * 2.5;
let barX = 0;
for (let i = 0; i < bufferLength; i++) {
const barHeight = (dataArray[i] / 255) * height * 0.8;
const hue = (i / bufferLength) * 120 + currentProgress * 2;
ctx.fillStyle = `hsla(${hue}, 70%, 50%, 0.7)`;
ctx.fillRect(barX, height - barHeight, barWidth, barHeight);
barX += barWidth + 1;
}
} else {
// Fallback visualization without audio
drawFallbackWave(width, height);
}
// Draw progress-based effects
drawProgressEffects(width, height);
}
draw();
}
function drawFallbackWave(width, height) {
ctx.lineWidth = 3;
ctx.strokeStyle = `hsl(${180 + currentProgress * 1.8}, 70%, 50%)`;
ctx.beginPath();
for (let x = 0; x < width; x++) {
const progress = x / width;
const amplitude = 50 * (currentProgress / 100);
const frequency = 0.02;
const offset = Date.now() * 0.001;
const y = height / 2 +
Math.sin((x * frequency + offset) * Math.PI) * amplitude *
Math.sin(progress * Math.PI);
if (x === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
}
ctx.stroke();
}
function drawProgressEffects(width, height) {
// Progress glow effect
const glowSize = 20 + currentProgress;
const glowX = (width * currentProgress) / 100;
const gradient = ctx.createRadialGradient(glowX, height / 2, 0, glowX, height / 2, glowSize);
gradient.addColorStop(0, `hsla(${180 + currentProgress * 1.8}, 70%, 50%, 0.8)`);
gradient.addColorStop(1, 'transparent');
ctx.fillStyle = gradient;
ctx.fillRect(glowX - glowSize, height / 2 - glowSize, glowSize * 2, glowSize * 2);
}
function updateProgress() {
if (isPaused || isCompleted) return;
if (currentProgress < targetProgress) {
currentProgress += 0.5;
if (currentProgress > targetProgress) {
currentProgress = targetProgress;
}
// Update UI
updateUI();
updateSound();
// Check completion
if (currentProgress >= 100) {
completeProgress();
}
}
}
function updateUI() {
// Update percentage display
document.getElementById('progressPercentage').textContent = Math.floor(currentProgress) + '%';
// Update ARIA attributes
document.getElementById('harmonyProgress').setAttribute('aria-valuenow', Math.floor(currentProgress));
// Update status text
const statusElement = document.getElementById('progressStatus');
if (isCompleted) {
statusElement.textContent = 'Complete! 🎵';
} else if (isPaused) {
statusElement.textContent = 'Paused';
} else if (currentProgress === 0) {
statusElement.textContent = 'Ready to begin';
} else if (currentProgress < 25) {
statusElement.textContent = 'Warming up...';
} else if (currentProgress < 50) {
statusElement.textContent = 'Building momentum...';
} else if (currentProgress < 75) {
statusElement.textContent = 'Approaching crescendo...';
} else if (currentProgress < 100) {
statusElement.textContent = 'Final movement...';
}
// Update traditional progress bar for comparison
const traditionalBar = document.getElementById('traditionalBar');
traditionalBar.style.width = currentProgress + '%';
traditionalBar.textContent = Math.floor(currentProgress) + '%';
}
// Control Functions
function startProgress() {
if (progressInterval) {
clearInterval(progressInterval);
}
initAudio();
resetProgress();
targetProgress = 100;
isPaused = false;
createOscillator();
progressInterval = setInterval(updateProgress, 50);
}
function pauseProgress() {
isPaused = true;
if (oscillator && gainNode) {
gainNode.gain.linearRampToValueAtTime(0.02, audioContext.currentTime + 0.1);
}
}
function resumeProgress() {
if (!progressInterval || isCompleted) {
startProgress();
} else {
isPaused = false;
if (oscillator && gainNode) {
gainNode.gain.linearRampToValueAtTime(0.1, audioContext.currentTime + 0.1);
}
}
}
function resetProgress() {
currentProgress = 0;
targetProgress = 0;
isPaused = false;
isCompleted = false;
if (progressInterval) {
clearInterval(progressInterval);
progressInterval = null;
}
stopOscillator();
updateUI();
}
function completeProgress() {
isCompleted = true;
currentProgress = 100;
updateUI();
if (progressInterval) {
clearInterval(progressInterval);
progressInterval = null;
}
// Play completion sound
if (audioContext && soundEnabled) {
playCompletionSound();
}
setTimeout(() => {
stopOscillator();
}, 1000);
}
function playCompletionSound() {
const completionOsc = audioContext.createOscillator();
const completionGain = audioContext.createGain();
completionOsc.connect(completionGain);
completionGain.connect(audioContext.destination);
completionOsc.type = 'sine';
completionOsc.frequency.setValueAtTime(523.25, audioContext.currentTime); // C5
completionOsc.frequency.linearRampToValueAtTime(659.25, audioContext.currentTime + 0.1); // E5
completionOsc.frequency.linearRampToValueAtTime(783.99, audioContext.currentTime + 0.2); // G5
completionGain.gain.setValueAtTime(0, audioContext.currentTime);
completionGain.gain.linearRampToValueAtTime(0.3, audioContext.currentTime + 0.05);
completionGain.gain.linearRampToValueAtTime(0, audioContext.currentTime + 0.5);
completionOsc.start(audioContext.currentTime);
completionOsc.stop(audioContext.currentTime + 0.5);
}
// Sound Toggle
document.getElementById('soundToggle').addEventListener('click', () => {
soundEnabled = !soundEnabled;
const svg = document.querySelector('#soundToggle svg');
if (!soundEnabled) {
svg.innerHTML = '<path d="M16.5 12c0-1.77-1.02-3.29-2.5-4.03v2.21l2.45 2.45c.03-.2.05-.41.05-.63zm2.5 0c0 .94-.2 1.82-.54 2.64l1.51 1.51C20.63 14.91 21 13.5 21 12c0-4.28-2.99-7.86-7-8.77v2.06c2.89.86 5 3.54 5 6.71zM4.27 3L3 4.27 7.73 9H3v6h4l5 5v-6.73l4.25 4.25c-.67.52-1.42.93-2.25 1.18v2.06c1.38-.31 2.63-.95 3.69-1.81L19.73 21 21 19.73l-9-9L4.27 3zM12 4L9.91 6.09 12 8.18V4z"/>';
if (oscillator && gainNode) {
gainNode.disconnect(audioContext.destination);
}
} else {
svg.innerHTML = '<path d="M3 9v6h4l5 5V4L7 9H3zm13.5 3c0-1.77-1.02-3.29-2.5-4.03v8.05c1.48-.73 2.5-2.25 2.5-4.02zM14 3.23v2.06c2.89.86 5 3.54 5 6.71s-2.11 5.85-5 6.71v2.06c4.01-.91 7-4.49 7-8.77s-2.99-7.86-7-8.77z"/>';
if (oscillator && gainNode && audioContext) {
gainNode.connect(audioContext.destination);
}
}
});
</script>
</body>
</html>