docs(visualizer): fix five inaccurate comments — sub-unity restitution, uniform heat boost, progressive push-out, scroll-speed cross-ref, eight-knob bar

This commit is contained in:
daniel-c-harvey
2026-06-17 05:20:12 -04:00
parent 4e34696719
commit d36aea212c
3 changed files with 13 additions and 11 deletions
@@ -59,7 +59,7 @@ public partial class MixWaveformVisualizer : ComponentBase, IAsyncDisposable
// `[MixVisualizer]`, same as the JS logs so the two interleave into one timeline). These pinpoint // `[MixVisualizer]`, same as the JS logs so the two interleave into one timeline). These pinpoint
// which upstream link is broken when the ribbon stays blank — set false once confirmed healthy. // which upstream link is broken when the ribbon stays blank — set false once confirmed healthy.
// ON for the Phase 10 reframe Wave R4 controls test (matches the JS-side DEBUG in // ON for the Phase 10 reframe Wave R4 controls test (matches the JS-side DEBUG in
// MixVisualizer.ts). Daniel evaluates the seven-knob bar + pause behavior in-browser; flip back to // MixVisualizer.ts). Daniel evaluates the eight-knob bar + pause behavior in-browser; flip back to
// false at reframe close along with the JS flag. // false at reframe close along with the JS flag.
private static readonly bool Debug = true; private static readonly bool Debug = true;
private const string Tag = "[MixVisualizer]"; private const string Tag = "[MixVisualizer]";
@@ -30,9 +30,10 @@ public sealed class MixVisualizerControlState
// sweet spot (§4c). // sweet spot (§4c).
/// <summary> /// <summary>
/// Default scroll-speed dial. Mirrors <c>DEFAULT_SCROLL_SPEED</c> in MixVisualizer.ts. Normalized /// Default scroll-speed dial. Normalized [0,1] → mapped C#-side to a visible time-span in seconds
/// [0,1] → mapped to the visible time-span via <see cref="MixZoomMapping"/> (0 = slow/wide window, /// via <see cref="MixZoomMapping"/>, then sent to MixVisualizer.ts as a seconds value via
/// 1 = fast/tight window). Opens mid-range. /// <c>setScrollSpeed</c>. The TS-side anchor is <c>DEFAULT_VISIBLE_SECONDS</c>. Opens mid-range
/// (0 = slow/wide window, 1 = fast/tight window).
/// </summary> /// </summary>
public const double DefaultScrollSpeed = 0.5; public const double DefaultScrollSpeed = 0.5;
@@ -1426,9 +1426,9 @@ export function create(canvas: HTMLCanvasElement): MixVisualizerHandle {
* toe) keeps the low end gentle so small dial moves near 0 don't suddenly erupt. */ * toe) keeps the low end gentle so small dial moves near 0 don't suddenly erupt. */
function heatScaleFromDial(dial: number): number { function heatScaleFromDial(dial: number): number {
const d = Math.min(Math.max(dial, 0), 1); const d = Math.min(Math.max(dial, 0), 1);
// Smoothstep toe (gentle at 0) scaled to reach 1.2 at dial 1 — Phase 10 §3.4: ~20% stronger // Smoothstep toe (gentle at 0) scaled by 1.2 — Phase 10 §3.4: uniform +20% across the curve
// at the high end so full heat roils harder. The low/mid feel is unchanged (the toe dominates // (every non-zero dial position is raised by 20%; the shape of the toe is preserved but the
// there); only the top end gains the extra 20% drive into the floor-heating + buoyancy + turbulence. // overall output is higher at every point).
return d * d * (3 - 2 * d) * 1.2; return d * d * (3 - 2 * d) * 1.2;
} }
@@ -1601,7 +1601,8 @@ export function create(canvas: HTMLCanvasElement): MixVisualizerHandle {
b.vx += sideSign * WAVE_COLLIDE_SPRING * penetration * dt * (1 - collideHardness); b.vx += sideSign * WAVE_COLLIDE_SPRING * penetration * dt * (1 - collideHardness);
// Hard elastic reflection (hard end): bounce the inward velocity back out, scaled // Hard elastic reflection (hard end): bounce the inward velocity back out, scaled
// by restitution × hardness (over-unity restitution at the top = the springy throw). // by restitution × hardness. Restitution is sub-unity (≤ 0.85) — bounded reflection,
// no energy added.
if (inwardSpeed > 0) { if (inwardSpeed > 0) {
b.vx += sideSign * inwardSpeed * (1 + waveRest) * collideHardness; b.vx += sideSign * inwardSpeed * (1 + waveRest) * collideHardness;
} }
@@ -1613,9 +1614,9 @@ export function create(canvas: HTMLCanvasElement): MixVisualizerHandle {
const throwUp = Math.min(WAVE_THROW_UP * penetration * dt * collideHardness, WAVE_THROW_UP_MAX); const throwUp = Math.min(WAVE_THROW_UP * penetration * dt * collideHardness, WAVE_THROW_UP_MAX);
b.vy -= throwUp; b.vy -= throwUp;
// Positional push-out: always eject the wax fully out of the ribbon along the normal so // Positional push-out: ejects the wax progressively out of the ribbon along the normal
// it can never lodge inside (Daniel "gets stuck"). The soft end eases it out gently // (converges across substeps, so no stuck wax). The soft end eases it out gently
// (mushy), the hard end snaps it clean — but both clear the boundary, so no stuck wax. // (mushy), the hard end snaps it clean.
b.x += sideSign * penetration * (0.5 + 0.5 * collideHardness); b.x += sideSign * penetration * (0.5 + 0.5 * collideHardness);
} }