namespace DeepDrftPublic.Client.Services; /// /// Holds the Mix visualizer's four continuous-control positions for the lifetime of the WASM app /// instance. Scoped in DI, so it lives across SPA navigations within one listening session — open a /// second mix and the sliders keep where you left them — but a fresh page load (F5) constructs a new /// instance, resetting to defaults. That matches the spec's "persist within session, reset on fresh /// load" without any cookie/localStorage round-trip (see mix-visualizer-webgl-renderer §3c). /// /// One state object, four properties — not four sibling holders (Daniel's decided shape, spec §3c). /// Each C#-side default mirrors a TS-side tuning anchor in MixVisualizer.ts; keep the two in sync, as /// the existing DefaultVisibleSeconds / DEFAULT_VISIBLE_SECONDS pair does. /// /// /// is the decoupling seam between the controls row and the visualizer bridge. /// The controls component (a sibling of the backdrop in the page tree) only mutates this shared state /// and raises ; the bridge component (MixWaveformVisualizer) subscribes /// and pushes the affected uniform to the JS module. This keeps the JS module handle single-owned by /// the bridge — no handle sharing, no service-locator, no cross-component interop. /// /// public sealed class MixVisualizerControlState { /// /// Default opening window. Mirrors DEFAULT_VISIBLE_SECONDS in MixVisualizer.ts; keep the /// two in sync (the TS owns the rendering anchors, this owns the C#-side session default). /// public const double DefaultVisibleSeconds = 10.0; // R2 TEMP (Phase 10 reframe Wave R2): the FOUR controls below are re-routed to the new // lava physics for Daniel's in-browser test — the JS handle setters map them as: // Bubblyness → lava GRAVITY, Detach → lava HEAT, ColorShiftSpeed → COLLISION STRENGTH, // Resolution (VisibleSeconds knob) → WAVEFORM WIDTH (see MixVisualizerControls.razor). // The defaults are tuned to Daniel's sweet spot (~20% gravity, ~100% heat). Wave R4 // replaces this with the proper seven-knob set + its own typed properties. Keep these // mirrored to the DEFAULT_* anchors in MixVisualizer.ts, as the existing sync discipline. /// /// Default GRAVITY dial (R2 temp; was bulge). Mirrors DEFAULT_BUBBLYNESS in MixVisualizer.ts. /// Normalized [0,1]; 0 = near-weightless float, 1 = wax falls + settles fast. Tuned to Daniel's /// ~20% sweet spot so the wax is buoyant-dominated and flows. /// public const double DefaultBubblyness = 0.2; /// /// Default HEAT dial (R2 temp; was detach). Mirrors DEFAULT_DETACH in MixVisualizer.ts. /// Normalized [0,1]; 0 = wax rests at the bottom (collision-only), 1 = lots of small turbulent /// bubbles. Tuned to Daniel's ~100% sweet spot. /// public const double DefaultDetach = 1.0; /// /// Default COLLISION-STRENGTH dial (R2 temp; was color-shift). Mirrors /// DEFAULT_COLOR_SHIFT_SPEED in MixVisualizer.ts. Normalized [0,1]; 0 = soft mush, /// 1 = hard elastic throw. /// public const double DefaultColorShiftSpeed = 0.5; /// /// Default WAVEFORM-WIDTH dial (R2 temp; routed to the resolution/zoom knob this wave). Mirrors /// DEFAULT_WAVEFORM_WIDTH in MixVisualizer.ts. Normalized [0,1]; 1 = full ribbon width /// (prior look), lower narrows the band so the lava gets more room. Opens at full width. /// public const double DefaultWaveformWidth = 1.0; /// Visible time-span in seconds (the resolution/zoom control). Reused as-is from 8.K. public double VisibleSeconds { get; set; } = DefaultVisibleSeconds; /// Bulge amount, normalized [0,1]. Inert until Wave 3 consumes the uniform. public double Bubblyness { get; set; } = DefaultBubblyness; /// Lava-lamp detachment, normalized [0,1]. Inert until Wave 3 consumes the uniform. public double Detach { get; set; } = DefaultDetach; /// Gradient-morph rate, normalized [0,1]. Inert until Wave 3 consumes the uniform. public double ColorShiftSpeed { get; set; } = DefaultColorShiftSpeed; /// /// Waveform width, normalized [0,1]. R2 TEMP: routed to the resolution/zoom knob for in-browser /// testing (Wave R4 gives it its own knob and restores the resolution knob to VisibleSeconds). /// public double WaveformWidth { get; set; } = DefaultWaveformWidth; /// /// Raised whenever any control value changes. The visualizer bridge subscribes to push the /// affected uniform(s). Mutators set the property then raise this; subscribers re-read the values. /// public event Action? Changed; /// Raise . Called by the controls component after mutating a value. public void NotifyChanged() => Changed?.Invoke(); }