feat(installer): v0.6 ergonomics + polish — 5 quick wins #3

Merged
s8n merged 5 commits from feat/ux-installer-v06-polish into main 2026-05-06 13:47:35 +01:00
Owner

v0.6 ergonomics + polish wave — installer quick wins

Five quick-win fixes from the v0.6 polish list, all landing in overlay/usr/local/bin/veilor-installer. One commit per fix.

Fixes

  1. gum input --password → bash read -srp (commit 6d86e00)
    Kills the duplicate-"Install" + stray-"T" fbcon render glitch that has been visible in every install since v0.5.27. gum input --password's bubbletea screen-restore writes back the previous menu buffer because the linux framebuffer terminfo lacks civis/cnorm cursor-hide sequences. read -srp is a single termios echo-off — no redraw, no glitch. Header rendered separately via gum style so visual parity with the rest of the installer is preserved. Whiptail fallback path unchanged.

  2. Banner staged reveal at 40ms/line (commit 4c1895d)
    Read banner.txt line by line with a 40ms sleep between each, then clear and redraw the bordered gum-style version. 5-line banner × 40ms = 200ms total reveal — slow enough to land an aesthetic on the first frame, fast enough that the operator never feels it as lag.

  3. Confirm-twice for LUKS + admin password (commit 767fe71)
    Re-prompt LUKS passphrase + admin password, string-compare, reject mismatch. A typo in the LUKS passphrase is unrecoverable (the disk is unmountable without it; we don't escrow). Catches keyboard-layout surprises before they brick the install.

  4. 10s reboot countdown (commit 138a047)
    Replace the static sleep 5 with a 10 → 1 redraw loop printing the remaining seconds via clear + gum style each tick. 10s (vs 5s) because operators were missing the eject window — laptops with the USB on the far side of the dock take 4-5s to physically reach.

  5. Eject-media reminder promoted to its own box (commit b64ee19)
    The reminder used to be one line buried inside the green success box and operators routinely missed it. It is now its own loud yellow thick-bordered gum-style box stacked directly below the success/countdown box, with three explanatory lines, redrawn for the full 10s of the countdown.

Before / after pseudo-screenshot

Before — v0.5.32 password screen (broken)

  ┌────────────────────────────┐
  │ [2/3] Encryption · LUKS2   │   <- header
  │ ********T                  │   <- stray T from previous menu state
  │                            │   <- duplicate "Install" rendered behind
  │  Install                   │      due to bubbletea screen-restore
  └────────────────────────────┘

After — v0.6 password screen (clean)

  ╭───────────────────────────────────────╮
  │ [2/3] Encryption · LUKS2 passphrase   │
  ╰───────────────────────────────────────╯
    password: _

  (re-prompt on confirm + mismatch loop until match)

Before — v0.5.32 success screen

  ╭──────────────────────────────╮
  │ ✓ Install complete           │
  │                              │
  │ System will reboot in 5 secs │
  │ Remove the install media.    │   <- one buried line, missed
  ╰──────────────────────────────╯

After — v0.6 success screen

  ╭─────────────────────────────╮
  │ ✓ Install complete          │
  │                             │
  │ Rebooting in 7s...          │
  ╰─────────────────────────────╯
  ┏━━━━━━━━━━━━━━━━━━━━━━━━━━���━━━━━━━━━━━━━━━━━━━┓
  ┃   Remove the install media NOW                ┃   <- own loud yellow box
  ┃                                               ┃
  ┃   Unplug the USB stick / eject the DVD        ┃
  ┃   before reboot, otherwise the system will    ┃
  ┃   boot back into the live ISO instead of      ┃
  ┃   your fresh install.                         ┃
  ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

Notes on duplicate "Install" investigation

Task brief asked whether the duplicate-"Install" warranted a gum chooseselect swap. Conclusion: no swap needed. main_menu() only contains ONE "Install" entry. The duplicate render was bubbletea's screen-restore replaying the previous menu buffer onto the password screen — fixing the password screen (fix 1) eliminates the artefact at its source. gum choose itself renders cleanly on the framebuffer because it doesn't go through the read-then-restore path that gum input --password uses.

Test plan

  • bash -n overlay/usr/local/bin/veilor-installer (passes locally)
  • Boot live ISO in QEMU; confirm banner staged reveal at install boot
  • Step into Install; enter LUKS pw with no glitch; mismatched confirm rejects with red box; matching confirm proceeds
  • Same for admin pw
  • Let install complete; confirm two stacked boxes, countdown ticks 10 → 1, system reboots
  • Whiptail fallback path unchanged — verify with TUI=whiptail veilor-installer on minimal image

Constraints honoured

  • One file touched (overlay/usr/local/bin/veilor-installer)
  • One commit per fix
  • Pushed to nullstone (Forgejo) only, NOT to origin (GitHub)
  • bash -n clean
## v0.6 ergonomics + polish wave — installer quick wins Five quick-win fixes from the v0.6 polish list, all landing in `overlay/usr/local/bin/veilor-installer`. One commit per fix. ### Fixes 1. **`gum input --password` → bash `read -srp`** (commit `6d86e00`) Kills the duplicate-"Install" + stray-"T" fbcon render glitch that has been visible in every install since v0.5.27. `gum input --password`'s bubbletea screen-restore writes back the previous menu buffer because the linux framebuffer terminfo lacks `civis/cnorm` cursor-hide sequences. `read -srp` is a single termios echo-off — no redraw, no glitch. Header rendered separately via `gum style` so visual parity with the rest of the installer is preserved. Whiptail fallback path unchanged. 2. **Banner staged reveal at 40ms/line** (commit `4c1895d`) Read `banner.txt` line by line with a 40ms sleep between each, then clear and redraw the bordered gum-style version. 5-line banner × 40ms = 200ms total reveal — slow enough to land an aesthetic on the first frame, fast enough that the operator never feels it as lag. 3. **Confirm-twice for LUKS + admin password** (commit `767fe71`) Re-prompt LUKS passphrase + admin password, string-compare, reject mismatch. A typo in the LUKS passphrase is unrecoverable (the disk is unmountable without it; we don't escrow). Catches keyboard-layout surprises before they brick the install. 4. **10s reboot countdown** (commit `138a047`) Replace the static `sleep 5` with a 10 → 1 redraw loop printing the remaining seconds via `clear` + `gum style` each tick. 10s (vs 5s) because operators were missing the eject window — laptops with the USB on the far side of the dock take 4-5s to physically reach. 5. **Eject-media reminder promoted to its own box** (commit `b64ee19`) The reminder used to be one line buried inside the green success box and operators routinely missed it. It is now its own loud yellow thick-bordered gum-style box stacked directly below the success/countdown box, with three explanatory lines, redrawn for the full 10s of the countdown. ### Before / after pseudo-screenshot #### Before — v0.5.32 password screen (broken) ``` ┌────────────────────────────┐ │ [2/3] Encryption · LUKS2 │ <- header │ ********T │ <- stray T from previous menu state │ │ <- duplicate "Install" rendered behind │ Install │ due to bubbletea screen-restore └────────────────────────────┘ ``` #### After — v0.6 password screen (clean) ``` ╭───────────────────────────────────────╮ │ [2/3] Encryption · LUKS2 passphrase │ ╰───────────────────────────────────────╯ password: _ (re-prompt on confirm + mismatch loop until match) ``` #### Before — v0.5.32 success screen ``` ╭──────────────────────────────╮ │ ✓ Install complete │ │ │ │ System will reboot in 5 secs │ │ Remove the install media. │ <- one buried line, missed ╰──────────────────────────────╯ ``` #### After — v0.6 success screen ``` ╭─────────────────────────────╮ │ ✓ Install complete │ │ │ │ Rebooting in 7s... │ ╰─────────────────────────────╯ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━���━━━━━━━━━━━━━━━━━━━┓ ┃ Remove the install media NOW ┃ <- own loud yellow box ┃ ┃ ┃ Unplug the USB stick / eject the DVD ┃ ┃ before reboot, otherwise the system will ┃ ┃ boot back into the live ISO instead of ┃ ┃ your fresh install. ┃ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ``` ### Notes on duplicate "Install" investigation Task brief asked whether the duplicate-"Install" warranted a `gum choose` → `select` swap. **Conclusion: no swap needed.** `main_menu()` only contains ONE "Install" entry. The duplicate render was bubbletea's screen-restore replaying the previous menu buffer onto the password screen — fixing the password screen (fix 1) eliminates the artefact at its source. `gum choose` itself renders cleanly on the framebuffer because it doesn't go through the read-then-restore path that `gum input --password` uses. ### Test plan - [ ] `bash -n overlay/usr/local/bin/veilor-installer` (passes locally) - [ ] Boot live ISO in QEMU; confirm banner staged reveal at install boot - [ ] Step into Install; enter LUKS pw with no glitch; mismatched confirm rejects with red box; matching confirm proceeds - [ ] Same for admin pw - [ ] Let install complete; confirm two stacked boxes, countdown ticks 10 → 1, system reboots - [ ] Whiptail fallback path unchanged — verify with `TUI=whiptail veilor-installer` on minimal image ### Constraints honoured - One file touched (`overlay/usr/local/bin/veilor-installer`) - One commit per fix - Pushed to `nullstone` (Forgejo) only, NOT to `origin` (GitHub) - `bash -n` clean
s8n added 5 commits 2026-05-06 10:33:59 +01:00
`gum input --password` corrupts the linux fbcon since v0.5.27 — the
bubbletea screen-restore writes back the previous menu buffer because
the framebuffer terminfo entry lacks `civis/cnorm` cursor-hide
sequences, leaving a duplicate "Install" plus a stray "T" rendered on
top of the password field. The fix is a single termios echo-off via
`read -srp`: no redraw, no glitch, no dependency on gum's TUI layer
for the one screen where it broke.

Header still rendered through `gum style` so visual parity with the
disk picker / confirm box is preserved. Whiptail fallback path
unchanged (passwordbox there has always rendered cleanly).
Read banner.txt line by line with a 40ms sleep between each, then
clear and redraw the bordered gum-style version. 5-line banner ×
40ms = 200ms total reveal — slow enough to land an aesthetic on the
first frame, fast enough that the operator never feels it as lag.

Pure cosmetic; no functional change to the install flow.
A typo in the LUKS passphrase is unrecoverable — the disk is
unmountable without it and we don't escrow the key. Re-prompting
until the two reads match catches keyboard-layout surprises (the
US/UK quote-key position is the most common one) before they brick
the install.

Admin password gets the same treatment for consistency. Less
catastrophic (resettable from a recovery shell) but a mismatch
still locks the user out of their fresh install on first boot.

Loop bails on cancel/ESC and re-prompts on validate_pw failure.
v0.5 used `sleep 5` after a static "System will reboot in 5 seconds."
box, which left the operator guessing how much time was left to grab
the USB stick. The new loop runs 10 → 1, clearing + redrawing the
gum-style success box each tick with the remaining-seconds figure,
giving the operator a visible window to act.

10 seconds (vs 5) because real hardware operators were missing the
window — laptops with the USB on the far side of the dock take
4-5 seconds to physically reach. 10 is comfortable, not annoying.
feat(installer): promote eject-media reminder to its own box
Some checks failed
Lint / Kickstart syntax (pull_request) Failing after 3s
Lint / Shell scripts (pull_request) Failing after 39s
Lint / No personal/onyx leaks (pull_request) Failing after 29s
b64ee19e53
In v0.5 the "Remove the install media" reminder was a single line
inside the green success box, and operators on both onyx and the
friend's RTX 4080 rig missed it — rebooted into the live ISO and
re-ran the installer thinking the install had silently failed.

Promote the reminder to its own loud yellow thick-bordered gum-style
box stacked directly below the success/countdown box, with three
lines of explanation. Renders for the full 10s of the countdown so
it stays in the operator's face the entire window.
s8n merged commit 8b1b49b5fc into main 2026-05-06 13:47:35 +01:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: veilor-org/veilor-os#3
No description provided.