docs(phase-10-reframe): fold Wave R2 eval into lava spec + PLAN (7th control, flat coalescing fluid, up-and-out collision)
This commit is contained in:
@@ -207,15 +207,17 @@ A **major reframe of the Mix visualizer's effects, controls, and color model**,
|
||||
**This supersedes the original Phase 10 (Waves 1–4) effects/controls/color design** — `product-notes/mix-visualizer-webgl-renderer.md` §4 (effects) and §7 (popover-controls) are marked superseded with a pointer to the reframe spec. The renderer *infrastructure* carries forward unchanged.
|
||||
|
||||
**The three reframes:**
|
||||
- **Lava → CPU-physics wax blobs.** Keep the single-pass WebGL2 fragment renderer; add a small CPU-side per-frame physics step modeling ~16–32 Lagrangian "wax blobs" (position/velocity/temperature/radius) uploaded as uniforms and blended with `smin` SDF metaballs. The waveform and lava share **the same plane WITH real 2D elastic collision** (blob↔waveform-boundary + blob↔blob) — the waveform pushes the fluid out of its way (read-only authority preserved; the fluid never deforms the waveform). At heat 0 the wax rests at the bottom and only collision moves it (collision always on, independent of heat); at heat max many bubbles rise/morph per second. **Rejected: a full ping-pong FBO Navier-Stokes fluid sim** — a lava lamp is high-viscosity/low-turbulence, the opposite regime; large rewrite for unwanted realism. Deliberate later upgrade only.
|
||||
- **Lava → CPU-physics wax blobs.** Keep the single-pass WebGL2 fragment renderer; add a small CPU-side per-frame physics step modeling ~16–32 Lagrangian "wax blobs" (position/velocity/temperature/radius) uploaded as uniforms and blended with `smin` SDF metaballs. The waveform and lava share **the same plane WITH real 2D elastic collision** (blob↔waveform-boundary + blob↔blob) — the waveform pushes the fluid out of its way (read-only authority preserved; the fluid never deforms the waveform). **Refined by Daniel's Wave R2 eval:** the fluid must read **flat** (an evenly-lit unified body, NOT blobs with bright pointed centers / cone-like radial gradients) and **melt into one fluid** (low viscosity / strong coalescence — "behave more like a fluid," not stiff globs in contact; the slow wax-like *motion* damping and the freely-coalescing *surface* are independent). **Energy-coupled dynamics:** higher heat/energy → **smaller bubbles + more turbulence** (many small lively turbulent bubbles at high heat; fewer, larger, calmer wax at low heat) — the lamp should feel dynamic and fun. At heat 0 the wax rests on the floor and only collision moves it (collision always on, independent of heat); at heat max many small turbulent bubbles rise/morph per second. **Tuning anchor: Daniel's sweet spot is ~20% gravity / ~100% heat** — calibrate defaults/ranges so that combination lands lively. **Rejected: a full ping-pong FBO Navier-Stokes fluid sim** — a lava lamp is high-viscosity/low-turbulence, the opposite regime; large rewrite for unwanted realism. Deliberate later upgrade only.
|
||||
- **Color → three-color OKLab gradient with three motions.** One source of truth (`DeepDrftPalettes`), no hardcoded hexes. Always A→B linear from the center line outward. Three combined motions: (1) anchors A/B **rotate among three theme colors X/Y/Z** at the rotation-speed control's rate — **OKLab interpolation, never through the rainbow** (the cyan fix is structural, not a tuning dial); (2) per-bar sinusoidal variation **baked at segment entry and fixed as the segment scrolls** — realized by **keying the sinusoid to mix-time** so it travels with the segment by construction (decided 2026-06-16; the explicit ring-buffer alternative is rejected for maintainability); (3) per-bar gradient curve shifts with scroll height (mostly A at bottom → mostly B at top). The static noise/frost texture is **removed** (Daniel: makes the screen look dirty).
|
||||
- **Controls → six knobs in an inline collapse/expand knob-bar.** Replaces the four: (1) waveform scroll speed [replaces resolution/zoom as a standalone control], (2) gradient rotation speed, (3) lava gravity, (4) lava heat, (5) blob density/size, (6) collision strength (soft→hard). **NOT a popover or drawer — an inline collapse/expand knob-bar** (decided 2026-06-16): an `@if`-guarded **animated flex row of the six `RadialKnob`s** living inline in the controls area, expanding/collapsing **in place** (CSS width/opacity/transform transition) so it reads as the controls collapsing/expanding, not a floating surface. The lava-lamp icon button toggles a bound bool — no MudPopover/MudDrawer. Styled to **match the NowPlaying hero aesthetic** (the session-detail hero overlay — translucent dark glass, overlay-label typography, `Color.Secondary`). Also: overflow-clip the visualizer to the **dynamic footer height** (the player bar changes height minimized/expanded) so visuals stop cleanly above it; the clip line is also the lava rest line.
|
||||
- **Controls → seven knobs in an inline collapse/expand knob-bar.** Replaces the four: (1) waveform scroll speed [replaces resolution/zoom as a standalone control], (2) gradient rotation speed, (3) lava gravity, (4) lava heat, (5) blob density/size, (6) collision strength (soft mush→hard up-and-out throw), (7) **waveform width** [added in the Wave R2 eval — narrows the waveform band so the lava fluid has more room to move on loud/busy songs; scales the waveform's amplitude→width mapping and its collision boundary]. **NOT a popover or drawer — an inline collapse/expand knob-bar** (decided 2026-06-16): an `@if`-guarded **animated flex row of the seven `RadialKnob`s** living inline in the controls area, expanding/collapsing **in place** (CSS width/opacity/transform transition) so it reads as the controls collapsing/expanding, not a floating surface. The lava-lamp icon button toggles a bound bool — no MudPopover/MudDrawer. Styled to **match the NowPlaying hero aesthetic** (the session-detail hero overlay — translucent dark glass, overlay-label typography, `Color.Secondary`). Also: overflow-clip the visualizer to the **dynamic footer height** (the player bar changes height minimized/expanded) so visuals stop cleanly above it; the clip line is also the lava rest line.
|
||||
|
||||
**Plus: redraw the lava-lamp glyph.** The current `DDIcons.LavaLamp` is rejected (Daniel: "form is shit, colors are shit"). Redraw to the classic 1970s silhouette — a wide truncated-cone metal **base**, a bulbous→roundedly-pointed teardrop **glass body**, a small cone **cap** ("offset cones") — with **navy fluid + moss blobs** (the theme's blue+green, faithful to the reference and on-theme) and a neutral/metallic base+cap. Authored in `DeepDrftShared.Client/Common/DDIcons.cs` as inner SVG markup (no `<svg>` wrapper; 24×24 viewBox); body silhouette `currentColor`, the two accent fills are commented literals traced to their `DeepDrftPalettes` source (SVG cannot resolve `var()`).
|
||||
|
||||
Heat→intensity and collision soft↔hard transfer functions are **staff-engineer tuning tasks** (endpoints fixed in the spec, formulas not). Full design, the wax-blob model, the collision model, the three-motion color model, the inline knob-bar, the icon redraw, observable acceptance criteria, and phasing: `product-notes/phase-10-mix-visualizer-lava-reframe.md`.
|
||||
Heat→intensity and collision soft↔hard transfer functions are **staff-engineer tuning tasks** (endpoints fixed in the spec — heat 0 = wax rests on floor / heat max = many small turbulent rising bubbles; collision soft = gentle mush / hard = high-elasticity up-and-out throw, wide range, smooth/no jitter — formulas not). Full design, the wax-blob model, the collision model, the three-motion color model, the inline knob-bar, the icon redraw, observable acceptance criteria, and phasing: `product-notes/phase-10-mix-visualizer-lava-reframe.md`.
|
||||
|
||||
**Sequenced as four reframe waves.** `Wave R1 → Wave R2 → (Wave R3 ‖ Wave R4)`. Wave R1 (de-noise + dynamic footer clip + icon redraw) is a cheap unblock for a clean substrate. Wave R2 (wax-blob physics + 2D collision) is the load-bearing prerequisite — prove the lava before the color and the UI. Wave R3 (OKLab three-color gradient, the three motions) and Wave R4 (six controls + NowPlaying-styled inline knob-bar + widened state to six properties + extended bridge handle) both depend on Wave R2 but are independent of each other. **Both prior open Daniel calls are now decided:** controls-UI is an inline collapse/expand knob-bar (not popover/drawer); per-segment color is mix-time-keyed.
|
||||
**Open / undecided (spec §10):** (a) **pause behavior** — whether the lava keeps convecting while audio is *paused* (lamp "always on") vs. the current freeze-on-pause (rAF gated on `isPlaying`) is an **undecided Daniel call**; default to freeze-on-pause until decided, switching is a localized gating change, not a model change. (b) **Future enhancement (deferred, NOT in R1–R4 scope):** a per-control **"auto-modulate" checkbox** that slowly oscillates each knob's value via a low-frequency oscillator so the visualizer drifts on its own — Daniel flagged it as a cool future idea; the knob-bar layout leaves room but nothing builds it now.
|
||||
|
||||
**Sequenced as four reframe waves.** `Wave R1 → Wave R2 → (Wave R3 ‖ Wave R4)`. Wave R1 (de-noise + dynamic footer clip + icon redraw) is a cheap unblock for a clean substrate. Wave R2 (wax-blob physics + 2D collision) is the load-bearing prerequisite — prove the lava before the color and the UI. Wave R3 (OKLab three-color gradient, the three motions) and Wave R4 (seven controls — including the new waveform-width knob — + NowPlaying-styled inline knob-bar + widened state to seven properties + extended bridge handle) both depend on Wave R2 but are independent of each other. **Both prior open Daniel calls are now decided:** controls-UI is an inline collapse/expand knob-bar (not popover/drawer); per-segment color is mix-time-keyed.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ This spec **supersedes** the original Phase 10 effects/controls/color design:
|
||||
- `product-notes/mix-visualizer-webgl-renderer.md` **§4 (the four visual effects)** — superseded by
|
||||
§3–§6 here.
|
||||
- `product-notes/mix-visualizer-webgl-renderer.md` **§7 (Wave 4 popover-controls rework)** — superseded
|
||||
by §7 here (the trigger and the widened body are kept; the four-knob popover becomes a six-knob
|
||||
by §7 here (the trigger and the widened body are kept; the four-knob popover becomes a seven-knob
|
||||
inline collapse/expand knob-bar — see §7).
|
||||
|
||||
What carries forward unchanged from Phase 10's landed waves (do **not** re-derive — reference it):
|
||||
@@ -60,9 +60,9 @@ Cross-references (read these before implementing):
|
||||
geometry, the datum texture, and the playhead machinery are reused; the §4-effect GLSL (the bubble
|
||||
SDF, the detach blobs, the HSL `mixHsl`/`vivify` color, the glass) is the part being replaced.
|
||||
- `DeepDrftPublic.Client/Controls/MixVisualizerControls.razor[.cs]` — the four-knob control component;
|
||||
becomes six knobs in an inline collapse/expand bar (§7).
|
||||
becomes seven knobs in an inline collapse/expand bar (§7).
|
||||
- `DeepDrftPublic.Client/Services/MixVisualizerControlState.cs` — the scoped four-property state holder;
|
||||
widens to six properties (§7c).
|
||||
widens to seven properties (§7c).
|
||||
- `DeepDrftPublic.Client/Controls/MixZoomMapping.cs` — reused unchanged for the scroll-speed control.
|
||||
- `DeepDrftPublic.Client/Controls/MixWaveformVisualizer.razor[.cs/.css]` — the bridge. Extend the handle
|
||||
with the new control setters; the `.css` gains the overflow-clip work (§2).
|
||||
@@ -85,7 +85,7 @@ Cross-references (read these before implementing):
|
||||
metaballs in the existing fragment shader, sharing the *same plane* as the waveform **with real 2D
|
||||
collision** — the waveform pushes the fluid out of its way. Replace the navy↔moss treatment with a
|
||||
**three-color, OKLab-interpolated, per-segment-baked gradient** that animates along three combined
|
||||
motions. Replace the four-knob popover with a **six-knob inline collapse/expand knob-bar** styled to
|
||||
motions. Replace the four-knob popover with a **seven-knob inline collapse/expand knob-bar** styled to
|
||||
match the hero NowPlaying aesthetic. Remove the static noise texture that makes the screen look dirty.
|
||||
Redraw the lava-lamp trigger glyph to the classic 1970s silhouette (§7f).
|
||||
|
||||
@@ -98,8 +98,8 @@ Redraw the lava-lamp trigger glyph to the classic 1970s silhouette (§7f).
|
||||
- The **three-color OKLab gradient model** with three combined motions: anchor rotation among X/Y/Z,
|
||||
per-segment sinusoidal variation baked at segment entry, and the per-bar curve shift with scroll
|
||||
height (§6).
|
||||
- **Six controls** replacing the four: scroll speed, gradient rotation speed, lava gravity, lava heat,
|
||||
blob density/size, collision strength (§7).
|
||||
- **Seven controls** replacing the four: scroll speed, gradient rotation speed, lava gravity, lava heat,
|
||||
blob density/size, collision strength, waveform width (§7).
|
||||
- The **inline collapse/expand knob-bar** (replacing the popover) styled to the NowPlaying hero
|
||||
aesthetic (§7).
|
||||
- A **redrawn `DDIcons.LavaLamp`** glyph — classic 1970s lava-lamp silhouette (§7f).
|
||||
@@ -133,7 +133,7 @@ Redraw the lava-lamp trigger glyph to the classic 1970s silhouette (§7f).
|
||||
| Color model (HSL navy↔moss) | — | OKLab three-color gradient, 3 motions (§6) |
|
||||
| Glass treatment | — | folded into the blob shading (§4f); no separate glass dials |
|
||||
| Static noise/frost texture | — | **removed** (§3) |
|
||||
| Controls (4 knobs, popover) | — | 6 knobs in an inline collapse/expand bar (§7) |
|
||||
| Controls (4 knobs, popover) | — | 7 knobs in an inline collapse/expand bar (§7) |
|
||||
| Lava-lamp trigger glyph | trigger placement kept | glyph **redrawn** (§7f) |
|
||||
|
||||
---
|
||||
@@ -236,6 +236,23 @@ This fixes "giant disconnected circles": the prior approach had too few scripted
|
||||
= 6`) with hash-driven pseudo-motion and no physics, so they read as detached discs. Real physics on
|
||||
16–32 blobs with `smin` merging reads as continuous wax that splits and recombines.
|
||||
|
||||
**The fluid must read FLAT, and the blobs must melt into one unified fluid (from Daniel's Wave R2 eval).**
|
||||
Two refinements to the rendered result, both load-bearing:
|
||||
|
||||
- **Flat fluid surface, not bright pointed centers.** The metaball/fluid surface must read **flat** —
|
||||
an evenly-lit fluid body. It must **NOT** read as blobs with bright pointed centers / cone-like radial
|
||||
gradients (a per-blob radial falloff peaking at each center reads as a field of glowing cones, which
|
||||
Daniel rejected). Shade the *composited* surface, not each blob's center: the brightness should be a
|
||||
property of the unified fluid's surface (normal/Fresnel from the SDF, §4f), flat across the body, not a
|
||||
per-blob hotspot.
|
||||
- **Melt into one fluid — low viscosity, strong coalescence.** The blobs must **coalesce into a single
|
||||
unified fluid** rather than reading as distinct stiff globs that merely touch. Bias the `smin` blend
|
||||
radius wide and the inter-blob cohesion high so overlapping/near blobs **melt together** into one
|
||||
continuous body — "behave more like a fluid," not like rigid beads in contact. This trades against the
|
||||
earlier "high-viscosity wax, not water" damping note (§4a integration): keep the *motion* viscous and
|
||||
slow, but make the *surface* coalesce freely. The damping is on velocity (slow, wax-like movement); the
|
||||
coalescence is on the surface field (fluid, unified). They are independent.
|
||||
|
||||
### 4b. Blob shape — varied, organic, not always circular
|
||||
|
||||
Blobs range **~20px to ~100px** across and are **not always circular** — they should read as varied,
|
||||
@@ -253,10 +270,31 @@ wax," not "N identical circles."
|
||||
**always on, independent of heat** (§5).
|
||||
- At **heat = max**, **many bubbles rise and morph per second** — a busy, actively roiling lamp.
|
||||
|
||||
The mapping from the 0..1 heat scalar to effect intensity (rise rate, how many blobs are buoyant at
|
||||
once, churn frequency) is a **well-tuned transfer function that staff-engineer owns** — this spec does
|
||||
not fix a formula. Note it as a tuning task: the requirement is the *endpoints* (0 = rest-at-bottom,
|
||||
collision-only; max = many rising/morphing per second) and a smooth, good-feeling sweep between them.
|
||||
**Energy-coupled dynamics (from Daniel's Wave R2 eval) — heat changes the *character* of the wax, not
|
||||
just the rise rate.** Higher heat/energy → **smaller bubbles + more turbulence**; lower heat → **fewer,
|
||||
larger, calmer wax**. Concretely:
|
||||
|
||||
- **High heat:** lots of **small, lively, turbulent bubbles** — the wax fragments into many small active
|
||||
blobs with visible churn/turbulence. Energetic and busy.
|
||||
- **Low heat:** **fewer, larger, calmer** masses — big lazy wax that mostly rests and drifts.
|
||||
|
||||
So heat couples to *both* buoyancy (rise) *and* the effective blob size/count distribution and the
|
||||
turbulence in the velocity field. (This interacts with the blob density/size control, §4e — heat shifts
|
||||
the wax toward the small-and-many end of whatever the density control sets.) **The visualizer should feel
|
||||
dynamic and fun** — heat is the "liveliness" axis, and the whole point is that turning it up makes the
|
||||
lamp visibly come alive, not merely rise faster.
|
||||
|
||||
The mapping from the 0..1 heat scalar to effect intensity (rise rate, bubble size/count split, churn
|
||||
frequency, turbulence) is a **well-tuned transfer function that staff-engineer owns** — this spec does
|
||||
not fix a formula. Note it as a tuning task: the requirement is the *endpoints* (0 = wax rests on the
|
||||
floor, collision-only; max = many small turbulent rising bubbles) and a smooth, good-feeling, dynamic
|
||||
sweep between them.
|
||||
|
||||
**Tuning reference — Daniel's sweet spot is ~20% gravity / ~100% heat.** Calibrate the defaults and the
|
||||
transfer-function ranges so that this combination lands in a great-feeling, lively state (it is the
|
||||
target the small-turbulent-bubble behavior above is described against). Treat ~20% gravity / ~100% heat
|
||||
as the calibration anchor for where "dynamic and fun" should sit; the ranges should make that reachable
|
||||
and good, not extreme.
|
||||
|
||||
### 4d. Gravity control
|
||||
|
||||
@@ -320,6 +358,16 @@ is a separate phase, not a tuning step.
|
||||
Mass can be derived from radius (bigger blob = more mass) so large blobs shove small ones convincingly —
|
||||
staff-engineer's call; the requirement is *elastic 2D collision on both pairs.*
|
||||
|
||||
**High elasticity, and the throw is UP AND OUT, not just sideways (from Daniel's Wave R2 eval).** The
|
||||
collision is **highly elastic** at the hard end. Critically, when the waveform collides with the wax at
|
||||
high collision strength it must **throw the bubbles UPWARD AND OUTWARD** — the waveform surface impulse
|
||||
has a vertical (lift) component, not merely horizontal displacement. The earlier "pushed out along the
|
||||
waveform's surface normal" framing is too flat: the desired read is the waveform *kicking* the fluid up
|
||||
and away, like a paddle slapping liquid, so the lava springs off it. Staff-engineer composes the impulse
|
||||
so a hard collision imparts both outward (normal) and upward (lift) velocity to the struck blobs.
|
||||
**Collision must be smooth — no jitter** (no per-frame popping/vibration at the boundary; the response
|
||||
must integrate stably even at high elasticity).
|
||||
|
||||
### 5b. Collision always on, independent of heat
|
||||
|
||||
Per §4c: the waveform↔lava collision runs **at all heat levels, including heat = 0.** At rest the
|
||||
@@ -328,18 +376,24 @@ lava feeling like one physical system rather than two layers.
|
||||
|
||||
### 5c. Collision strength — soft → hard (the sixth control)
|
||||
|
||||
A **collision strength** control sweeps the interaction from **soft → 100% hard.** It blends between two
|
||||
behaviors:
|
||||
A **collision strength** control sweeps the interaction from **genuinely soft → 100% hard** across a
|
||||
**wide soft↔hard range** (from Daniel's Wave R2 eval — the soft end must be genuinely soft, not a faint
|
||||
version of hard, and the spread between the two ends should be large and expressive). It blends between
|
||||
two behaviors:
|
||||
|
||||
- **(a) Hard obstacle:** the waveform is a rigid wall the fluid flows around — full elastic reflection,
|
||||
blobs cannot enter the silhouette at all.
|
||||
- **(b) Soft displacement/shove:** the waveform gently pushes the fluid aside — a soft penalty force
|
||||
proportional to penetration depth, blobs squish against and partially into the boundary before being
|
||||
eased out.
|
||||
- **(a) Hard / high-elasticity throw:** the waveform is a near-rigid surface that **throws the wax UP AND
|
||||
OUT** — high restitution, the struck blobs spring off the boundary with both outward (normal) and
|
||||
upward (lift) velocity (§5a). At max it reads as the waveform energetically kicking the lava off it.
|
||||
- **(b) Soft mush:** the waveform gently **mushes** the lava around — a soft penalty force proportional to
|
||||
penetration depth, the wax squishes against and partially into the boundary and slowly eases back, with
|
||||
little or no springy throw. At/near min it must be **genuinely soft** — the fluid yields and gently
|
||||
deforms, no kick.
|
||||
|
||||
The knob blends (b) → (a) as it sweeps 0 → 1. At 0 it is a gentle shove (the fluid yields and slowly
|
||||
recovers); at 1 it is a hard wall (crisp reflection, no penetration). The same blend factor can scale the
|
||||
blob↔blob restitution for consistency (softer overall world at low strength), staff-engineer's call.
|
||||
The knob blends (b) → (a) as it sweeps 0 → 1: at 0, gentle mushing of the lava (soft, yielding, slow
|
||||
recovery); at 1, a high-elasticity up-and-out throw. The range must be **wide** so the difference between
|
||||
ends is dramatic, and the sweep must stay **smooth with no jitter** at any setting (§5a). The same blend
|
||||
factor can scale the blob↔blob restitution for consistency (softer overall world at low strength),
|
||||
staff-engineer's call.
|
||||
|
||||
> **Dropped:** the earlier Phase 10 "bubbles spawn from peaks" idea is **not relevant** to this model —
|
||||
> blobs are a persistent physical population, not spawned-from-the-waveform particles. Do not carry it
|
||||
@@ -347,9 +401,13 @@ blob↔blob restitution for consistency (softer overall world at low strength),
|
||||
|
||||
### 5d. Transfer functions left to staff-engineer
|
||||
|
||||
As with heat (§4c), the exact penetration-penalty curve, restitution coefficients, and the soft↔hard
|
||||
blend shape are **staff-engineer tuning tasks.** This spec fixes the *model* (two elastic collision
|
||||
pairs, a soft↔hard blend on a knob, collision always on) and the *endpoints*, not the constants.
|
||||
As with heat (§4c), the exact penetration-penalty curve, restitution coefficients, the lift/normal
|
||||
impulse split, and the soft↔hard blend shape are **staff-engineer tuning tasks.** This spec fixes the
|
||||
*model* (two elastic collision pairs, a wide soft↔hard blend on a knob, collision always on, smooth/no
|
||||
jitter) and the *endpoints* (soft = gentle mush; hard = high-elasticity up-and-out throw), not the
|
||||
constants. The heat transfer-function endpoints are likewise fixed (heat 0 = wax rests on the floor;
|
||||
heat max = many small turbulent rising bubbles) with the ~20% gravity / ~100% heat sweet spot as the
|
||||
calibration anchor (§4c).
|
||||
|
||||
---
|
||||
|
||||
@@ -442,18 +500,19 @@ OKLab. Drop the `mixHsl` / `vivify` / `VIVID_*` machinery entirely.
|
||||
|
||||
---
|
||||
|
||||
## 7. The six controls + the inline collapse/expand knob-bar
|
||||
## 7. The seven controls + the inline collapse/expand knob-bar
|
||||
|
||||
### 7a. The six controls (replacing the four)
|
||||
### 7a. The seven controls (replacing the four)
|
||||
|
||||
| # | Control | What it drives | Range | Replaces |
|
||||
|---|---------|----------------|-------|----------|
|
||||
| 1 | **Waveform scroll speed** | Apparent bottom-to-top scroll rate (decouples scroll from zoom) | normalized, mapped via `MixZoomMapping` or a new scroll-rate map | the old **resolution/zoom** control — *resolution as a standalone control is gone* |
|
||||
| 2 | **Color gradient rotation speed** | Motion 1 anchor-rotation rate among X/Y/Z (§6b) | normalized 0→1 → slow→fast cycle | the old **color-shift speed** |
|
||||
| 3 | **Lava gravity** | Downward force on the wax (§4d) | normalized 0→1 | new |
|
||||
| 4 | **Lava heat** | Energy into the system; 0 = rest-at-bottom, max = many rising/morphing (§4c) | normalized 0→1 | the old **detach**, re-modeled |
|
||||
| 4 | **Lava heat** | Energy into the system; 0 = rest-at-bottom, max = many small turbulent rising bubbles (§4c) | normalized 0→1 | the old **detach**, re-modeled |
|
||||
| 5 | **Blob density/size** | Amount of wax — count/size within the 16–32 / 20–100px bands (§4e) | normalized 0→1 | new (the old **bubblyness** is gone; bulge is now physical) |
|
||||
| 6 | **Collision strength** | Soft → 100% hard waveform/blob collision (§5c) | normalized 0→1 → soft→hard | new |
|
||||
| 6 | **Collision strength** | Soft mush → 100% hard up-and-out throw, waveform/blob collision (§5c) | normalized 0→1 → soft→hard | new |
|
||||
| 7 | **Waveform width** | Width of the waveform portion of the visualizer — narrows the waveform band so the lava fluid has more room to move (§7a, below) | normalized 0→1 → narrow→wide | new (added in the Wave R2 eval) |
|
||||
|
||||
Note the swap: **resolution/zoom as a standalone control is removed — scroll speed replaces it.** The
|
||||
`MIN_VISIBLE_SECONDS` anchor still exists internally for the datum-density framing, but the user-facing
|
||||
@@ -461,14 +520,24 @@ control is "how fast does it scroll," not "how much do I see." Staff-engineer de
|
||||
speed reuses `MixZoomMapping` (treating it as a scroll-rate map) or gets a fresh linear map; either way
|
||||
keep the log-feel continuity that made the zoom slider feel good.
|
||||
|
||||
**Control 7 — waveform width (added in the Wave R2 eval).** Adjusts the **width of the waveform portion**
|
||||
of the visualizer — i.e. how much horizontal band the symmetric ±amplitude waveform silhouette occupies.
|
||||
**The point of the control:** on loud/busy songs the waveform is wide and crowds the canvas; narrowing it
|
||||
gives the **lava fluid more room to move**. Low = a narrow waveform band (more room for lava); high = a
|
||||
wide waveform band. Mechanically this scales the waveform's amplitude→screen-width mapping (the half-width
|
||||
the silhouette extends from the center line for a given loudness), which also resizes the collision
|
||||
boundary the fluid parts around (§5) — narrowing the waveform literally clears space for the wax. The
|
||||
datum and scroll geometry are unchanged; only the horizontal extent of the waveform band scales.
|
||||
|
||||
Defaults are Daniel's to tune on screen (his standing preference — he tunes ranges by hand once it is
|
||||
live). Recommended starting points: scroll speed ~mid, rotation ~0.3, gravity ~0.5, heat ~0.3, density
|
||||
~0.4, collision ~0.5. These are feel-anchors, not commitments.
|
||||
live). Recommended starting points: scroll speed ~mid, rotation ~0.3, gravity ~0.2, heat ~1.0, density
|
||||
~0.4, collision ~0.5, width ~0.6. The **~20% gravity / ~100% heat** anchor reflects Daniel's stated sweet
|
||||
spot (§4c). These are feel-anchors, not commitments.
|
||||
|
||||
### 7b. The inline collapse/expand knob-bar (decided — NOT a popover or drawer)
|
||||
|
||||
**Decision (Daniel, 2026-06-16): the controls are an inline collapse/expand knob-bar, NOT a floating
|
||||
popover or a drawer.** The six RadialKnobs live **inline in the controls area** (where the controls sit
|
||||
popover or a drawer.** The seven RadialKnobs live **inline in the controls area** (where the controls sit
|
||||
today) as an **`@if`-guarded flex row** that **animates open and closed in place**. It must read as
|
||||
**part of the controls collapsing/expanding** — the knob row expanding out from its predecessor — **not**
|
||||
a separate surface hanging off the icon.
|
||||
@@ -478,9 +547,10 @@ a separate surface hanging off the icon.
|
||||
- A **bound `bool`** (e.g. `_controlsExpanded`) gates the knob row. The **lava-lamp icon button toggles
|
||||
it** — the same `DDIcons.LavaLamp` trigger kept from Phase 10 §7c, now redrawn (§7f), now a
|
||||
collapse/expand toggle instead of a popover anchor.
|
||||
- When toggled open, the flex row of six knobs **animates open** via **CSS transition** — width / opacity
|
||||
- When toggled open, the flex row of seven knobs **animates open** via **CSS transition** — width / opacity
|
||||
/ transform — **expanding out from the icon / its predecessor element**, so it reads as the controls
|
||||
growing in place. When toggled closed it collapses back the same way.
|
||||
growing in place. When toggled closed it collapses back the same way. (Seven knobs is wider than six —
|
||||
see the wrap note below.)
|
||||
- **Animation intent:** a smooth in-place expansion (expand-from-icon / slide-open flex row), reading as
|
||||
one continuous collapse/expand of the controls area — not a panel popping into existence over the page.
|
||||
Use the codebase's existing transition vocabulary (the existing controls/transition CSS) so the motion
|
||||
@@ -491,36 +561,37 @@ a separate surface hanging off the icon.
|
||||
|
||||
**Why this over the Phase 10 popover.** The popover read as a detached panel hanging off the icon; Daniel
|
||||
wants the controls to *be* the controls — collapsing and expanding in place. The inline animated flex row
|
||||
keeps the six knobs in the page's flow, makes the open/close a property of the controls themselves, and
|
||||
keeps the seven knobs in the page's flow, makes the open/close a property of the controls themselves, and
|
||||
avoids the popover/drawer overlay machinery entirely. (Prior-art touchstone: an inline "expand for
|
||||
advanced settings" disclosure row — e.g. a toolbar that grows a secondary row of controls in place —
|
||||
rather than a flyout/menu.)
|
||||
|
||||
**Layout note.** Six knobs in a flex row may wrap on narrow viewports (2×3 / 3×2) — a layout call, but
|
||||
all six must remain reachable, and the wrap must still read as part of the inline collapse/expand (the
|
||||
whole block grows/shrinks), not as a separate surface.
|
||||
**Layout note.** Seven knobs in a flex row may wrap on narrow viewports (e.g. 4×3 / 3×4 / 2-row) — a
|
||||
layout call, but all seven must remain reachable, and the wrap must still read as part of the inline
|
||||
collapse/expand (the whole block grows/shrinks), not as a separate surface.
|
||||
|
||||
### 7c. State — widen to six properties
|
||||
### 7c. State — widen to seven properties
|
||||
|
||||
Widen `MixVisualizerControlState` from four properties to **six**: `ScrollSpeed` (replacing
|
||||
Widen `MixVisualizerControlState` from four properties to **seven**: `ScrollSpeed` (replacing
|
||||
`VisibleSeconds` as the user-facing axis, or keep `VisibleSeconds` internally and add a `ScrollSpeed`
|
||||
that maps to it — staff-engineer's call), `GradientRotationSpeed` (rename of `ColorShiftSpeed`),
|
||||
`LavaGravity`, `LavaHeat` (re-modeled from `Detach`), `BlobDensity`, `CollisionStrength`. Each with a
|
||||
`const` default mirrored to the TS tuning anchors (keep the C#↔TS default-sync discipline the existing
|
||||
`Default*` consts have). Same scoped-DI persistence model: survives SPA nav within a session, resets on
|
||||
fresh load. Same `Changed` event seam — the bridge subscribes and pushes the affected uniform; the
|
||||
knob-bar component only mutates state and raises `Changed`. **This is the same architecture as today, just
|
||||
six properties instead of four.**
|
||||
`LavaGravity`, `LavaHeat` (re-modeled from `Detach`), `BlobDensity`, `CollisionStrength`, and
|
||||
`WaveformWidth` (the seventh, added in the Wave R2 eval — drives the waveform-band horizontal extent,
|
||||
§7a). Each with a `const` default mirrored to the TS tuning anchors (keep the C#↔TS default-sync
|
||||
discipline the existing `Default*` consts have). Same scoped-DI persistence model: survives SPA nav
|
||||
within a session, resets on fresh load. Same `Changed` event seam — the bridge subscribes and pushes the
|
||||
affected uniform; the knob-bar component only mutates state and raises `Changed`. **This is the same
|
||||
architecture as today, just seven properties instead of four.**
|
||||
|
||||
The bridge handle gains setters for the new controls (`setScrollSpeed`, `setGradientRotationSpeed`,
|
||||
`setLavaGravity`, `setLavaHeat`, `setBlobDensity`, `setCollisionStrength`) — extend, don't redesign,
|
||||
mirroring how Phase 10 §2d extended the handle.
|
||||
`setLavaGravity`, `setLavaHeat`, `setBlobDensity`, `setCollisionStrength`, `setWaveformWidth`) — extend,
|
||||
don't redesign, mirroring how Phase 10 §2d extended the handle.
|
||||
|
||||
### 7d. RadialKnob — consumed unchanged, six instead of four
|
||||
### 7d. RadialKnob — consumed unchanged, seven instead of four
|
||||
|
||||
`RadialKnob` (`DeepDrftShared.Client/Components/RadialKnob.razor`) is consumed as-is (its API is fixed —
|
||||
`Value`/`ValueChanged`/`Min`/`Max`/`Step`/`Label`/`Size`/`Color`/`HoldValue`; no icon slot; `Label` is
|
||||
SVG text). Six knobs in the inline bar, each with an adjacent `MudIcon` caption (the no-icon-slot
|
||||
SVG text). Seven knobs in the inline bar, each with an adjacent `MudIcon` caption (the no-icon-slot
|
||||
constraint from Phase 10 §7e still holds). `HoldValue=false` so they are live. `Step="0.001"` for
|
||||
continuous feel. Suggested Material icons per control (staff-engineer picks final glyphs):
|
||||
|
||||
@@ -532,9 +603,10 @@ continuous feel. Suggested Material icons per control (staff-engineer picks fina
|
||||
| 4. Lava heat | `LocalFireDepartment` / `Whatshot` |
|
||||
| 5. Blob density/size | `BubbleChart` / `Grain` |
|
||||
| 6. Collision strength | `Adjust` / `Compress` |
|
||||
| 7. Waveform width | `WidthNormal` / `SwapHoriz` / `SettingsEthernet` (a horizontal-extent glyph) |
|
||||
|
||||
Six knobs in a row may wrap on narrow viewports (2×3 / 3×2) — a layout call, but all six must remain
|
||||
reachable.
|
||||
Seven knobs in a row may wrap on narrow viewports (4×3 / 3×4 / two rows) — a layout call, but all seven
|
||||
must remain reachable.
|
||||
|
||||
### 7e. Aesthetic target — match the NowPlaying hero
|
||||
|
||||
@@ -629,58 +701,69 @@ convention, and the theme-alignment discipline — not the exact coordinates.)
|
||||
|
||||
**Lava behavior**
|
||||
|
||||
5. **Heat 0 = rest + collision-only.** At heat 0 the wax pools at the rest line and does not rise on its
|
||||
own; the waveform pushing through it still displaces it (collision always on).
|
||||
6. **Heat max = active.** At max heat, many bubbles rise and morph per second — an actively roiling lamp.
|
||||
7. **Blobs.** Blobs read as varied organic wax shapes (not N identical circles), in the ~20–100px range,
|
||||
5. **Heat 0 = rest + collision-only.** At heat 0 the wax rests on the floor (pooled at the rest line) and
|
||||
does not rise on its own; the waveform pushing through it still displaces it (collision always on).
|
||||
6. **Heat max = small turbulent bubbles.** At max heat, the wax breaks into **many small, lively,
|
||||
turbulent bubbles** that rise and morph per second — an actively roiling, fragmented lamp (not a few
|
||||
big masses rising faster). Energy couples to bubble size/count and turbulence, not just rise rate.
|
||||
7. **Flat, unified fluid.** The fluid reads **flat** — an evenly-lit fluid body, **not** blobs with bright
|
||||
pointed centers / cone-like radial gradients. Blobs **melt into one unified fluid** (strong
|
||||
coalescence) rather than distinct stiff globs in contact.
|
||||
8. **Blobs.** Blobs read as varied organic wax shapes (not N identical circles), in the ~20–100px range,
|
||||
merging and splitting via `smin` — no "giant disconnected circles."
|
||||
8. **Gravity** changes settling/rise behavior independently of heat.
|
||||
9. **Blob density/size** changes how much wax is in the system across its range.
|
||||
9. **Gravity** changes settling/rise behavior independently of heat. At the **~20% gravity / ~100% heat**
|
||||
sweet spot the lamp reads dynamic, lively, and fun (the calibration anchor, §4c).
|
||||
10. **Blob density/size** changes how much wax is in the system across its range.
|
||||
|
||||
**Collision**
|
||||
|
||||
10. **Two elastic pairs.** Blob↔waveform and blob↔blob both collide elastically.
|
||||
11. **Collision strength** sweeps soft (fluid yields and recovers) → hard (rigid wall, no penetration)
|
||||
across its range.
|
||||
11. **Two elastic pairs.** Blob↔waveform and blob↔blob both collide elastically.
|
||||
12. **Collision strength — wide soft↔hard sweep.** Sweeps **genuinely soft mush** (the waveform gently
|
||||
pushes the lava around; fluid yields and slowly recovers, no springy kick) → **hard up-and-out throw**
|
||||
(high elasticity; the waveform throws the bubbles **upward and outward**, not just sideways). The
|
||||
range is wide/expressive and the response is **smooth — no jitter** at any setting.
|
||||
|
||||
**Color**
|
||||
|
||||
12. **Three-color OKLab gradient.** A→B linear from center outward; no cyan, no rainbow excursion — the
|
||||
13. **Three-color OKLab gradient.** A→B linear from center outward; no cyan, no rainbow excursion — the
|
||||
blend stays faithful to the theme colors at all rotation phases.
|
||||
13. **Anchor rotation.** A and B rotate among X/Y/Z over time at the gradient-rotation-speed rate;
|
||||
14. **Anchor rotation.** A and B rotate among X/Y/Z over time at the gradient-rotation-speed rate;
|
||||
dragging the control visibly changes the rotation rate, never frozen at the slow end.
|
||||
14. **Per-segment bake (mix-time-keyed).** A segment's colors are fixed when it enters at the bottom and
|
||||
15. **Per-segment bake (mix-time-keyed).** A segment's colors are fixed when it enters at the bottom and
|
||||
travel with it unchanged as it scrolls up and out — colors do not recompute under a stationary
|
||||
segment. (Realized via the mix-time-keyed sinusoid, §6b motion 2.)
|
||||
15. **Per-bar curve shift.** A bar is mostly A at the bottom and mostly B by the top — color appears to
|
||||
16. **Per-bar curve shift.** A bar is mostly A at the bottom and mostly B by the top — color appears to
|
||||
move outward as the bar climbs.
|
||||
16. **One source of truth.** No hardcoded theme hexes in the visualizer; a `DeepDrftPalettes` edit or a
|
||||
17. **One source of truth.** No hardcoded theme hexes in the visualizer; a `DeepDrftPalettes` edit or a
|
||||
dark-mode toggle re-themes the field live with no duplicate to maintain. (The icon's two accent
|
||||
literals are the documented, commented exception — §7f.)
|
||||
|
||||
**Controls / knob-bar**
|
||||
|
||||
17. **Six controls.** Exactly six RadialKnobs — scroll speed, gradient rotation speed, gravity, heat,
|
||||
density/size, collision strength — each captioned with an icon; resolution/zoom as a standalone
|
||||
control is gone.
|
||||
18. **Inline collapse/expand.** Clicking the lava-lamp icon expands the six-knob flex row **in place**
|
||||
18. **Seven controls.** Exactly seven RadialKnobs — scroll speed, gradient rotation speed, gravity, heat,
|
||||
density/size, collision strength, **waveform width** — each captioned with an icon; resolution/zoom as
|
||||
a standalone control is gone.
|
||||
19. **Waveform width.** Dragging the waveform-width control narrows/widens the waveform band across its
|
||||
range; narrowing it visibly clears horizontal space for the lava (and shrinks the collision boundary
|
||||
the fluid parts around). The datum/scroll geometry is otherwise unchanged.
|
||||
20. **Inline collapse/expand.** Clicking the lava-lamp icon expands the seven-knob flex row **in place**
|
||||
(animated open/closed via CSS transition), reading as the controls collapsing/expanding — **not** a
|
||||
floating popover or drawer. Clicking again collapses it; dragging a knob does not collapse it.
|
||||
19. **NowPlaying aesthetic.** The knob-bar's surface color + structure match the session hero now-playing
|
||||
21. **NowPlaying aesthetic.** The knob-bar's surface color + structure match the session hero now-playing
|
||||
overlay (translucent dark glass, overlay-label typography, `Color.Secondary` accents).
|
||||
20. **Persistence + read-only.** All six positions survive SPA nav within a session, reset on fresh
|
||||
22. **Persistence + read-only.** All seven positions survive SPA nav within a session, reset on fresh
|
||||
load; no control and no knob-bar element is a seek/playback surface; the bridge and read-only contract
|
||||
are intact.
|
||||
|
||||
**Icon**
|
||||
|
||||
21. **Redrawn lava-lamp glyph.** The trigger shows the classic 1970s silhouette — wide truncated-cone
|
||||
23. **Redrawn lava-lamp glyph.** The trigger shows the classic 1970s silhouette — wide truncated-cone
|
||||
base, bulbous→roundedly-pointed teardrop glass body, small cone cap — with navy fluid + moss blobs
|
||||
and a neutral/metallic base+cap; body tints via `currentColor`; renders cleanly at ~24px.
|
||||
|
||||
**Performance**
|
||||
|
||||
22. **60 FPS** on a mid-range desktop with heat, density, and collision at non-trivial values
|
||||
24. **60 FPS** on a mid-range desktop with heat, density, and collision at non-trivial values
|
||||
simultaneously; graceful degrade (drop internal resolution before frames) on weaker/mobile devices.
|
||||
|
||||
---
|
||||
@@ -695,27 +778,30 @@ under the open Phase 10 and distinct from its landed Waves 1–4.**
|
||||
Remove the static noise/frost layer (§3), implement the dynamic footer-height clip + lava-rest line
|
||||
(§2c), and **redraw the `DDIcons.LavaLamp` glyph** (§7f — independent, can land anytime, grouped here as
|
||||
cheap polish). Small, independent, and gives a clean substrate to build the lava on. **Acceptance:** §8
|
||||
#3, #4, #21.
|
||||
#3, #4, #23.
|
||||
|
||||
### Wave R2 — The wax-blob physics + collision (the load-bearing step)
|
||||
Stand up the CPU physics step (16–32 blobs: position/velocity/temperature/radius), the per-frame uniform
|
||||
upload, the `smin` metaball render, the heat/gravity/density mapping, and the 2D collision model (both
|
||||
pairs, the soft↔hard blend). This is where the architecture is proven; it replaces the §4-effect GLSL.
|
||||
**Acceptance:** §8 #1, #5–#11, #22 (at this wave's workload). Controls can be temporary sliders/debug
|
||||
knobs here — the real inline knob-bar is Wave R4.
|
||||
upload, the `smin` metaball render (**flat, coalescing fluid** — §4a refinement), the heat/gravity/density
|
||||
mapping (**energy-coupled: high heat → small turbulent bubbles** — §4c), and the 2D collision model (both
|
||||
pairs, the wide soft-mush ↔ hard up-and-out-throw blend, smooth/no jitter — §5a/§5c). This is where the
|
||||
architecture is proven; it replaces the §4-effect GLSL. **Acceptance:** §8 #1, #5–#12, #24 (at this wave's
|
||||
workload). Controls can be temporary sliders/debug knobs here — the real inline knob-bar is Wave R4.
|
||||
|
||||
### Wave R3 — The OKLab three-color gradient (the three motions)
|
||||
Replace the HSL `mixHsl`/`vivify` color with OKLab interpolation; implement the three motions (anchor
|
||||
rotation among X/Y/Z, per-segment baked sinusoidal variation **keyed to mix-time**, per-bar curve shift),
|
||||
sourced from `DeepDrftPalettes` with no hardcoded duplicates. **Acceptance:** §8 #12–#16. The
|
||||
sourced from `DeepDrftPalettes` with no hardcoded duplicates. **Acceptance:** §8 #13–#17. The
|
||||
per-segment-bake requirement (§6b motion 2) uses the mix-time-keyed realization so it travels with the
|
||||
segment by construction (decided — §6b).
|
||||
|
||||
### Wave R4 — Six controls + the NowPlaying-styled inline knob-bar
|
||||
Widen `MixVisualizerControlState` to six properties; replace the four-knob popover with the six-knob
|
||||
**inline collapse/expand knob-bar** (§7b — `@if`-guarded animated flex row, lava-lamp icon toggles it, no
|
||||
popover/drawer); style it to the session-hero aesthetic; extend the bridge handle with the new setters.
|
||||
**Acceptance:** §8 #17–#20.
|
||||
### Wave R4 — Seven controls + the NowPlaying-styled inline knob-bar
|
||||
Widen `MixVisualizerControlState` to **seven** properties (including the new **waveform width** control,
|
||||
§7a); replace the four-knob popover with the seven-knob **inline collapse/expand knob-bar** (§7b —
|
||||
`@if`-guarded animated flex row, lava-lamp icon toggles it, no popover/drawer); wire the waveform-width
|
||||
control to scale the waveform-band extent and its collision boundary (§7a); style it to the session-hero
|
||||
aesthetic; extend the bridge handle with the new setters (including `setWaveformWidth`). **Acceptance:**
|
||||
§8 #18–#22.
|
||||
|
||||
**Dependency shape:** `Wave R1 → Wave R2 → (Wave R3 ‖ Wave R4)`. Wave R1 is a quick unblock (and folds in
|
||||
the independent icon redraw). Wave R2 is the prerequisite for everything visual. Waves R3 (color) and R4
|
||||
@@ -727,8 +813,9 @@ ranges/transfer-functions by hand once on screen throughout (his standing prefer
|
||||
|
||||
## 10. Open items
|
||||
|
||||
Tuning knobs only — the controls-UI fork and the per-segment-storage fork are both now **decided** (§7b
|
||||
inline knob-bar; §6b mix-time-keyed). None block starting Wave R1.
|
||||
Tuning knobs, one undecided behavior call, and one deferred future idea — the controls-UI fork and the
|
||||
per-segment-storage fork are both now **decided** (§7b inline knob-bar; §6b mix-time-keyed). None of the
|
||||
items below block starting Wave R1.
|
||||
|
||||
- **§4c, §5d — transfer functions:** heat 0..1 → rise/morph intensity; collision 0..1 → soft↔hard blend
|
||||
shape; restitution coefficients; penetration-penalty curve. All staff-engineer tuning tasks with the
|
||||
@@ -741,4 +828,29 @@ inline knob-bar; §6b mix-time-keyed). None block starting Wave R1.
|
||||
(strongest match in the tree) or point to a different component.
|
||||
- **§7f — icon accent literals:** the two literal navy/moss stops the SVG forces (commented to their
|
||||
`DeepDrftPalettes` source) — exact hexes are staff-engineer's to pull from the palette.
|
||||
- **Defaults** for all six controls — Daniel tunes on screen.
|
||||
- **§7d — waveform-width icon glyph:** `WidthNormal` / `SwapHoriz` / `SettingsEthernet` suggested;
|
||||
staff-engineer picks the final horizontal-extent glyph.
|
||||
- **Defaults** for all seven controls — Daniel tunes on screen (the ~20% gravity / ~100% heat sweet spot,
|
||||
§4c, anchors the heat/gravity pair).
|
||||
|
||||
### Undecided — Daniel calls (not blocking, but unresolved)
|
||||
|
||||
- **Pause behavior — does the lava keep convecting while audio is paused?** Today the visualizer freezes
|
||||
on pause (the rAF loop is gated on `isPlaying` — Phase 10 §2e, carried forward). The reframe's wax
|
||||
physics raises the question of whether the lava should **keep convecting/bubbling while paused** (the
|
||||
lamp is "always on," the way a real lava lamp keeps going regardless of the music) or **freeze with the
|
||||
scroll** as it does now. **Undecided — Daniel's call.** It affects the rAF-gating rule and whether the
|
||||
physics step runs decoupled from playback. Flagged here; not blocking Wave R1/R2 (default to the current
|
||||
freeze-on-pause behavior until Daniel decides; switching to always-convect is a localized change to the
|
||||
gating, not the model).
|
||||
|
||||
### Future enhancements (explicitly out of the current reframe scope)
|
||||
|
||||
- **Per-control slow LFO auto-modulation.** Each knob could carry an optional **"auto-modulate" checkbox**
|
||||
that, when enabled, gently oscillates that control's value over time via a **low-frequency oscillator**
|
||||
(a slow sinusoid around the knob's set point), so the visualizer drifts and breathes on its own without
|
||||
the user touching it. Daniel flagged this as a "cool future enhancement" (Wave R2 eval). **Deferred — not
|
||||
in the R1–R4 scope.** When picked up it is additive: a per-control bool + amplitude/rate in
|
||||
`MixVisualizerControlState`, an LFO applied at the bridge before the uniform push, and a small checkbox
|
||||
affordance per knob in the inline knob-bar. Captured so the knob-bar's per-control layout (§7b) leaves
|
||||
room for a future toggle, but nothing in R1–R4 builds it.
|
||||
|
||||
Reference in New Issue
Block a user