feat(visualizer): R2 lava tuning — flat fluid, melt, up+out throw, heat-driven turbulence, waveform-width knob
This commit is contained in:
@@ -18,10 +18,13 @@
|
||||
<div class="mix-visualizer-controls">
|
||||
|
||||
@* RadialKnob exposes no aria-label/attribute-capture and is out of scope to modify, so the
|
||||
accessible name rides on the wrapping group div instead (a plain element accepts it). *@
|
||||
<div class="mix-visualizer-control" role="group" aria-label="Resolution (visible time-span)">
|
||||
<RadialKnob Value="@ResolutionFraction"
|
||||
ValueChanged="@OnResolutionChanged"
|
||||
accessible name rides on the wrapping group div instead (a plain element accepts it).
|
||||
R2 TEMP: this knob is repurposed from resolution/zoom to WAVEFORM WIDTH for in-browser lava
|
||||
testing (scroll speed isn't critical for evaluating the lava). The on-screen icon still reads
|
||||
ZoomIn; R4 redraws the controls and restores the resolution mapping. *@
|
||||
<div class="mix-visualizer-control" role="group" aria-label="Waveform width (R2 temp: on the resolution knob)">
|
||||
<RadialKnob Value="@ControlState.WaveformWidth"
|
||||
ValueChanged="@OnWaveformWidthChanged"
|
||||
Min="0"
|
||||
Max="1"
|
||||
Step="0.001"
|
||||
@@ -66,13 +69,11 @@
|
||||
</div>
|
||||
|
||||
@code {
|
||||
// Resolution rides the log mapping (knob fraction [0,1] ↔ visible seconds); the other three are
|
||||
// already normalized [0,1] and bind to their state properties directly.
|
||||
private double ResolutionFraction => MixZoomMapping.SecondsToFraction(ControlState.VisibleSeconds);
|
||||
|
||||
private void OnResolutionChanged(double fraction)
|
||||
// R2 TEMP: the resolution knob is repurposed to WAVEFORM WIDTH (already normalized [0,1], binds
|
||||
// directly). R4 restores the log zoom mapping (MixZoomMapping) and gives width its own knob.
|
||||
private void OnWaveformWidthChanged(double value)
|
||||
{
|
||||
ControlState.VisibleSeconds = MixZoomMapping.FractionToSeconds(fraction);
|
||||
ControlState.WaveformWidth = value;
|
||||
ControlState.NotifyChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -202,10 +202,12 @@ public partial class MixWaveformVisualizer : ComponentBase, IAsyncDisposable
|
||||
// ── Bridge pushes. Each is a no-op until the module handle exists. ───────────────────────────
|
||||
|
||||
/// <summary>
|
||||
/// Push all four control values to the module from the shared state. Used to seed on first render
|
||||
/// and to re-push when the controls row signals a change. Resolution drives the scroll/zoom; the
|
||||
/// other three are routed to the lava physics (gravity/heat/collision) by the JS handle in
|
||||
/// Wave R2 (see MixVisualizer.ts). The bridge contract is unchanged.
|
||||
/// Push the control values to the module from the shared state. Used to seed on first render and
|
||||
/// to re-push when the controls row signals a change. In the Phase 10 reframe Wave R2 the four
|
||||
/// live controls are routed to the lava physics by the JS handle (see MixVisualizer.ts):
|
||||
/// Bubblyness→gravity, Detach→heat, ColorShiftSpeed→collision, and the repurposed resolution knob
|
||||
/// (WaveformWidth)→waveform width. VisibleSeconds is still seeded once via setZoom so the window
|
||||
/// holds at its default; the controls row no longer mutates it this wave. Bridge contract unchanged.
|
||||
/// </summary>
|
||||
private async Task PushControlsAsync()
|
||||
{
|
||||
@@ -214,6 +216,7 @@ public partial class MixWaveformVisualizer : ComponentBase, IAsyncDisposable
|
||||
await _handle.InvokeVoidAsync("setBubblyness", ControlState.Bubblyness);
|
||||
await _handle.InvokeVoidAsync("setDetach", ControlState.Detach);
|
||||
await _handle.InvokeVoidAsync("setColorShiftSpeed", ControlState.ColorShiftSpeed);
|
||||
await _handle.InvokeVoidAsync("setWaveformWidth", ControlState.WaveformWidth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -27,33 +27,42 @@ public sealed class MixVisualizerControlState
|
||||
/// </summary>
|
||||
public const double DefaultVisibleSeconds = 10.0;
|
||||
|
||||
// R2 TEMP (Phase 10 reframe Wave R2): the three controls below are re-routed to the new
|
||||
// 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.
|
||||
// The defaults are bumped so the lava looks ALIVE on open (heat non-zero). Wave R4
|
||||
// replaces this with the proper six-knob set + its own typed properties. Keep these
|
||||
// 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.
|
||||
|
||||
/// <summary>
|
||||
/// Default GRAVITY dial (R2 temp; was bulge). Mirrors <c>DEFAULT_BUBBLYNESS</c> in MixVisualizer.ts.
|
||||
/// Normalized [0,1]; 0 = near-weightless float, 1 = wax falls + settles fast.
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public const double DefaultBubblyness = 0.5;
|
||||
public const double DefaultBubblyness = 0.2;
|
||||
|
||||
/// <summary>
|
||||
/// Default HEAT dial (R2 temp; was detach). Mirrors <c>DEFAULT_DETACH</c> in MixVisualizer.ts.
|
||||
/// Normalized [0,1]; 0 = wax rests at the bottom (collision-only), 1 = many bubbles rising.
|
||||
/// Non-zero default so the lamp is alive on open.
|
||||
/// Normalized [0,1]; 0 = wax rests at the bottom (collision-only), 1 = lots of small turbulent
|
||||
/// bubbles. Tuned to Daniel's ~100% sweet spot.
|
||||
/// </summary>
|
||||
public const double DefaultDetach = 0.45;
|
||||
public const double DefaultDetach = 1.0;
|
||||
|
||||
/// <summary>
|
||||
/// Default COLLISION-STRENGTH dial (R2 temp; was color-shift). Mirrors
|
||||
/// <c>DEFAULT_COLOR_SHIFT_SPEED</c> in MixVisualizer.ts. Normalized [0,1]; 0 = soft shove,
|
||||
/// 1 = hard elastic wall.
|
||||
/// <c>DEFAULT_COLOR_SHIFT_SPEED</c> in MixVisualizer.ts. Normalized [0,1]; 0 = soft mush,
|
||||
/// 1 = hard elastic throw.
|
||||
/// </summary>
|
||||
public const double DefaultColorShiftSpeed = 0.5;
|
||||
|
||||
/// <summary>
|
||||
/// Default WAVEFORM-WIDTH dial (R2 temp; routed to the resolution/zoom knob this wave). Mirrors
|
||||
/// <c>DEFAULT_WAVEFORM_WIDTH</c> 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.
|
||||
/// </summary>
|
||||
public const double DefaultWaveformWidth = 1.0;
|
||||
|
||||
/// <summary>Visible time-span in seconds (the resolution/zoom control). Reused as-is from 8.K.</summary>
|
||||
public double VisibleSeconds { get; set; } = DefaultVisibleSeconds;
|
||||
|
||||
@@ -66,6 +75,12 @@ public sealed class MixVisualizerControlState
|
||||
/// <summary>Gradient-morph rate, normalized [0,1]. Inert until Wave 3 consumes the uniform.</summary>
|
||||
public double ColorShiftSpeed { get; set; } = DefaultColorShiftSpeed;
|
||||
|
||||
/// <summary>
|
||||
/// 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).
|
||||
/// </summary>
|
||||
public double WaveformWidth { get; set; } = DefaultWaveformWidth;
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
|
||||
Reference in New Issue
Block a user