Skip to content

feat(gui): vu-nano-v1 face + rotating needle#25

Open
yves-vogl wants to merge 8 commits into
feat/v0.3.1-visual-overhaulfrom
feat/v0.3.2-vu-nano
Open

feat(gui): vu-nano-v1 face + rotating needle#25
yves-vogl wants to merge 8 commits into
feat/v0.3.1-visual-overhaulfrom
feat/v0.3.2-vu-nano

Conversation

@yves-vogl

Copy link
Copy Markdown
Contributor

Summary

  • Replaces the vu-dome-v1 circular meter (face+needle+glass) with the nano-banana-approved Weston-style VU face, promoted as the reusable Basilica Audio VU component (shared by all 13 plugins).
  • Needle is a separate Blender-rendered brass blade (.scaffold/gui-assets/vu-nano-v1/render_needle.py), no baked hub, rest pose straight up (0 deg).
  • Pivot and the dB→angle tick table are measured, not hand-tuned: .scaffold/gui-assets/vu-nano-v1/analyze_face.py does a numpy polar-unwrap analysis of vu-face-no-needle.png (Blender's bundled Python). Verified by re-compositing the needle at the measured -20/0/+3 dB angles and confirming it lands exactly on each tick, matching vu-face.png's reference 0 dB pose.
  • AnalogMeter::Assets simplified to a single face/needle Image pair (no @1x/@2x tiers, no glass layer - this asset family ships one 1024px render per layer, plenty of resolution headroom for the 100/150/200% stepped window scale).
  • No layout change: PluginEditorLayout.h's meter bay rects are unchanged - the visible dial still exactly fills the existing 190px bays; only the (transparent, mouse-transparent) overhang margin fraction grew internally (AnalogMeter::contentFractionOfCanvas 0.95 → 0.79). Confirmed via the regenerated docs/gui-preview.png snapshot and a standalone launch.
  • Face asset shipped (resources/gui/vu_nano_face_1024x1024.png) is a masked derivative of the approved vu-face-no-needle.png: alpha rewritten to 0 outside the measured bezel radius (RGB untouched, so composited over black it's pixel-identical to what was approved) so the existing bay-overhang layout convention keeps working with what is otherwise a fully opaque source render. See .scaffold/gui-assets/vu-nano-v1/mask_face.py.

Base branch note

This PR is based on feat/v0.3.1-visual-overhaul (not main, and not yet merged - PR #24 is still awaiting Yves' visual sign-off) because the meter code this PR touches only exists on that branch. Diff here is scoped to the meter only; do not merge before/without #24.

Test plan

  • ctest --test-dir build - 88/88 green (Debug, native arm64, CPM_SOURCE_CACHE shared cache)
  • AnalogMeterBallisticsTests.cpp updated to the new measured tick table (was vu-dome-v1's hand-tuned table)
  • Editor snapshot test regenerated docs/gui-preview.png - both meters render the new face+needle correctly, no layout collision with the header/knob grid
  • Standalone launched (Silentium.app), both VU meters visible and rendering; quit cleanly (no leak-detector assertions)
  • Yves: visual sign-off on the running plugin (screenshot in docs/gui-preview.png) before merge, per the suite's GUI-quality-gate convention

Not merged

Per instructions, this PR is not merged - report only, pending Yves' visual confirmation.

Replace the vu-dome-v1 circular meter (face+needle+glass) with the
nano-banana-approved Weston-style VU face, promoted as the reusable
Basilica Audio VU component. The needle is a separate Blender-rendered
brass blade (no baked hub, rest pose straight up); pivot and the
dB->angle tick table are measured directly off the face art (numpy
polar-unwrap analysis, see .scaffold/gui-assets/vu-nano-v1/) rather
than hand-tuned.

- AnalogMeter::Assets now holds a single face/needle Image pair (no
  @1x/@2x tiers, no glass layer - vu-nano-v1 ships one 1024px render
  per layer); rotation is applied directly at the measured angle since
  the needle asset's own rest pose is 0 deg.
- Meter bay geometry (PluginEditorLayout.h) is UNCHANGED - the visible
  dial still exactly fills the existing 190px bays, only the
  (transparent, mouse-transparent) margin fraction grew internally.
- Face asset shipped is a masked derivative of the approved
  vu-face-no-needle.png (alpha rewritten to 0 outside the measured
  bezel radius; RGB untouched) so the existing bay-overhang layout
  convention keeps working with an opaque-background source render.
- Regenerated docs/gui-preview.png via the editor snapshot test.

88/88 tests green (Debug, native arm64); standalone launched and
quit cleanly with both meters rendering and animating correctly.
PR #25 review of docs/gui-preview.png flagged the VU needle as a blurry
~1px sliver at the rendered ~200px component size. Two independent fixes:

- resources/gui/vu_nano_needle_1024x1024.png: re-rendered from
  gui-pipeline's vu-nano-v1/render_needle.py with a wider, less-extreme
  taper (stays broad through the body, only narrows sharply near the tip)
  plus a brass highlight streak. Pivot/length unchanged, verified against
  the measured tick table. Mean alpha in a 6x6px window at 50% of the
  blade's length, resampled to the actual 241px on-screen AnalogMeter
  size, goes from 0.46 to 1.00 (2.2x denser); at 70% up the shaft, 0.26 to
  0.90 (3.5x).

- src/gui/AnalogMeter.cpp: setBufferedToImage(true) on construction, and
  Graphics::setImageResamplingQuality(highResamplingQuality) before both
  the face and needle draws in paint() - the default mediumResamplingQuality
  is a real quality difference on the native CoreGraphics/Direct2D
  backends used at runtime (kCGInterpolationMedium vs ...High), though it
  is a no-op on the headless SoftwareImageType path the snapshot test
  uses (JUCE 8.0.14's software rasteriser only distinguishes low vs.
  not-low resampling quality) - see the in-code comments for the exact
  source citations.

docs/gui-preview.png regenerated via the existing EditorSnapshotTests.cpp
snapshot test.
The Blender-rendered needle in this file is superseded by an asset
extracted directly from the nano-banana vu-face.png reference render
(basilica-audio/gui-pipeline @ d2ee0a9, vu-nano-v1/extract_needle.py).
Same filename/geometry (pivot_frac_xy unchanged), so no CMake or
PluginEditor change is needed - drop-in replacement.

Verified: full Debug build + all 88 ctest cases green, regenerated
docs/gui-preview.png via the editor snapshot test, and a manual launch
of Silentium.app to confirm no runtime issue loading the new PNG.
Direction reversed same-day: both the previous wide-blade re-profile
and the extraction-based needle (basilica-audio/gui-pipeline @ d2ee0a9)
read as too fat for the intended precision-instrument look. Swaps in
render_needle.py's new hairline profile instead (gui-pipeline @
b5ebb14) - BASE_W an order of magnitude thinner (0.100 -> 0.010),
near-uniform width until a short taper just before the tip, no
mid-blade widening. Same filename/geometry, so no CMake/PluginEditor
change.

Verified: full Debug build + all 88 ctest cases green, regenerated
docs/gui-preview.png via the editor snapshot test (needle reads
clearly as a hairline at actual on-screen ~241px component size, not
a disappearing sliver - see gui-pipeline's README for the measured
peak-alpha numbers), and a manual launch of Silentium.app to confirm
no runtime issue loading the new PNG.
…round

Removes the photoreal faceplate_silentium_v2 PNG from the editor's plate
background (Yves' verdict: the nano-banana render looked wrong) and
replaces it with a vector-drawn glossy-black plate: a vertical gradient
with a warm rim at the top ~15%, a broad soft diagonal upper-left
reflection styled after brand/mock-raytrace-1-frontal.png, and a hairline
bright bevel tracing the rounded outline. Meters and knobs get a shared
drop-shadow via juce::DropShadowEffect so they read as objects sitting on
the plate rather than pasted flat onto it.

The old faceplate PNGs remain bundled in resources/gui/ (unused, for
manual cleanup) since removing them was explicitly out of scope. As a
side effect of removing the plate art, the captions baked into it (title,
knob/toggle labels) are no longer drawn - accessible names via setTitle()
are unaffected.
…e emblem) + needle overlays

Replaces the JUCE-drawn glossy-black plate + separate vu-nano-v1 face/needle
pair with ONE photoreal master render (resources/gui/faceplate-silentium-v3.png)
carrying the obsidian plate, both VU dials, tube-vent grilles, all 9 knobs,
both toggles, and the Basilica rose emblem baked in. Only the live rotating
needle (a hand-authored vector-equivalent asset, vu-needle-master-v3.png -
raster-extracting the master's own ~3-11px needle proved too soft at
arbitrary rotation angles) plus a subtle incandescent pilot-lamp glow with
gentle per-instance flicker are drawn live by AnalogMeter, which no longer
draws a face image at all in this usage.

PluginEditorLayout.h's @1x geometry table is re-derived from
.scaffold/gui-assets/faceplate-silentium-v3/faceplate-metadata.json
(pivot/tick/knob/toggle positions measured directly on the master render).
AnalogMeter's components are pivot-centred squares (fraction always 0.5,0.5)
matching the baked hub position; knobs/toggles use the master's own
staggered centres instead of a straight grid. All synthetic drop-shadow/
gradient/bevel/header-roundel JUCE paint code is removed - the master
already bakes plausible lighting for every control.

Tests: AnalogMeterBallisticsTests updated to the new measured tick table;
EditorLayoutTests rewritten around explicit knob/toggle centres, including
the new knob-row Y-alignment invariant.
Replace v0.3.2's single baked master faceplate with genuine standalone
master-reference assets composited live, per Yves' final art direction:
bare obsidian baseline plate, a tamed softbox reflection layer, flickering
tube-vent glow (independent per-tube noise sources), a freshly re-extracted
rose emblem, both VU dial faces with peak LEDs, single-image rotated knobs,
and corner screws. AnalogMeter now draws its own face/glow/LED in addition
to the needle, with a configurable pivot fraction (the fresh face asset's
hub isn't canvas-centred). All plate/dial/knob/toggle geometry was
re-measured directly against the master-04 render, which differs
materially from the master-03 metadata the old layout table was based on.

Known compromise: the two footer toggles still use the older
toggle_brass_v2_strip filmstrip asset - no master-04-generation toggle
render exists yet, flagged as a follow-up rather than silently shipped.
Replace the three prior "component composition" GUI attempts (bare
JUCE-drawn background, single baked master, true component assembly
of many standalone master-reference PNGs) with a single-master-
baseline architecture: master-05.png alone bakes the entire static
faceplate (plate, bevel, screws, rose, both empty VU faces, all 9
knobs at rest, both toggles up, both vents at normal glow). Only
three small, targeted dynamic overlays remain: a per-toggle
master-06.png crop swap when a toggle is off, a subtle signal-driven
vent-glow cross-blend between master-glow-dim.png and master-05's own
baked level (never brighter - the hot/very-hot frames are dropped
per Yves' explicit rejection of that look), and the two AnalogMeter
needle/LED overlays.

Knobs and toggles are now passive: a transparent-draw juce::Slider
per knob and a plain juce::ToggleButton per toggle (mouse + APVTS
only, no visible rotation), which structurally rules out the
double-image artifact of overlaying a rotating control on a baked
one. PluginEditorLayout.h was re-measured directly against
master-05.png (HoughCircles + HSV colour-threshold blob detection,
see analysis/measure_master_05.py) rather than the prior master-04
table. AnalogMeter no longer draws its own dial face.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant