Show floating grain particles in water when grain_mass > 0

35 particles distributed across full pot height, clipped to dynamic
water area via water-clip-rect updated alongside water fill level.
Particle opacity transitions on grain_mass changes per step.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DGKe8JzTM2Gr1fdx9wYXTi
This commit is contained in:
2026-06-26 22:27:05 +02:00
co-authored by Claude Sonnet 4.6
parent 7dfe88b89e
commit bc4a11dcb7
3 changed files with 76 additions and 0 deletions
+21
View File
@@ -320,6 +320,14 @@ function currentStepWaterMass() {
return sudWaterMass;
}
function currentStepGrainMass() {
if (sudStepIndex !== null && sudStepIndex >= 0 && sudStepIndex < sudSchedule.length) {
const step = sudSchedule[sudStepIndex];
if ('grain_mass' in step) return step.grain_mass;
}
return sudGrainMass;
}
function updatePotVisualization() {
// Thermometer mercury column (0°C = y=174, 100°C = y=28, tube length = 146)
const tubeBottom = 174;
@@ -338,9 +346,14 @@ function updatePotVisualization() {
const potInnerBottom = 172;
const potInnerH = potInnerBottom - potInnerTop; // 142
const particlesEl = document.getElementById('grain-particles');
const waterClipRect = document.getElementById('water-clip-rect');
if (sudEmpty || sudVolumen <= 0) {
waterFillEl.setAttribute('height', '0');
waterWaveEl.setAttribute('d', '');
if (waterClipRect) waterClipRect.setAttribute('height', '0');
if (particlesEl) particlesEl.style.opacity = '0';
return;
}
@@ -350,6 +363,14 @@ function updatePotVisualization() {
waterFillEl.setAttribute('y', waterTop.toFixed(1));
waterFillEl.setAttribute('height', waterH.toFixed(1));
waterWaveEl.setAttribute('d', wavePathD(63, 177, waterTop, 3, 28));
if (waterClipRect) {
waterClipRect.setAttribute('y', waterTop.toFixed(1));
waterClipRect.setAttribute('height', waterH.toFixed(1));
}
if (particlesEl) {
particlesEl.style.opacity = currentStepGrainMass() > 0 ? '1' : '0';
}
}
// --- Status line - mirrors update_status_step_label(). ---