Files
mangotune/docs/PREVIEW_UPDATE_MAP.md
T
44r0n7 a36c02bbf7 docs: refresh preview update guidance and repo map
This documents the current preview apply contract, updates the project
map to match the live code paths, and adds the local scratchpad issue
tracking reminder to the workspace instructions.
2026-03-31 17:23:13 -04:00

13 KiB

Preview Update Map

This document maps how MangoTune updates the built-in live preview today:

  • what uses live apply
  • what falls back to restart
  • what intentionally restarts
  • what updates preview runtime only
  • what does not touch preview at all

It also notes the main inconsistencies and the recommended direction.

Core Paths

1. Debounced config live apply

Code:

  • mod.rs
    • refresh_live_preview_for_key(...)

Behavior:

  • used for most normal config edits
  • waits 180 ms
  • if preview is running:
    • grabs current in-memory config
    • calls preview.apply_live_config(&config)
    • falls back to preview.restart(&config) if live apply fails

Used by:

  • most schema-backed rows in shared widgets
  • most text-entry commit paths
  • most color rows
  • hotkey rows
  • typography font changes
  • many dashboard field edits through maybe_reload_preview_for_key(...)

Intent:

  • cheap, smooth preview refresh for ordinary config edits

2. Immediate config live apply

Code:

  • mod.rs
    • apply_live_preview_now(...)

Behavior:

  • if preview is running:
    • cancels any pending debounced refresh
    • immediately calls preview.apply_live_config(&config)
    • falls back to preview.restart(&config) if live apply fails

Used by:

  • dashboard metric chips
  • dashboard layout/style flag chips like:
    • Compact
    • No margin
    • Horizontal
    • Outline
  • shared switch/toggle rows

Intent:

  • immediate visual response for simple on/off interactions

3. Explicit restart

Code:

  • overview.rs
    • preview page Restart button
    • maybe_restart_active_preview(...)

Behavior:

  • always restarts the preview process/window

Used by:

  • explicit Restart button on Live Preview
  • Studio preview window size changes
    • width
    • height

Intent:

  • for changes that need a fresh preview window/process

4. Preview runtime-only apply

Code:

Behavior:

  • does not push a MangoHud config rewrite
  • updates the Studio preview runtime knobs only

Used by Live Preview runtime controls:

  • scene
  • studio scene
  • FPS cap
  • particle count
  • particle size
  • GPU passes
  • interaction steps
  • VRAM pressure
  • vsync
  • pause

Intent:

  • update the preview workload/runtime without treating those as MangoHud config edits

5. Save/reload/apply-profile style preview apply

Code:

  • window.rs
    • apply_preview_current_config(...)

Behavior:

  • if preview is running:
    • applies current in-memory config
    • falls back to restart on failure

Used after bigger state changes:

  • revert/discard unsaved changes
  • undo-style restore of saved snapshot
  • redo
  • restore safety backup into state
  • reset to defaults
  • load config target from disk
  • reload active config from disk
  • profile apply/restore flows that replace current state

Intent:

  • after whole-config replacement, immediately synchronize preview to the new state

Where Each UI Surface Lands

Shared Schema Widgets

Switch rows

Code:

Preview path:

  • apply_live_preview_now(...)

Notes:

  • immediate
  • dependency enable/disable logic runs first
  • page may also refresh if dependent toggle state changed

Spin rows

Code:

Preview path:

  • refresh_live_preview_for_key(...)

Notes:

  • debounced live apply
  • good fit for repeated numeric scrubbing

Combo rows

Code:

Preview path:

  • refresh_live_preview_for_key(...)

Notes:

  • debounced

Entry rows

Code:

  • toggle_row.rs
    • build_entry_row(...)
    • connect_entry_preview_commit(...)

Preview path:

  • on focus-leave / commit:
    • refresh_live_preview_for_key(...)

Notes:

  • avoids thrashing on every keystroke
  • updates config/validation immediately
  • preview waits until commit

Threshold triplet rows

Code:

  • toggle_row.rs
    • build_int_triplet_row(...)
    • connect_group_entry_preview_commit(...)

Preview path:

  • on leaving the whole triplet group:
    • refresh_live_preview_for_key(...)

Notes:

  • correct behavior for grouped value editing

Multi-select rows

Code:

Preview path:

  • refresh_live_preview_for_key(...)

Notes:

  • debounced-ish via helper timing, but effectively immediate enough per toggle

Color Widgets

Single color rows

Code:

Preview path:

  • entry:
    • commit on focus-leave via refresh_live_preview_for_key(...)
  • swatch:
    • immediate refresh_live_preview_for_key(...)

Color list / threshold palette rows

Code:

Preview path:

  • entry triplets:
    • commit on leaving group via refresh_live_preview_for_key(...)
  • swatches:
    • immediate refresh_live_preview_for_key(...)

Hotkeys

Code:

Preview path:

  • refresh_live_preview_for_key(...)

Notes:

  • sensible
  • hotkeys should not require restart

Typography Page

Code:

Preview path:

  • refresh_live_preview_for_key(...)

Notes:

  • this is reasonable if MangoHud live apply can accept font-path changes
  • if users later report font changes only working after restart, this is one place to revisit

Dashboard

Position grid

Code:

Preview path:

  • maybe_reload_preview_for_key(...)
    • delegates to refresh_live_preview_for_key(...)

Scale/slider style controls

Code:

Preview path:

  • mostly maybe_reload_preview_for_key(...)

Notes:

  • width also uses live apply right now on dashboard
  • that differs from Studio preview window width, which correctly restarts
  • this is okay because dashboard width is MangoHud HUD width, not preview window size

Dashboard flag chips

Code:

Preview path:

  • apply_live_preview_now(...)

Current examples:

  • Compact
  • No margin
  • Horizontal
  • Outline

Notes:

  • this is now consistent with user expectation
  • earlier forced restart path was removed

Dashboard metric chips

Code:

Preview path:

  • apply_live_preview_now(...)

Notes:

  • immediate
  • dependency cascade logic runs first

Dashboard color controls

Code:

  • overview.rs
    • build_color_control(...)
    • connect_dashboard_entry_preview_commit(...)

Preview path:

  • entry:
    • commit on focus-leave via maybe_reload_preview_for_key(...)
  • swatch:
    • immediate maybe_reload_preview_for_key(...)

Live Preview Page

Preview config buttons

Code:

Behavior:

  • Start
    • preview.start(...)
  • Apply
    • direct preview.apply_live_config(&config)
  • Restart
    • direct preview.restart(&config)
  • Stop
    • direct preview.stop()

Notes:

  • this page is the canonical behavior reference
  • shared helpers should behave consistently with Apply

Studio runtime controls

Code:

  • overview.rs
    • maybe_apply_studio_preview_runtime(...)
    • maybe_restart_active_preview(...)

Behavior split:

  • runtime-only live updates:
    • scene
    • studio scene
    • fps cap
    • particle count
    • particle size
    • gpu passes
    • interaction steps
    • vram pressure
    • vsync
    • pause
  • restart:
    • preview window width
    • preview window height

Assessment:

  • this split is correct

HUD Order

Code:

Preview path:

  • if preview is running:
    • direct preview.apply_live_config(&config)
    • fallback preview.restart(&config)
  • if preview is not running:
    • refresh_live_preview_for_key(...)

Notes:

  • this now matches the current shared immediate-apply behavior
  • drag/drop was removed for now because it was causing native corruption
  • row movement via buttons is stable

Window-Level Whole-State Flows

Code:

  • window.rs
    • apply_preview_current_config(...)

Used by:

  • revert/discard
  • redo
  • restore backup
  • reset defaults
  • config target switch
  • reload from disk
  • similar whole-state replace flows

Preview path:

  • direct apply_live_config
  • fallback restart

Assessment:

  • correct
  • after a whole config replacement, immediate apply is the right default

Inconsistencies Found

1. Shared helpers previously disagreed with Live Preview -> Apply

Status:

  • fixed

What was wrong:

  • shared helpers used to refuse preview updates when validator::is_saveable(...) was false
  • but the explicit Apply button on Live Preview did not
  • this created confusing “manual Apply works, normal controls do not” behavior

Current state:

  • shared helpers now match the Apply button behavior

2. HUD Order had its own crash-prone interaction model

Status:

  • mitigated, not fully ideal

What changed:

  • drag/drop removed
  • explicit up/down controls now used

Assessment:

  • behavior is stable now
  • drag/drop can be revisited later as a separate feature

3. Some edits are commit-on-leave while others are immediate

Status:

  • mostly intentional

Examples:

  • entry fields wait for commit/leave
  • toggles and swatches apply immediately

Assessment:

  • this is good
  • text editing should not hot-apply every keystroke

4. Preview runtime controls and MangoHud config controls use different paths

Status:

  • intentional and correct

Assessment:

  • Studio runtime controls should stay separate from MangoHud config live apply

Areas That Should Probably Stay As-Is

  • shared switch rows using immediate apply
  • shared spin/combo rows using debounced apply
  • text entry rows using commit-on-leave
  • Studio runtime controls using runtime-only apply
  • Studio window size using restart
  • whole-config replacement flows using immediate apply + restart fallback

Areas Worth Watching

1. Font changes

Current behavior:

  • live apply

Potential issue:

  • if MangoHud does not reliably rebuild fonts on live apply, these may need explicit restart semantics later

Current recommendation:

  • keep live apply unless users report failures

2. Very structural layout changes

Current behavior:

  • dashboard shell flags now live-apply

Assessment:

  • that is the desired behavior
  • only revisit if MangoHud itself proves some of these are not safely live-applicable

3. HUD Order

Current behavior:

  • direct immediate apply + restart fallback

Assessment:

  • correct
  • no reason to special-case restart-only here

Rule 1

Use live apply by default for MangoHud config edits.

Rule 2

Use restart only when the preview window/process itself must be recreated.

Current known restart-only cases that fit this rule:

  • Studio preview window width
  • Studio preview window height
  • explicit Restart button

Rule 3

For typed text/group editors, commit preview updates on field/group exit rather than per keystroke.

Rule 4

Keep Live Preview -> Apply as the canonical behavior reference.

If a shared helper behaves differently from that button, the shared helper is probably the thing that is wrong.

Suggested Follow-Up Cleanup

These are code-cleanup ideas, not urgent bug fixes.

  1. Centralize preview update intent into a small enum

    • DebouncedApply
    • ImmediateApply
    • Restart
    • RuntimeOnly
  2. Replace direct ad hoc preview.apply_live_config(...).or_else(restart) call sites with one shared helper

    • currently duplicated in:
      • mod.rs
      • overview.rs
      • hud_order.rs
      • window.rs
  3. Add a short code comment near Live Preview -> Apply

    • stating that it is the reference behavior shared helpers should match
  4. Revisit drag-and-drop for HUD Order only as a separate stability task

    • not as part of normal preview semantics work