feat(mix-visualizer): Phase 10 tuning — smooth waveform, bouncy collision, 8 knobs
Smooth the loudness contour (~50 ms envelope at preprocessing + decode-time, plus smootherstep render reconstruction); retune wax↔waveform collision to bouncy/sub-unity (no explosion/stuck/jitter); split the bubbles knob into fluid-amount + fluid-viscosity (cohesion via uniform-only smin/wobble); retune scroll/gravity/heat/width ranges; make the colour rotation visible and boost OKLab chroma; the controls bar now holds its layout and hides only its knobs via a Visible parameter.
This commit is contained in:
@@ -1,17 +1,18 @@
|
||||
namespace DeepDrftPublic.Client.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Holds the Mix visualizer's seven continuous-control positions for the lifetime of the WASM app
|
||||
/// Holds the Mix visualizer's eight 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 knobs 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 (lava reframe §7c).
|
||||
///
|
||||
/// One state object, seven properties — not seven sibling holders, and (deliberately) NO constructor
|
||||
/// parameters: this is a plain scoped value holder, so widening it from four to seven properties adds
|
||||
/// fields + defaults only and never forces a consumer constructor to grow. Each C#-side default mirrors
|
||||
/// a TS-side tuning anchor in MixVisualizer.ts; keep the two in sync, as the existing
|
||||
/// <c>DefaultVisibleSeconds</c> / <c>DEFAULT_VISIBLE_SECONDS</c> pair does.
|
||||
/// One state object, eight properties — not eight sibling holders, and (deliberately) NO constructor
|
||||
/// parameters: this is a plain scoped value holder, so widening it (the Phase 10 split of the single
|
||||
/// density knob into fluid-amount + fluid-viscosity) adds fields + defaults only and never forces a
|
||||
/// consumer constructor to grow. Each C#-side default mirrors a TS-side tuning anchor in
|
||||
/// MixVisualizer.ts; keep the two in sync, as the <c>DefaultVisibleSeconds</c> /
|
||||
/// <c>DEFAULT_VISIBLE_SECONDS</c> pair does.
|
||||
///
|
||||
/// <para>
|
||||
/// <see cref="Changed"/> is the decoupling seam between the controls bar and the visualizer bridge.
|
||||
@@ -23,8 +24,8 @@ namespace DeepDrftPublic.Client.Services;
|
||||
/// </summary>
|
||||
public sealed class MixVisualizerControlState
|
||||
{
|
||||
// ── The seven control defaults (lava reframe §7a). Each mirrors a DEFAULT_* anchor in
|
||||
// MixVisualizer.ts; keep the two in sync, as the existing default-sync discipline requires.
|
||||
// ── The eight control defaults (Phase 10). Each mirrors a DEFAULT_* anchor in
|
||||
// MixVisualizer.ts; keep the two in sync, as the default-sync discipline requires.
|
||||
// Feel-anchors only — Daniel tunes on screen; the ~20% gravity / ~100% heat pair is his stated
|
||||
// sweet spot (§4c).
|
||||
|
||||
@@ -37,10 +38,10 @@ public sealed class MixVisualizerControlState
|
||||
|
||||
/// <summary>
|
||||
/// Default gradient-rotation-speed dial. Mirrors <c>DEFAULT_GRADIENT_ROTATION_SPEED</c> in
|
||||
/// MixVisualizer.ts. Normalized [0,1] → slow→fast anchor-rotation. INERT until Wave R3 builds the
|
||||
/// OKLab three-colour gradient that consumes it.
|
||||
/// MixVisualizer.ts. Normalized [0,1] → slow→fast anchor-rotation; drives the live OKLab
|
||||
/// three-colour gradient. 0.45 opens with a clearly-visible ~7 s colour cycle (Phase 10 §3.2).
|
||||
/// </summary>
|
||||
public const double DefaultGradientRotationSpeed = 0.3;
|
||||
public const double DefaultGradientRotationSpeed = 0.45;
|
||||
|
||||
/// <summary>
|
||||
/// Default lava-gravity dial. Mirrors <c>DEFAULT_LAVA_GRAVITY</c> in MixVisualizer.ts. Normalized
|
||||
@@ -56,10 +57,18 @@ public sealed class MixVisualizerControlState
|
||||
public const double DefaultLavaHeat = 1.0;
|
||||
|
||||
/// <summary>
|
||||
/// Default blob-density dial. Mirrors <c>DEFAULT_BLOB_DENSITY</c> in MixVisualizer.ts. Normalized
|
||||
/// [0,1]; 0 = a few large lazy blobs, 1 = many smaller active blobs.
|
||||
/// Default fluid-amount dial. Mirrors <c>DEFAULT_FLUID_AMOUNT</c> in MixVisualizer.ts. The first
|
||||
/// half of the Phase 10 "bubbles" split. Normalized [0,1]; 0 = few small blobs, 1 = many larger
|
||||
/// blobs (more wax in the container — blob count + per-blob volume).
|
||||
/// </summary>
|
||||
public const double DefaultBlobDensity = 0.4;
|
||||
public const double DefaultFluidAmount = 0.4;
|
||||
|
||||
/// <summary>
|
||||
/// Default fluid-viscosity / cohesion dial. Mirrors <c>DEFAULT_FLUID_VISCOSITY</c> in
|
||||
/// MixVisualizer.ts. The second half of the Phase 10 "bubbles" split. Normalized [0,1]; 1 = high
|
||||
/// cohesion (crisp spheres that snap back), 0 = low cohesion (deforms freely, stays gooey/merged).
|
||||
/// </summary>
|
||||
public const double DefaultFluidViscosity = 0.6;
|
||||
|
||||
/// <summary>
|
||||
/// Default collision-strength dial. Mirrors <c>DEFAULT_COLLISION_STRENGTH</c> in MixVisualizer.ts.
|
||||
@@ -69,15 +78,16 @@ public sealed class MixVisualizerControlState
|
||||
|
||||
/// <summary>
|
||||
/// Default waveform-width dial. Mirrors <c>DEFAULT_WAVEFORM_WIDTH</c> in MixVisualizer.ts.
|
||||
/// Normalized [0,1]; 1 = full ribbon width, lower narrows the band so the lava gets more room.
|
||||
/// Normalized [0,1], mapped onto the useful 10%–95% ribbon-extent band (Phase 10 §3.7); 0.5 opens
|
||||
/// mid-band. Narrowing clears room for the lava.
|
||||
/// </summary>
|
||||
public const double DefaultWaveformWidth = 0.6;
|
||||
public const double DefaultWaveformWidth = 0.5;
|
||||
|
||||
/// <summary>Apparent bottom-to-top scroll rate, normalized [0,1]. Bridge maps it to a visible
|
||||
/// time-span via <see cref="MixZoomMapping"/>; the standalone resolution/zoom control is gone.</summary>
|
||||
public double ScrollSpeed { get; set; } = DefaultScrollSpeed;
|
||||
|
||||
/// <summary>Gradient anchor-rotation rate, normalized [0,1]. Inert until Wave R3 consumes it.</summary>
|
||||
/// <summary>Gradient anchor-rotation rate, normalized [0,1]. Drives the live OKLab gradient.</summary>
|
||||
public double GradientRotationSpeed { get; set; } = DefaultGradientRotationSpeed;
|
||||
|
||||
/// <summary>Downward force on the wax, normalized [0,1].</summary>
|
||||
@@ -86,8 +96,12 @@ public sealed class MixVisualizerControlState
|
||||
/// <summary>Energy into the lava system, normalized [0,1]. 0 = rest-at-bottom, 1 = roiling.</summary>
|
||||
public double LavaHeat { get; set; } = DefaultLavaHeat;
|
||||
|
||||
/// <summary>Amount of wax (blob count/size), normalized [0,1].</summary>
|
||||
public double BlobDensity { get; set; } = DefaultBlobDensity;
|
||||
/// <summary>Amount of wax (blob count + per-blob volume), normalized [0,1]. Phase 10 split, part 1.</summary>
|
||||
public double FluidAmount { get; set; } = DefaultFluidAmount;
|
||||
|
||||
/// <summary>Fluid viscosity / cohesion, normalized [0,1]. 1 = crisp spheres, 0 = gooey/deformed.
|
||||
/// Phase 10 split, part 2.</summary>
|
||||
public double FluidViscosity { get; set; } = DefaultFluidViscosity;
|
||||
|
||||
/// <summary>Collision hardness, normalized [0,1]. 0 = soft mush, 1 = hard up-and-out throw.</summary>
|
||||
public double CollisionStrength { get; set; } = DefaultCollisionStrength;
|
||||
|
||||
Reference in New Issue
Block a user