# Research: ModernZ UI scaling at certain resolutions/window sizes (issue #6)

Date: 2026-07-28. Status: implemented 2026-08-06; outcome in §5.

## 0. What mpv-manager ships today

- Live release manifest [mpv.rocks/api/releases.json](https://mpv.rocks/api/releases.json) (dated 2026-07-28)
  distributes **ModernZ v0.3.3** — `modernz.lua`, `modernz-icons.ttf`, `modernz.conf` all from
  `https://github.com/Samillion/ModernZ/releases/download/v0.3.3/...`.
- v0.3.3 is the **latest upstream release** ([releases page](https://github.com/Samillion/ModernZ/releases));
  `main` is only trivially ahead (input-handling refactor, no scaling changes). No version bump is pending.
- `cmd/generate-info/main.go` always tracks the latest GitHub release (fallback constant `0.3.0` at line 327 only
  applies if the API call fails), so the shipped version drifts forward automatically on each manifest regen.
- The installer downloads and BLAKE3-verifies upstream `modernz.conf`, then modifies only the verified staged
  copy before installation. New managed installs set `vidscale=no`, `scalewindowed=1.0`, and
  `scalefullscreen=1.0`; ModernZ updates preserve the existing effective values for those three keys.
- The ModernZ editor curates 24 of the 208 conf options, including `scalewindowed`, `scalefullscreen`
  (bounds 0.1–5.0) and `vidscale`. Both Web and TUI editors now provide friendly scaling labels, recommended
  state, paired-size guidance, and HiDPI examples.

## 1. How ModernZ scaling actually works (modernz.lua v0.3.3, `osc_init()` ~L3060)

- Canvas height `playresy = unscaled_y / scale`, where `scale` = `scalefullscreen` in fullscreen, else
  `scalewindowed` (both default `1.0`, any positive float; [conf](https://raw.githubusercontent.com/Samillion/ModernZ/v0.3.3/modernz.conf),
  [USER_OPTS.md](https://github.com/Samillion/ModernZ/blob/main/docs/USER_OPTS.md)).
- `vidscale` (default `auto`) decides `unscaled_y`:
  - `auto` → follow mpv's `osd-scale-by-window`, which **defaults to `yes`**
    ([mpv manual](https://mpv.io/manual/master/#options-osd-scale-by-window), verified in mpv `DOCS/man/options.rst`).
  - scaling with video (`auto`+default, or `yes`): `unscaled_y = 720` — the OSC is laid out on a fixed 720-line
    canvas stretched over the window. **OSC size ∝ window height ÷ 720 × scale.** A 540px-high window shrinks the
    OSC to 0.75×; 4K fullscreen (2160px) balloons it to 3×; toggling fullscreen on a 4K display can double it.
  - `vidscale=no`: `unscaled_y = display_h` — OSC elements keep a **constant pixel size** (× scale factor)
    regardless of window size, resolution, or fullscreen state.
- There is **no DPI/HiDPI awareness**: `modernz.lua` never reads `display-hidpi-scale`; no auto-scaling,
  min/max-dimension, or DPI option exists upstream. HiDPI users manually raise `scalewindowed` (e.g. 1.5 for
  150 % system scaling — see issue [#279](https://github.com/Samillion/ModernZ/issues/279)).
- `hidetimeout` is visibility-only, unrelated to sizing. Element-level sizing options exist but are manual too
  (§3 table). Responsive layout uses fixed width triggers (`portrait_window_trigger=950`,
  `hide_volume_bar_trigger=1150`), independent of scale.
- The two scale factors are independent, so a user who changed only `scalewindowed` sees a size **jump** when
  toggling fullscreen — a plausible "wrong at certain window sizes" report.

## 2. Upstream changes after the version the app first shipped (0.3.0 → 0.3.3)

The app added ModernZ at ~0.3.0/0.3.1 (issue #11 tracked the 0.3.1 font change). From the
[release notes](https://github.com/Samillion/ModernZ/releases):

- **v0.3.1** — single font `modernz-icons.ttf` replaces `fluent-system-icons.ttf`/`material-design-icons.ttf`
  (app handles this, `pkg/installer/common.go:470-471` cleans legacy fonts); new `icon_style`; options
  renamed/removed (`seek_resets_hidetimeout` gone; speed button icon → text label).
- **v0.3.2** — new `seekbar_height` presets (small/medium/large/xlarge), `keep_with_cursor`, `deadzonesize`,
  `deadzone_hide`, `windowcontrols_independent`, `seek_handle_*`; seekbar made wider by default; `osc_height`
  now drives element positioning; thumbnail options renamed; `windowcontrols_fullscreen` removed.
- **v0.3.3** — layouts `mini` and `seekbar` added (`layout` = default/compact/mini/seekbar); A/B-loop indicator;
  title ellipsis + clipping fixes; `chapter_softrepeat` removed. Every 0.3.x note warns "options have been
  renamed or removed" — old conf files must be replaced, which the app's reinstall flow does.
- Scaling-behavior history: PR [#123](https://github.com/Samillion/ModernZ/pull/123) (Oct 2024) changed
  `vidscale`'s default `yes` → `auto` so the OSC respects `osd-scale-by-window`; net default behavior unchanged
  (mpv default is `yes`) but users with `osd-scale-by-window=no` in mpv.conf now get fixed-size OSC.

## 3. Conf diff: upstream v0.3.3 (208 opts) vs app editor (24 opts)

All 24 curated keys verified present under identical names in the v0.3.3 conf (mechanical grep, no renames
affect the editor). Scaling/sizing-relevant options upstream has that the editor does **not** expose:

| Option | Default | Since | Relevance to #6 |
|---|---|---|---|
| `vidscale` | auto | old | **Exposed already** — the master switch for resolution-dependent sizing |
| `seekbar_height` | medium | 0.3.2 | **Exposed already** |
| `osc_height` | 60 | (0.3.2 wired) | Overall bar height |
| `playpause_size` / `midbuttons_size` / `sidebuttons_size` | 28/24/24 | ≤0.3.0 | Button icon sizes |
| `time_font_size` / `tooltip_font_size` / `speed_font_size` | 16/14/16 | 0.3.x | Text legibility at scale |
| `chapter_title_font_size` / `window_title_font_size` | 16/26 | 0.3.x | Text legibility |
| `seek_handle_size` (0–1) / `seek_handle_border_size` | 0.8/0.42 | 0.3.2 | Seekbar handle proportions |
| `button_hover_size` | 115 | ≤0.3.2 | Hover grow % — can look like "jittery size" |
| `portrait_window_trigger` / `hide_volume_bar_trigger` | 950/1150 | ≤0.3.2 | Width px where layout drops elements — looks like "broken at small sizes" |

## 4. Known upstream issues about scaling (none open)

- [#24](https://github.com/Samillion/ModernZ/issues/24) / PR [#26](https://github.com/Samillion/ModernZ/pull/26):
  raised subtitles mispositioned with non-default `scalefullscreen` — fixed Oct 2024.
- [#183](https://github.com/Samillion/ModernZ/issues/183): freezes with `vidscale=no` on minimize — closed
  "not bug: update mpv" (old mpv build).
- [#359](https://github.com/Samillion/ModernZ/issues/359): select-menu text ignores `osd-scale-by-window=no` —
  closed "not bug: mpv related" (menu is mpv-rendered, out of ModernZ's control).
- [#279](https://github.com/Samillion/ModernZ/issues/279), [#295](https://github.com/Samillion/ModernZ/issues/295):
  4K/150 %-DPI user running `scalewindowed=1.5`; timecode hidden at narrow windows and tooltip/title overlap at
  larger fonts — both fixed (width triggers, `tooltip_height_offset`, title offsets). Confirms the intended
  HiDPI workflow is manual scale factors.
- Same complaint class exists for mpv's builtin OSC: [mpv#827](https://github.com/mpv-player/mpv/issues/827)
  (OSC too small on <720p windows), [mpv#3429](https://github.com/mpv-player/mpv/issues/3429)
  (scalewindowed/scalefullscreen "unreliable/glitchy"). The semantics are inherited from mpv's osc.lua design;
  upstream treats window-proportional sizing as intended behavior, not a bug.

## 5. Implemented outcome for issue #6

**Diagnosis.** "UI scaling looks wrong at certain resolutions/window sizes" matches the default
`vidscale=auto` + mpv `osd-scale-by-window=yes`: OSC size is proportional to window height against a 720-line
canvas (§1). Tiny OSC on small windows, oversized OSC on 4K fullscreen, and a size jump on fullscreen toggle if
only one of `scalewindowed`/`scalefullscreen` was changed. It is by-design upstream; there is nothing to fix in
mpv-manager's install path, and the app already ships the latest ModernZ (v0.3.3), so **no version bump** helps.

The manager now chooses resolution-independent sizing for new managed installs:

```ini
vidscale=no
scalewindowed=1.0
scalefullscreen=1.0
```

This transformation occurs only after the downloaded upstream config passes BLAKE3 verification and while it is
still staged. Existing installs retain their complete `modernz.conf` byte for byte during ModernZ updates, with a
timestamped pre-update backup. The Web and TUI editors call `vidscale=no` **Consistent size (recommended)**, distinguish the upstream `auto` behavior, and explain
that both size multipliers should normally match. They also suggest 1.25, 1.5, or 2.0 as manual HiDPI starting
points. The global `mpv.conf` option remains untouched so other OSD/scripts are not changed as a side effect.

Legacy installs whose effective value is still `auto` receive a persistent one-time Web/TUI choice to apply the new
recommendation or keep their current behavior. Applying it changes only `vidscale`; explicit custom size multipliers
are not replaced. Explicit `vidscale=yes` and previously resolved migrations are never silently overridden.

Further element-level sizing (`time_font_size`, `tooltip_font_size`, `osc_height`) remains optional future editor
coverage rather than part of issue #6. No private ModernZ fork or upstream behavior change is required.

## Sources

- [ModernZ releases](https://github.com/Samillion/ModernZ/releases) ·
  [v0.3.3 modernz.conf](https://raw.githubusercontent.com/Samillion/ModernZ/v0.3.3/modernz.conf) ·
  [modernz.lua (main)](https://github.com/Samillion/ModernZ/blob/main/modernz.lua) ·
  [USER_OPTS.md](https://github.com/Samillion/ModernZ/blob/main/docs/USER_OPTS.md)
- [mpv manual: --osd-scale-by-window](https://mpv.io/manual/master/#options-osd-scale-by-window) (default `yes`,
  cross-checked against mpv `DOCS/man/options.rst` on master)
- [mpv.rocks/api/releases.json](https://mpv.rocks/api/releases.json) (fetched 2026-07-28)
- Issues/PRs linked inline in §2 and §4. All URLs fetched and resolving as of 2026-07-28.
