@namespace DeepDrftPublic.Client.Controls @using DeepDrftPublic.Client.Services @inject MixVisualizerControlState ControlState @* The Mix visualizer controls. EIGHT continuous RadialKnobs — scroll speed, gradient rotation speed, lava gravity, lava heat, fluid amount, fluid viscosity, collision strength, waveform width — each its own dedicated control with a Material-icon caption. The single "bubbles" knob is split into fluid-amount + fluid-viscosity (Phase 10 §5). Visibility (Phase 10 §4): the host ALWAYS renders this component now and feeds the lava-lamp toggle into the @Visible parameter. THIS component decides knob visibility — it @if-gates the knobs but keeps the container's reserved size, so the content below the controls bar never pops when the lamp toggles. The gating is Blazor @if (matching the established "@if-gated knob band, no CSS hide/glass/animation" convention) — the knobs are simply not rendered when hidden, while a min-height container holds the layout. No collapse animation, no glass surface, no CSS visibility-hiding of populated knobs. It owns NO JS interop: it mutates the shared, session-scoped MixVisualizerControlState and raises its Changed event. The backdrop bridge (MixWaveformVisualizer) subscribes to that event and pushes the affected dial to the WebGL module. That keeps the JS module handle single-owned by the bridge and this component purely presentational. None of these is a seek surface (read-only contract §D). RadialKnob has no icon slot (its Label renders as SVG text) and no aria attribute-capture, so each control's Material icon rides beside its knob as an adjacent MudIcon caption and the accessible name rides on the wrapping group div (§7d). HoldValue stays false so the knobs are live — ValueChanged fires continuously during drag, preserving the Changed/NotifyChanged seam. *@
@if (Visible) {
}
@code { /// /// Whether the knob band is shown. The host wires its lava-lamp toggle straight into this — the host /// always renders this component, and THIS component decides knob visibility (Phase 10 §4). When /// false the knobs are @if-gated out but the container holds its reserved height (CSS min-height), so /// content below the bar never pops as the lamp toggles. /// [Parameter] public bool Visible { get; set; } // Each handler mutates its own dedicated property then raises Changed — the bridge re-reads and // pushes the affected dial. All values are already normalized [0,1]; the bridge maps scroll speed // to a visible time-span and routes the rest straight to the lava/colour dials. private void OnScrollSpeedChanged(double value) { ControlState.ScrollSpeed = value; ControlState.NotifyChanged(); } private void OnGradientRotationSpeedChanged(double value) { ControlState.GradientRotationSpeed = value; ControlState.NotifyChanged(); } private void OnLavaGravityChanged(double value) { ControlState.LavaGravity = value; ControlState.NotifyChanged(); } private void OnLavaHeatChanged(double value) { ControlState.LavaHeat = value; ControlState.NotifyChanged(); } private void OnFluidAmountChanged(double value) { ControlState.FluidAmount = value; ControlState.NotifyChanged(); } private void OnFluidViscosityChanged(double value) { ControlState.FluidViscosity = value; ControlState.NotifyChanged(); } private void OnCollisionStrengthChanged(double value) { ControlState.CollisionStrength = value; ControlState.NotifyChanged(); } private void OnWaveformWidthChanged(double value) { ControlState.WaveformWidth = value; ControlState.NotifyChanged(); } }