diff --git a/web/app.js b/web/app.js
index 91d953e..e2be24d 100644
--- a/web/app.js
+++ b/web/app.js
@@ -273,6 +273,20 @@ function updateStepPlates() {
});
}
+// --- Stirrer visualization ---
+
+function updateStirrerVisualization() {
+ const g = document.getElementById('stirrer-blades');
+ if (!g) return;
+ if (stirrerSpeedIst > 0) {
+ const duration = Math.min(10, 50 / stirrerSpeedIst).toFixed(2);
+ g.style.setProperty('--stir-duration', duration + 's');
+ g.classList.add('spinning');
+ } else {
+ g.classList.remove('spinning');
+ }
+}
+
// --- Fire visualization ---
function updateFireVisualization() {
@@ -487,6 +501,7 @@ function onStirrerChanged(msg) {
document.getElementById('stirrer-speed-readout').textContent = msg.Speed;
initialSpeedSync = false;
}
+ updateStirrerVisualization();
updateStepPlates();
} else if (key === 'Capabilities') {
const power = msg.Capabilities.Power;
diff --git a/web/index.html b/web/index.html
index 2a2597f..eb28921 100644
--- a/web/index.html
+++ b/web/index.html
@@ -100,8 +100,10 @@
-
-
+
+
+
+
diff --git a/web/style.css b/web/style.css
index aa0f207..582ee72 100644
--- a/web/style.css
+++ b/web/style.css
@@ -152,6 +152,19 @@ header#connection-bar {
display: block;
}
+/* Stirrer animation */
+@keyframes stir-rotate {
+ to { transform: rotate(360deg); }
+}
+#stirrer-blades {
+ transform-box: fill-box;
+ transform-origin: 50% 50%;
+ animation: stir-rotate var(--stir-duration, 1s) linear infinite paused;
+}
+#stirrer-blades.spinning {
+ animation-play-state: running;
+}
+
/* Fire animations */
@keyframes flicker-1 {
0%, 100% { transform: scaleY(1.00) scaleX(1.00); }