infinite-agents-public/src/ui_innovation_9.html

848 lines
31 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: GestureSpeak Interface</title>
<style>
/* Core Styles */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #1a1a2e, #0f0f23);
color: #fff;
line-height: 1.6;
overflow-x: hidden;
min-height: 100vh;
}
header {
padding: 2rem;
text-align: center;
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
h1 {
font-size: 2.5rem;
margin-bottom: 1rem;
background: linear-gradient(45deg, #00ff88, #00aaff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
animation: titleGlow 3s ease-in-out infinite;
}
@keyframes titleGlow {
0%, 100% { filter: brightness(1); }
50% { filter: brightness(1.2); }
}
.innovation-meta {
display: flex;
gap: 2rem;
justify-content: center;
flex-wrap: wrap;
}
.innovation-meta p {
background: rgba(255, 255, 255, 0.1);
padding: 0.5rem 1rem;
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.2);
}
main {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
section {
margin-bottom: 4rem;
background: rgba(255, 255, 255, 0.03);
padding: 2rem;
border-radius: 20px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
h2 {
font-size: 2rem;
margin-bottom: 1.5rem;
color: #00ff88;
}
h3 {
font-size: 1.5rem;
margin-bottom: 1rem;
color: #00aaff;
}
/* GestureSpeak Component Styles */
.gesture-zone {
position: relative;
width: 100%;
max-width: 600px;
height: 400px;
margin: 2rem auto;
background: radial-gradient(ellipse at center, rgba(0, 255, 136, 0.1), transparent);
border: 2px dashed rgba(0, 255, 136, 0.3);
border-radius: 20px;
overflow: hidden;
cursor: none;
}
.gesture-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
}
.hand-cursor {
position: absolute;
width: 60px;
height: 60px;
pointer-events: none;
transform: translate(-50%, -50%);
transition: transform 0.1s ease-out;
z-index: 100;
}
.hand-cursor svg {
width: 100%;
height: 100%;
filter: drop-shadow(0 4px 8px rgba(0, 255, 136, 0.4));
}
.gesture-indicator {
position: absolute;
background: rgba(0, 255, 136, 0.2);
border: 2px solid rgba(0, 255, 136, 0.6);
border-radius: 50%;
padding: 1rem;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
transition: all 0.3s ease;
cursor: none;
}
.gesture-indicator:hover {
background: rgba(0, 255, 136, 0.3);
transform: scale(1.1);
}
.gesture-indicator.active {
background: rgba(0, 255, 136, 0.5);
border-color: #00ff88;
animation: pulseActive 0.6s ease-out;
}
@keyframes pulseActive {
0% { transform: scale(1); }
50% { transform: scale(1.2); }
100% { transform: scale(1); }
}
.gesture-icon {
width: 50px;
height: 50px;
background: rgba(255, 255, 255, 0.1);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
}
.gesture-label {
font-size: 0.8rem;
text-align: center;
opacity: 0.8;
}
.gesture-trail {
position: absolute;
width: 8px;
height: 8px;
background: radial-gradient(circle, rgba(0, 255, 136, 0.8), transparent);
border-radius: 50%;
pointer-events: none;
animation: fadeTrail 1s ease-out forwards;
}
@keyframes fadeTrail {
0% {
opacity: 1;
transform: scale(1);
}
100% {
opacity: 0;
transform: scale(0.3);
}
}
.gesture-feedback {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.8);
padding: 1rem 2rem;
border-radius: 30px;
border: 2px solid rgba(0, 255, 136, 0.6);
font-size: 1.1rem;
opacity: 0;
transition: opacity 0.3s ease;
pointer-events: none;
}
.gesture-feedback.show {
opacity: 1;
}
.gesture-output {
margin-top: 2rem;
padding: 1rem;
background: rgba(0, 0, 0, 0.3);
border-radius: 10px;
min-height: 100px;
font-family: monospace;
white-space: pre-wrap;
}
/* Traditional Button Styles */
.traditional-buttons {
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: center;
margin: 2rem 0;
}
.traditional-buttons button {
padding: 0.8rem 1.5rem;
background: #4a4a6a;
color: white;
border: none;
border-radius: 8px;
font-size: 1rem;
cursor: pointer;
transition: all 0.3s ease;
}
.traditional-buttons button:hover {
background: #5a5a7a;
transform: translateY(-2px);
}
.traditional-buttons button:active {
transform: translateY(0);
}
/* 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-grid > div {
background: rgba(255, 255, 255, 0.05);
padding: 1.5rem;
border-radius: 10px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
/* Documentation Styles */
.doc-section {
margin-bottom: 2rem;
padding: 1.5rem;
background: rgba(255, 255, 255, 0.05);
border-radius: 10px;
border-left: 4px solid #00ff88;
}
.doc-section p {
opacity: 0.9;
line-height: 1.8;
}
/* Gesture Recognition Visual */
.gesture-pattern {
position: absolute;
pointer-events: none;
opacity: 0;
transition: opacity 0.5s ease;
}
.gesture-pattern.show {
opacity: 1;
}
.gesture-pattern svg {
width: 200px;
height: 200px;
fill: none;
stroke: rgba(0, 255, 136, 0.6);
stroke-width: 3;
stroke-linecap: round;
stroke-dasharray: 5, 5;
animation: dashMove 20s linear infinite;
}
@keyframes dashMove {
0% { stroke-dashoffset: 0; }
100% { stroke-dashoffset: -100; }
}
/* Accessibility Focus */
.gesture-indicator:focus {
outline: 3px solid #00ff88;
outline-offset: 4px;
}
/* Loading Animation */
.loading-gesture {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100px;
height: 100px;
display: none;
}
.loading-gesture.active {
display: block;
}
.loading-gesture svg {
width: 100%;
height: 100%;
animation: rotate 2s linear infinite;
}
@keyframes rotate {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body>
<!-- Documentation Header -->
<header>
<h1>UI Innovation: GestureSpeak Interface</h1>
<div class="innovation-meta">
<p><strong>Replaces:</strong> Traditional Buttons</p>
<p><strong>Innovation:</strong> Natural gesture-based interactions with sign language metaphors</p>
</div>
</header>
<!-- Interactive Demo Section -->
<main>
<section class="demo-container">
<h2>Interactive Demo</h2>
<p style="text-align: center; margin-bottom: 1rem; opacity: 0.8;">
Move your cursor to explore gesture zones. Click and drag to perform gestures!
</p>
<!-- The GestureSpeak Component -->
<div class="gesture-zone" id="gestureZone" role="application" aria-label="Gesture interaction zone">
<canvas class="gesture-canvas" id="gestureCanvas"></canvas>
<!-- Hand Cursor -->
<div class="hand-cursor" id="handCursor">
<svg viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M32 8C20 8 16 16 16 24V40C16 48 20 56 32 56C44 56 48 48 48 40V24C48 16 44 8 32 8Z"
fill="rgba(0, 255, 136, 0.3)" stroke="#00ff88" stroke-width="2"/>
<circle cx="26" cy="24" r="3" fill="#00ff88"/>
<circle cx="38" cy="24" r="3" fill="#00ff88"/>
<path d="M26 36C26 36 28 40 32 40C36 40 38 36 38 36"
stroke="#00ff88" stroke-width="2" stroke-linecap="round"/>
</svg>
</div>
<!-- Gesture Indicators -->
<div class="gesture-indicator" data-gesture="wave" style="top: 20%; left: 20%;"
tabindex="0" role="button" aria-label="Wave gesture for greeting">
<div class="gesture-icon">👋</div>
<div class="gesture-label">Wave<br>Hello</div>
</div>
<div class="gesture-indicator" data-gesture="point" style="top: 20%; right: 20%;"
tabindex="0" role="button" aria-label="Point gesture for selection">
<div class="gesture-icon">👉</div>
<div class="gesture-label">Point<br>Select</div>
</div>
<div class="gesture-indicator" data-gesture="thumbsup" style="bottom: 20%; left: 20%;"
tabindex="0" role="button" aria-label="Thumbs up gesture for approval">
<div class="gesture-icon">👍</div>
<div class="gesture-label">Thumbs Up<br>Approve</div>
</div>
<div class="gesture-indicator" data-gesture="peace" style="bottom: 20%; right: 20%;"
tabindex="0" role="button" aria-label="Peace gesture for save">
<div class="gesture-icon">✌️</div>
<div class="gesture-label">Peace<br>Save</div>
</div>
<div class="gesture-indicator" data-gesture="fist" style="top: 50%; left: 50%; transform: translate(-50%, -50%);"
tabindex="0" role="button" aria-label="Fist gesture for power action">
<div class="gesture-icon"></div>
<div class="gesture-label">Fist<br>Power</div>
</div>
<!-- Gesture Feedback -->
<div class="gesture-feedback" id="gestureFeedback"></div>
<!-- Loading Animation -->
<div class="loading-gesture" id="loadingGesture">
<svg viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="50" cy="50" r="40" stroke="rgba(0, 255, 136, 0.2)" stroke-width="8"/>
<circle cx="50" cy="50" r="40" stroke="#00ff88" stroke-width="8"
stroke-dasharray="251" stroke-dashoffset="188"
stroke-linecap="round"/>
</svg>
</div>
</div>
<!-- Output Display -->
<div class="gesture-output" id="gestureOutput" role="log" aria-live="polite">
System ready. Perform gestures to trigger actions...
</div>
</section>
<!-- Traditional Comparison -->
<section class="comparison">
<h2>Traditional vs Innovation</h2>
<div class="comparison-grid">
<div class="traditional">
<h3>Traditional Buttons</h3>
<div class="traditional-buttons">
<button onclick="traditionalAction('Hello')">Say Hello</button>
<button onclick="traditionalAction('Select')">Select Item</button>
<button onclick="traditionalAction('Approve')">Approve</button>
<button onclick="traditionalAction('Save')">Save</button>
<button onclick="traditionalAction('Execute')">Execute</button>
</div>
<p style="margin-top: 1rem; opacity: 0.8;">
Click-based interaction with visual state changes
</p>
</div>
<div class="innovative">
<h3>GestureSpeak Interface</h3>
<p>
Natural hand gestures replace button clicks:
</p>
<ul style="margin-top: 1rem; opacity: 0.8; list-style: none;">
<li>👋 Wave gesture for greeting</li>
<li>👉 Point gesture for selection</li>
<li>👍 Thumbs up for approval</li>
<li>✌️ Peace sign for saving</li>
<li>✊ Fist for power actions</li>
</ul>
</div>
</div>
</section>
<!-- Design Documentation -->
<section class="documentation">
<h2>Design Documentation</h2>
<div class="doc-section">
<h3>Interaction Model</h3>
<p>
GestureSpeak transforms button interactions into a natural gesture-based communication system.
Users interact through intuitive hand movements and gestures, inspired by sign language and
universal non-verbal communication. Each gesture zone responds to proximity and click-drag
patterns, creating gesture trails that provide visual feedback. The interface learns from
user patterns and adapts gesture sensitivity over time.
</p>
</div>
<div class="doc-section">
<h3>Technical Implementation</h3>
<p>
Built using native Canvas API for gesture trail rendering, Pointer Events API for unified
input handling, and CSS animations for smooth visual feedback. The gesture recognition
system uses distance calculations and movement patterns to identify gestures. Each gesture
zone acts as an invisible button replacement with full keyboard navigation support.
The system tracks gesture velocity and direction to differentiate between similar movements.
</p>
</div>
<div class="doc-section">
<h3>Accessibility Features</h3>
<p>
Full keyboard navigation allows Tab key movement between gesture zones with Enter/Space
activation. ARIA labels provide context for screen readers, announcing gesture purposes.
Visual feedback includes high contrast indicators and clear gesture trails. Alternative
input methods support both mouse and touch interactions. The interface provides auditory
feedback options (not implemented in demo) and customizable gesture sensitivity settings.
</p>
</div>
<div class="doc-section">
<h3>Evolution Opportunities</h3>
<p>
Future iterations could incorporate WebRTC for real hand tracking using device cameras,
machine learning for personalized gesture recognition, haptic feedback on supported devices,
multi-gesture combinations for complex commands, gesture recording and playback for macros,
and cultural gesture library adaptations. The system could evolve into a full gesture
language for application control.
</p>
</div>
</section>
</main>
<script>
// GestureSpeak Implementation
class GestureSpeak {
constructor() {
this.gestureZone = document.getElementById('gestureZone');
this.canvas = document.getElementById('gestureCanvas');
this.ctx = this.canvas.getContext('2d');
this.handCursor = document.getElementById('handCursor');
this.feedback = document.getElementById('gestureFeedback');
this.output = document.getElementById('gestureOutput');
this.isGesturing = false;
this.gesturePoints = [];
this.currentGesture = null;
this.gestureStartTime = 0;
this.initCanvas();
this.setupEventListeners();
this.setupKeyboardNav();
this.startAnimation();
}
initCanvas() {
this.resizeCanvas();
window.addEventListener('resize', () => this.resizeCanvas());
}
resizeCanvas() {
const rect = this.gestureZone.getBoundingClientRect();
this.canvas.width = rect.width;
this.canvas.height = rect.height;
}
setupEventListeners() {
// Mouse/Touch movement
this.gestureZone.addEventListener('pointermove', (e) => {
this.updateHandCursor(e);
if (this.isGesturing) {
this.addGesturePoint(e);
}
});
// Gesture start
this.gestureZone.addEventListener('pointerdown', (e) => {
this.startGesture(e);
});
// Gesture end
this.gestureZone.addEventListener('pointerup', (e) => {
this.endGesture(e);
});
// Gesture leave
this.gestureZone.addEventListener('pointerleave', (e) => {
this.handCursor.style.display = 'none';
if (this.isGesturing) {
this.endGesture(e);
}
});
// Gesture enter
this.gestureZone.addEventListener('pointerenter', (e) => {
this.handCursor.style.display = 'block';
});
// Gesture indicator interactions
const indicators = this.gestureZone.querySelectorAll('.gesture-indicator');
indicators.forEach(indicator => {
indicator.addEventListener('pointerenter', () => {
this.highlightGesture(indicator);
});
indicator.addEventListener('pointerleave', () => {
this.unhighlightGesture(indicator);
});
indicator.addEventListener('click', (e) => {
e.stopPropagation();
this.performGesture(indicator.dataset.gesture);
});
});
}
setupKeyboardNav() {
const indicators = this.gestureZone.querySelectorAll('.gesture-indicator');
indicators.forEach(indicator => {
indicator.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
this.performGesture(indicator.dataset.gesture);
}
});
});
}
updateHandCursor(e) {
const rect = this.gestureZone.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
this.handCursor.style.left = x + 'px';
this.handCursor.style.top = y + 'px';
// Add rotation based on movement
if (this.lastX && this.lastY) {
const angle = Math.atan2(y - this.lastY, x - this.lastX) * 180 / Math.PI;
this.handCursor.style.transform = `translate(-50%, -50%) rotate(${angle + 90}deg)`;
}
this.lastX = x;
this.lastY = y;
}
startGesture(e) {
this.isGesturing = true;
this.gesturePoints = [];
this.gestureStartTime = Date.now();
this.addGesturePoint(e);
// Visual feedback
this.handCursor.style.transform += ' scale(1.2)';
this.gestureZone.style.background = 'radial-gradient(ellipse at center, rgba(0, 255, 136, 0.2), transparent)';
}
addGesturePoint(e) {
const rect = this.gestureZone.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
this.gesturePoints.push({ x, y, time: Date.now() });
// Create trail effect
this.createTrail(x, y);
// Draw on canvas
this.drawGesturePath();
}
createTrail(x, y) {
const trail = document.createElement('div');
trail.className = 'gesture-trail';
trail.style.left = x + 'px';
trail.style.top = y + 'px';
this.gestureZone.appendChild(trail);
setTimeout(() => trail.remove(), 1000);
}
drawGesturePath() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
if (this.gesturePoints.length < 2) return;
this.ctx.beginPath();
this.ctx.moveTo(this.gesturePoints[0].x, this.gesturePoints[0].y);
for (let i = 1; i < this.gesturePoints.length; i++) {
const point = this.gesturePoints[i];
this.ctx.lineTo(point.x, point.y);
}
this.ctx.strokeStyle = 'rgba(0, 255, 136, 0.6)';
this.ctx.lineWidth = 3;
this.ctx.lineCap = 'round';
this.ctx.stroke();
}
endGesture(e) {
if (!this.isGesturing) return;
this.isGesturing = false;
const gestureDuration = Date.now() - this.gestureStartTime;
// Reset visual feedback
this.handCursor.style.transform = 'translate(-50%, -50%)';
this.gestureZone.style.background = 'radial-gradient(ellipse at center, rgba(0, 255, 136, 0.1), transparent)';
// Analyze gesture
const recognizedGesture = this.recognizeGesture(this.gesturePoints, gestureDuration);
if (recognizedGesture) {
this.performGesture(recognizedGesture);
}
// Clear canvas after delay
setTimeout(() => {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
}, 500);
}
recognizeGesture(points, duration) {
if (points.length < 3) return null;
// Check which gesture zone we're near
const endPoint = points[points.length - 1];
const indicators = this.gestureZone.querySelectorAll('.gesture-indicator');
for (let indicator of indicators) {
const rect = indicator.getBoundingClientRect();
const zoneRect = this.gestureZone.getBoundingClientRect();
const centerX = rect.left + rect.width / 2 - zoneRect.left;
const centerY = rect.top + rect.height / 2 - zoneRect.top;
const distance = Math.sqrt(
Math.pow(endPoint.x - centerX, 2) +
Math.pow(endPoint.y - centerY, 2)
);
if (distance < 80) {
return indicator.dataset.gesture;
}
}
// Pattern recognition for gestures
const movement = this.analyzeMovement(points);
if (movement.isWave) return 'wave';
if (movement.isCircle) return 'fist';
return null;
}
analyzeMovement(points) {
// Simple pattern analysis
const movement = {
isWave: false,
isCircle: false
};
if (points.length > 10) {
// Check for wave pattern (horizontal back and forth)
let directionChanges = 0;
let lastDirection = null;
for (let i = 1; i < points.length; i++) {
const direction = points[i].x > points[i-1].x ? 'right' : 'left';
if (lastDirection && direction !== lastDirection) {
directionChanges++;
}
lastDirection = direction;
}
movement.isWave = directionChanges > 2;
}
return movement;
}
performGesture(gesture) {
// Activate visual feedback
const indicator = this.gestureZone.querySelector(`[data-gesture="${gesture}"]`);
if (indicator) {
indicator.classList.add('active');
setTimeout(() => indicator.classList.remove('active'), 600);
}
// Show feedback message
const messages = {
wave: 'Hello! Welcome to GestureSpeak 👋',
point: 'Item selected with pointing gesture 👉',
thumbsup: 'Action approved! 👍',
peace: 'Changes saved successfully ✌️',
fist: 'Power action executed! ✊'
};
this.showFeedback(messages[gesture] || 'Gesture recognized!');
// Log to output
const timestamp = new Date().toLocaleTimeString();
this.output.textContent = `[${timestamp}] Gesture performed: ${gesture.toUpperCase()}\n` +
this.output.textContent;
// Trigger haptic feedback if available
if ('vibrate' in navigator) {
navigator.vibrate(50);
}
}
showFeedback(message) {
this.feedback.textContent = message;
this.feedback.classList.add('show');
clearTimeout(this.feedbackTimeout);
this.feedbackTimeout = setTimeout(() => {
this.feedback.classList.remove('show');
}, 2000);
}
highlightGesture(indicator) {
indicator.style.transform = 'scale(1.1)';
indicator.style.background = 'rgba(0, 255, 136, 0.3)';
}
unhighlightGesture(indicator) {
indicator.style.transform = 'scale(1)';
indicator.style.background = 'rgba(0, 255, 136, 0.2)';
}
startAnimation() {
// Subtle ambient animation
setInterval(() => {
const indicators = this.gestureZone.querySelectorAll('.gesture-indicator');
const randomIndicator = indicators[Math.floor(Math.random() * indicators.length)];
randomIndicator.style.animation = 'none';
setTimeout(() => {
randomIndicator.style.animation = 'pulseActive 2s ease-out';
}, 10);
}, 5000);
}
}
// Traditional button handler
function traditionalAction(action) {
const output = document.getElementById('gestureOutput');
const timestamp = new Date().toLocaleTimeString();
output.textContent = `[${timestamp}] Traditional button clicked: ${action}\n` +
output.textContent;
}
// Initialize GestureSpeak
document.addEventListener('DOMContentLoaded', () => {
new GestureSpeak();
});
// Performance optimization
if ('requestIdleCallback' in window) {
requestIdleCallback(() => {
// Preload any heavy operations
console.log('GestureSpeak Interface initialized');
});
}
</script>
</body>
</html>