diff --git a/app.py b/app.py index 7e72440..508a4c4 100644 --- a/app.py +++ b/app.py @@ -113,6 +113,14 @@ def handle_animation_speed_update(data): # Broadcast animation speed update to all clients emit('animation_speed_update', data, broadcast=True, include_self=False) +@socketio.on('brightness_update') +def handle_brightness_update(data): + """Handle brightness updates from controller""" + print(f'Brightness update received: {data}') + print(f'Broadcasting brightness update to {len(connected_clients)} clients') + # Broadcast brightness update to all clients + emit('brightness_update', data, broadcast=True, include_self=False) + @socketio.on('join_room') def handle_join_room(data): """Handle client joining a specific room""" diff --git a/templates/mechanical_counter.html b/templates/mechanical_counter.html index 92fa958..b30ef6d 100644 --- a/templates/mechanical_counter.html +++ b/templates/mechanical_counter.html @@ -75,7 +75,7 @@ top: 0; left: 0; width: 100%; - height: 1000px; /* 10 digits * 100px each */ + height: 1200px; /* 10 digits * 120px each (matches default wheel height) */ transition: transform 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94); display: flex; flex-direction: column; @@ -83,7 +83,7 @@ .digit { width: 100%; - height: 100px; + height: 120px; display: flex; justify-content: center; align-items: center; @@ -143,64 +143,13 @@ z-index: 1; } - .mechanical-sound::before { - content: ''; - position: absolute; - top: 50%; - left: 0; - right: 0; - height: 2px; - background: linear-gradient(90deg, transparent, #ffffff, transparent); - opacity: 0; - transition: opacity 0.3s; - } - - .digit-wheel.animating .mechanical-sound::before { - opacity: 1; - } - - /* Glitch effect for mechanical feel */ - .digit-wheel.animating .digit.active { - animation: glitch 0.1s ease-in-out; - } - - @keyframes glitch { - 0%, 100% { transform: translateX(0); } - 25% { transform: translateX(-1px); } - 75% { transform: translateX(1px); } - } - - /* Mechanical click sound simulation */ - .click-indicator { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 4px; - height: 4px; - background: #ffffff; - border-radius: 50%; - opacity: 0; - z-index: 3; - } - - .digit-wheel.animating .click-indicator { - animation: click 0.8s ease-in-out; - } - - @keyframes click { - 0% { opacity: 0; transform: translate(-50%, -50%) scale(0); } - 50% { opacity: 1; transform: translate(-50%, -50%) scale(1); } - 100% { opacity: 0; transform: translate(-50%, -50%) scale(2); } - } + /* Removed visual effects that caused white lines during animation */
Disconnected
-
-
0
1
@@ -216,8 +165,6 @@
-
-
0
1
@@ -233,8 +180,6 @@
-
-
0
1
@@ -250,8 +195,6 @@
-
-
0
1
@@ -267,8 +210,6 @@
-
-
0
1
@@ -284,8 +225,6 @@
-
-
0
1
@@ -319,6 +258,9 @@ // Animation speed (default value) let currentAnimationSpeed = 0.5; + + // Brightness (default value) + let currentBrightness = 100; // Connection status socket.on('connect', function() { @@ -372,6 +314,12 @@ updateAnimationSpeed(data.speed || data); }); + // Handle brightness updates from controller + socket.on('brightness_update', function(data) { + console.log('Received brightness update:', data); + updateBrightness(data.brightness || data); + }); + // Handle general events (for backward compatibility) socket.on('receive_event', function(data) { console.log('Received event:', data); @@ -390,6 +338,9 @@ if (data.type === 'animation_speed' || data.speed) { updateAnimationSpeed(data.speed || data); } + if (data.type === 'brightness' || data.brightness) { + updateBrightness(data.brightness || data); + } }); function updateCounter(values) { @@ -450,6 +401,7 @@ const currentValue = parseInt(strip.getAttribute('data-current') || '0'); const targetY = -(currentValue * height); strip.style.transform = `translateY(${targetY}px)`; + console.log(`Recalculated digit strip ${index} position to ${targetY}px for value ${currentValue}`); }); // Update individual digit heights and widths @@ -473,6 +425,21 @@ }); } + function updateBrightness(brightness) { + console.log('Updating brightness to:', brightness); + currentBrightness = brightness; + + // Calculate brightness filter value (0-1 range) + const brightnessFilter = brightness / 100; + + // Update all digit wheels with new brightness + const digitWheels = document.querySelectorAll('.digit-wheel'); + digitWheels.forEach((wheel, index) => { + wheel.style.filter = `brightness(${brightnessFilter})`; + console.log(`Updated digit wheel ${index} brightness to ${brightness}% (filter: ${brightnessFilter})`); + }); + } + function animateDigitWheel(position, fromValue, toValue) { const wheel = digitWheels[position]; const strip = wheel.querySelector('.digit-strip'); @@ -485,6 +452,8 @@ // Calculate the target position using current wheel height const targetY = -(toValue * wheelHeight); + console.log(`Animating digit ${position} from ${fromValue} to ${toValue}, targetY: ${targetY}, wheelHeight: ${wheelHeight}`); + // Add animation class wheel.classList.add('animating'); @@ -498,9 +467,14 @@ digit.classList.toggle('active', index === toValue); }); - // Remove animation class after animation completes + // Remove animation class after animation completes and ensure proper positioning setTimeout(() => { wheel.classList.remove('animating'); + + // Double-check the position is correct after animation + const finalTargetY = -(toValue * wheelHeight); + strip.style.transform = `translateY(${finalTargetY}px)`; + console.log(`Final position check for digit ${position}: ${finalTargetY}px`); }, currentAnimationSpeed * 1000); } @@ -543,36 +517,7 @@ socket.emit('viewport_update', viewportData); } - // Add some mechanical sound simulation - function playMechanicalSound() { - // Create a simple mechanical click sound using Web Audio API - try { - const audioContext = new (window.AudioContext || window.webkitAudioContext)(); - const oscillator = audioContext.createOscillator(); - const gainNode = audioContext.createGain(); - - oscillator.connect(gainNode); - gainNode.connect(audioContext.destination); - - oscillator.frequency.setValueAtTime(800, audioContext.currentTime); - oscillator.frequency.exponentialRampToValueAtTime(400, audioContext.currentTime + 0.1); - - gainNode.gain.setValueAtTime(0.1, audioContext.currentTime); - gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.1); - - oscillator.start(audioContext.currentTime); - oscillator.stop(audioContext.currentTime + 0.1); - } catch (e) { - console.log('Audio not supported'); - } - } - - // Play sound when digits animate - document.addEventListener('animationstart', function(e) { - if (e.target.classList.contains('digit-wheel')) { - playMechanicalSound(); - } - }); + // Removed mechanical sound simulation to eliminate white lines during animation \ No newline at end of file diff --git a/templates/mechanical_counter_controller.html b/templates/mechanical_counter_controller.html index 985d3ad..f1b2ffe 100644 --- a/templates/mechanical_counter_controller.html +++ b/templates/mechanical_counter_controller.html @@ -643,6 +643,102 @@ border-bottom: 1px solid #333; } + .brightness-controls { + background: rgba(0, 0, 0, 0.5); + border-radius: 10px; + padding: 20px; + margin-bottom: 20px; + border: 1px solid #00ff00; + } + + .brightness-controls h3 { + color: #00ff00; + text-align: center; + margin-bottom: 15px; + } + + .brightness-group { + display: flex; + align-items: center; + gap: 15px; + justify-content: center; + margin-bottom: 15px; + } + + .brightness-label { + font-weight: bold; + color: #00ff00; + min-width: 120px; + } + + .brightness-slider { + flex: 1; + max-width: 300px; + height: 6px; + background: rgba(255, 255, 255, 0.2); + border-radius: 3px; + outline: none; + -webkit-appearance: none; + } + + .brightness-slider::-webkit-slider-thumb { + -webkit-appearance: none; + width: 16px; + height: 16px; + background: #00ff00; + border-radius: 50%; + cursor: pointer; + } + + .brightness-slider::-moz-range-thumb { + width: 16px; + height: 16px; + background: #00ff00; + border-radius: 50%; + cursor: pointer; + border: none; + } + + .brightness-value { + min-width: 80px; + text-align: center; + font-family: monospace; + color: #00ff00; + font-weight: bold; + } + + .brightness-preview { + display: inline-block; + padding: 10px; + background: rgba(0, 0, 0, 0.8); + border: 1px solid #00ff00; + border-radius: 5px; + margin-left: 15px; + text-align: center; + } + + .brightness-preview-box { + width: 40px; + height: 60px; + background: linear-gradient(145deg, #2a2a2a, #1a1a1a); + border: 1px solid #444; + border-radius: 5px; + display: inline-block; + position: relative; + overflow: hidden; + } + + .brightness-preview-digit { + width: 100%; + height: 60px; + display: flex; + align-items: center; + justify-content: center; + color: #ffffff; + font-size: 20px; + background: linear-gradient(145deg, #1a1a1a, #0a0a0a); + } + .counter-preview { text-align: center; margin-bottom: 20px; @@ -730,6 +826,24 @@
+
+

Global Brightness Control

+
+
Brightness:
+ + 100% +
+
+
8
+
+
+
+
+ + +
+
+

Digit Wheel Size

@@ -963,6 +1077,9 @@ // Animation speed (default value) let currentAnimationSpeed = 0.5; + + // Brightness (default value) + let currentBrightness = 100; // Connection status socket.on('connect', function() { @@ -1071,6 +1188,21 @@ speedPreviewStrip.style.transition = `transform ${newSpeed}s ease`; }); + // Add event listener to brightness slider + const brightnessSlider = document.getElementById('globalBrightness'); + const brightnessValue = document.getElementById('globalBrightnessValue'); + const brightnessPreviewBox = document.getElementById('brightnessPreviewBox'); + + brightnessSlider.addEventListener('input', function() { + const newBrightness = parseInt(this.value); + currentBrightness = newBrightness; + brightnessValue.textContent = newBrightness + '%'; + + // Update preview with brightness filter + const brightnessFilter = newBrightness / 100; + brightnessPreviewBox.style.filter = `brightness(${brightnessFilter})`; + }); + function updateCounter() { const counterData = { type: 'counter_update', @@ -1300,6 +1432,27 @@ }, (currentAnimationSpeed * 1000) + 200); } + function updateGlobalBrightness() { + const brightnessData = { + type: 'brightness_update', + brightness: currentBrightness, + timestamp: new Date().toISOString() + }; + + console.log('Sending brightness update:', brightnessData); + socket.emit('brightness_update', brightnessData); + addSentEvent(brightnessData); + } + + function resetGlobalBrightness() { + const defaultBrightness = 100; + brightnessSlider.value = defaultBrightness; + currentBrightness = defaultBrightness; + brightnessValue.textContent = defaultBrightness + '%'; + brightnessPreviewBox.style.filter = 'brightness(1)'; + updateGlobalBrightness(); + } + function incrementDigit(index) { let currentValue = currentValues[index]; currentValue = (currentValue + 1) % 10; // Wrap around from 9 to 0