fix(ui): make UI scale work in DAWs (live zoom + window resize)#4
Merged
Conversation
The UI-scale badge only wrote `ui_scale.txt`, which is read solely by the
standalone launcher (`niner-launch.sh --dpi-scale`). In a DAW nothing read
it and `Editor::set_scale_factor` was never driven from it, so clicking the
badge was a no-op in every host (not distro/WM-specific). Resizing the
window also did nothing — the editor never participated in host resize.
Drive both egui's content zoom and a matching programmatic window resize
from a single scale value, every frame:
ctx.set_zoom_factor(scale);
if editor_state.size() != BASE * scale { editor_state.set_requested_size(..) }
With baseview's native scale pinned to 1.0 (DAW hosts default to it; the
standalone launcher now passes `--dpi-scale 1.0`), effective ppp == scale:
the host window grows to BASE × scale physical pixels while the layout keeps
drawing into a fixed 680×444 logical space. Uniform scale, no reflow — knob
rows never move relative to each other.
- src/ui/editor.rs: per-frame zoom + resize reconcile; honest badge tooltip/log.
- src/params.rs: open pre-scaled (new BASE_WINDOW_SIZE const) to avoid a
first-frame resize flash.
- tools/niner-launch.sh: pin --dpi-scale 1.0; plugin owns scaling now.
- Cargo.toml: repoint nih_plug/nih_plug_egui to Hornfisk/nih-plug@8b51e93,
which exposes EguiState::set_requested_size (private upstream).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Hornfisk
added a commit
that referenced
this pull request
Jun 5, 2026
The UI-scale badge only wrote `ui_scale.txt`, which is read solely by the
standalone launcher (`niner-launch.sh --dpi-scale`). In a DAW nothing read
it and `Editor::set_scale_factor` was never driven from it, so clicking the
badge was a no-op in every host (not distro/WM-specific). Resizing the
window also did nothing — the editor never participated in host resize.
Drive both egui's content zoom and a matching programmatic window resize
from a single scale value, every frame:
ctx.set_zoom_factor(scale);
if editor_state.size() != BASE * scale { editor_state.set_requested_size(..) }
With baseview's native scale pinned to 1.0 (DAW hosts default to it; the
standalone launcher now passes `--dpi-scale 1.0`), effective ppp == scale:
the host window grows to BASE × scale physical pixels while the layout keeps
drawing into a fixed 680×444 logical space. Uniform scale, no reflow — knob
rows never move relative to each other.
- src/ui/editor.rs: per-frame zoom + resize reconcile; honest badge tooltip/log.
- src/params.rs: open pre-scaled (new BASE_WINDOW_SIZE const) to avoid a
first-frame resize flash.
- tools/niner-launch.sh: pin --dpi-scale 1.0; plugin owns scaling now.
- Cargo.toml: repoint nih_plug/nih_plug_egui to Hornfisk/nih-plug@8b51e93,
which exposes EguiState::set_requested_size (private upstream).
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Hornfisk
added a commit
that referenced
this pull request
Jun 5, 2026
⚠️ WORK IN PROGRESS — not release-ready. If you cloned this, the GUI is mid-rework: the chassis is a placeholder bare plate whose baked NINER logo is misaligned/clipped. A clean logo-less plate + an isolated code-drawn logo are pending. Do not tag/release from this commit. GUI rework — bare-plate strategy: - assets/chassis.png: replaced the FALLOUT photoreal chassis with a bare battered-metal plate. The art carries no knob grid / labels / sockets, so the whole faceplate-vs-grid alignment problem is gone — every interactive element is code-drawn and grid-locked by construction. - Re-enable procedural chrome over the bare plate: SHOW_KNOB_LABELS (knob.rs), SHOW_SECTION_LABELS + SHOW_CORNER_SCREWS (panels.rs) = true. Header logo stays baked for now (SHOW_HEADER_LOGO=false) — KNOWN misalignment, to be replaced by an isolated code-drawn logo (inverted-N), pending assets. - knob.rs: NINER_ALIGN_TEMPLATE=1 dev overlay (magenta knob-grid rings) kept as a gated authoring aid. UI-scale regression fix (PR #4 broke standalone scaling): - Root cause: PR #4 swapped the working baseview *native* scaling lever for ctx.set_zoom_factor(), which upstream egui-baseview (BillyDM @ec70c3f) ignores — it tessellates/renders at its own pixels_per_point (the baseview scale policy, pinned to 1.0). So at 1.5x the window grew but content stayed 1x, with per-frame "pixels_per_point changed between text layout and tessellation" warnings. - Fix: restore native scaling. * tools/niner-launch.sh: forward --dpi-scale "$SCALE" (from ui_scale.txt) again instead of pinning 1.0. * params.rs: open the editor at the logical BASE size (no pre-multiply by ui_scale) so baseview's ppp does the scaling once. * editor.rs: drop the dead set_zoom_factor + set_requested_size reconcile block (and the now-unused editor_state_clone). Badge tooltip/log are honest: scale persists and applies on plugin reopen. 1x / 1.5x / 2x all render correctly at launch. - FOLLOW-UP: truly live in-DAW rescale needs an egui-baseview fork that renders at the zoom-aware ppp (egui_ctx.pixels_per_point()). Deferred. TODO on this branch: regen bare plate without the baked logo + wire the isolated inverted-N logo as a code-drawn header asset; recolor the small grey labels to bone-white for legibility on the lower-contrast plate. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Hornfisk
added a commit
that referenced
this pull request
Jun 6, 2026
…4cf59 Replaces the parallel bd4cf59 WIP ('bare-metal faceplate + native scaling') with the iterated, in-app-verified result from this session. (Note: drops bd4cf59's one-line .gitignore add.) UI scaling (issue #3 cont.): PR #4's egui-zoom broke the standalone (window grew to ~680x scale^2, content splayed). Standalone-only causes: the fork's nih_plug_egui resize emits a logical-points ViewportCommand::InnerSize beside queue.resize, so with zoom_factor=scale the host-less window over-sizes (a DAW host overrides it); and EguiState was pre-scaled by ui_scale, compounding with the launcher --dpi-scale. Fix: crate::IS_STANDALONE (set in run_standalone) — the standalone skips the zoom + set_requested_size path and keeps EguiState at base 680x444, so baseview --dpi-scale is the sole scale; DAW path unchanged. niner-launch passes --dpi-scale <saved>. Bumped to 0.8.0. GUI (Fallout faceplate): flat dark distressed plate for legibility, with Niner's logo + correctly-spelled labels drawn live (the genai full-faceplates baked wrong labels — ANT/BW — and misaligned sockets). New MasterRow.display_bg glossy LCD panel; per-section glossy knob caps (assets/knob_<section>.png) blitted untinted for true white speculars, falling back to the tinted neutral cap; TEXT_DIM raised + widgets::outlined_text halo on knob labels for legibility; removed the vestigial preset-bar divider. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3.
Problem
The
UI 1.5xbadge only wroteui_scale.txt(read solely by the standalone launcher via--dpi-scale). In a DAW nothing read it andEditor::set_scale_factorwas never driven from it, so clicking the badge — and resizing the window — did nothing in every host.Fix
Drive egui content zoom + a matching programmatic window resize from one scale value, every frame:
With baseview's native scale pinned to 1.0 (DAW hosts default to it; the launcher now passes
--dpi-scale 1.0), effective ppp ==scale: the host window grows to680×444 × scalephysical px while the layout keeps drawing into a fixed680×444logical space. Uniform scale, no reflow — knob rows never move relative to each other.Changes
src/ui/editor.rs— per-frame zoom + resize reconcile; honest badge tooltip/log.src/params.rs— open pre-scaled (newBASE_WINDOW_SIZEconst) to avoid a first-frame resize flash.tools/niner-launch.sh— pin--dpi-scale 1.0; plugin owns scaling now.Cargo.toml— repointnih_plug/nih_plug_eguitoHornfisk/nih-plug@8b51e93(upstream28b149e+ one line exposingEguiState::set_requested_size, private upstream — mirrors the existingHornfisk/baseviewpatch pattern).Verification
cargo checkclean;cargo testgreen (7 tests).niner-launch.sh. If a host ignoresrequest_resize, it degrades to opening at the right size (still better than today).🤖 Generated with Claude Code