From 9c0b716758b12dd9bb71a2596228bc1edc14f656 Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Tue, 27 Oct 2026 22:32:58 +0100 Subject: [PATCH 1/6] Status blocks replace the spinner: blue breathing / green / red MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ui_quiet_run now paints a TTY-safe status BLOCK: a background-coloured SPACE (never a glyph, no font/locale dependency — the braille lesson). busy : blue block breathing through a 256-colour ramp (48;5;17..33) with the live dnf action after it ok : solid green block + package count fail : solid RED block (spec: YuKu changed the red X to a red block) followed by the log tail Colour-depth aware: 256-colour ramp -> 16-colour blue/bright-blue -> plain ASCII spinner when the terminal reports no colour. LANG=C pty run shows zero non-ASCII bytes. Also vendors lib/ui-block.sh (the standalone helper from the Telegram session prototype; fail changed to red block) and installs the ui_block_close EXIT trap — with a return 0, because an EXIT trap's status becomes the script's exit code (harness caught every-successful- run exiting 1 through that path). --- lib/common.sh | 61 ++++++++++++++++++------- lib/ui-block.sh | 115 ++++++++++++++++++++++++++++++++++++++++++++++++ setup.sh | 4 ++ 3 files changed, 165 insertions(+), 15 deletions(-) create mode 100644 lib/ui-block.sh diff --git a/lib/common.sh b/lib/common.sh index df27987..d515ab6 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -101,43 +101,74 @@ ui_quiet_run() { before=$(wc -l < "$log" 2>/dev/null || echo 0) - # Child writes to the log; we draw a LIVE line: spinner frame + the package - # dnf is currently working on. gum spin was tried here first but rendered - # as a frozen block on the real VM ("looks like it hangs") — this variant - # animates independently of gum and shows real progress, not just motion. + # ---- status BLOCK (TTY-safe: a background-coloured SPACE, never a glyph) -- + # busy: blue block that breathes (bg-colour ramp) + current dnf action + # ok : solid green block + package count + # fail: solid RED block (spec change from the X, per YuKu) + # Colour-depth aware: 256 -> ramp, 16 -> blue/bright-blue, none -> ASCII. + local depth=0 nc + nc=$(tput colors 2>/dev/null || echo 0) + case "$nc" in ''|*[!0-9]*) nc=0 ;; esac + if (( nc >= 256 )); then depth=256 + elif (( nc >= 8 )); then depth=16 + fi + + local -a bg=() + case "$depth" in + 256) bg=( "48;5;17" "48;5;19" "48;5;21" "48;5;27" "48;5;33" "48;5;27" "48;5;21" "48;5;19" ) ;; + 16) bg=( "44" "104" "44" "104" ) ;; + esac + local -a ch=( "|" "/" "-" "\\" ) + "$@" >>"$log" 2>&1 & local pid=$! - # ASCII frames ONLY: braille/em-dash are multibyte UTF-8 and rendered as - # garbage letters when the session locale is not UTF-8 (VM-proven: the - # spinner appeared as changing random chars, not as a spinner). - local frames=( '|' '/' '-' '\\' ) local f=0 cur while kill -0 "$pid" 2>/dev/null; do cur=$(sed -n "$((before+1)),\$p" "$log" 2>/dev/null \ | grep -E '^(Installing|Upgrading|Downgrading|Removing|Verifying|Preparing|Cleanup):' \ | tail -n 1 || true) - if [[ -n "$cur" ]]; then - printf '\r %s %s: %s' "${frames[$f]}" "$msg" "$cur" >&2 + if (( depth >= 16 )); then + if [[ -n "$cur" ]]; then + printf '\r\033[%sm \033[0m %s: %s' "${bg[$(( f % ${#bg[@]} ))]}" "$msg" "$cur" >&2 + else + printf '\r\033[%sm \033[0m %s' "${bg[$(( f % ${#bg[@]} ))]}" "$msg" >&2 + fi else - printf '\r %s %s' "${frames[$f]}" "$msg" >&2 + if [[ -n "$cur" ]]; then + printf '\r %s %s: %s' "${ch[$(( f % ${#ch[@]} ))]}" "$msg" "$cur" >&2 + else + printf '\r %s %s' "${ch[$(( f % ${#ch[@]} ))]}" "$msg" >&2 + fi fi - f=$(( (f + 1) % ${#frames[@]} )) + f=$(( f + 1 )) sleep 0.15 done local rc=0 wait "$pid" || rc=$? - # wipe the progress line before printing the result printf '\r%*s\r' 100 '' >&2 if (( rc == 0 )); then n=$(sed -n "$((before+1)),\$p" "$log" 2>/dev/null | grep -c '^Installing:' || true) local plural="s" (( n == 1 )) && plural="" - ok "$msg (${n} package${plural})" + if (( depth == 256 )); then + printf '\033[48;5;34m \033[0m %s (%s package%s)\n' "$msg" "$n" "$plural" >&2 + elif (( depth == 16 )); then + printf '\033[42m \033[0m %s (%s package%s)\n' "$msg" "$n" "$plural" >&2 + else + ok "$msg (${n} package${plural})" + fi return 0 else - color_red " Failed: $msg" + if (( depth == 256 )); then + printf '\033[48;5;196m \033[0m %s\n' "$msg" >&2 + elif (( depth == 16 )); then + printf '\033[41m \033[0m %s\n' "$msg" >&2 + else + color_red " Failed: $msg" + fi + color_red " (dnf reported a transaction failure)" color_red " Last lines from $log:" sed -n "$((before+1)),\$p" "$log" 2>/dev/null | tail -n 20 | sed 's/^/ /' >&2 return "$rc" diff --git a/lib/ui-block.sh b/lib/ui-block.sh new file mode 100644 index 0000000..259b850 --- /dev/null +++ b/lib/ui-block.sh @@ -0,0 +1,115 @@ +#!/usr/bin/env bash +# ui-block.sh - TTY-safe status "block" indicator (no special fonts) +# +# busy : blue block that "breathes" (background colour pulses) +# ok : solid green block +# fail : solid red block (changed from red X per YuKu's spec) +# +# Why this works on a bare TTY: the "block" is a BACKGROUND-COLOURED SPACE, +# not a U+2588 glyph. No fonts, no UTF-8, no locale dependency. +# +# Draws on /dev/tty, never stdout: ui_choose/ui_confirm capture stdout with $(), +# so a status line on stdout would corrupt every captured answer. + +_UB_FD="" +_UB_PID="" +_UB_MSG="" + +_ub_tty() { + if [[ -z "$_UB_FD" ]]; then + # probe first: a bare `exec {fd}>/dev/tty` failure still prints its error + { : >/dev/tty; } 2>/dev/null || { _UB_FD=""; return 1; } + exec {_UB_FD}>/dev/tty 2>/dev/null || { _UB_FD=""; return 1; } + fi + [[ -n "$_UB_FD" ]] +} + +_ub_depth() { + local n + n=$(tput colors 2>/dev/null || echo 0) + case "$n" in ''|*[!0-9]*) n=0 ;; esac + if [[ "$n" -ge 256 ]]; then echo 256 + elif [[ "$n" -ge 8 ]]; then echo 16 + else echo 0; fi +} + +# paint one background-coloured block (a SPACE) + message +_ub_paint() { + printf '\r\033[%sm \033[0m %s' "$1" "$2" >&"$_UB_FD" +} + +_ub_busy_loop() { + local depth pal=() i + depth=$(_ub_depth) + case "$depth" in + 256) pal=(17 18 19 20 21 27 33 27 21 20 19 18) ;; # blue breathe + 16) pal=(44 104 44 104) ;; # blue / bright blue + *) pal=("|" "/" "-" "\\") ;; # last-resort spinner + esac + while :; do + for i in "${pal[@]}"; do + if [[ "$depth" -eq 256 ]]; then + _ub_paint "48;5;$i" "$_UB_MSG" # 256-colour cube background + elif [[ "$depth" -eq 16 ]]; then + _ub_paint "$i" "$_UB_MSG" # plain ANSI background (44/104) + else + printf '\r[%s] %s' "$i" "$_UB_MSG" >&"$_UB_FD" + fi + sleep 0.08 || return 0 + done + done +} + +_ub_stop() { + if [[ -n "$_UB_PID" ]]; then + kill "$_UB_PID" 2>/dev/null + wait "$_UB_PID" 2>/dev/null + _UB_PID="" + fi +} + +ui_block_start() { + _UB_MSG="${1:-Working}" + _ub_tty || return 0 # no tty: silent no-op + _ub_stop + _ub_busy_loop & + _UB_PID=$! +} + +ui_block_ok() { + local msg="${1:-Done}" d + _ub_tty || return 0 + _ub_stop + d=$(_ub_depth) + case "$d" in + 256) _ub_paint "48;5;34" "$msg" ;; + 16) _ub_paint "42" "$msg" ;; + *) printf '\r[OK] %s' "$msg" >&"$_UB_FD" ;; + esac + printf '\033[0m\n' >&"$_UB_FD" +} + +ui_block_fail() { + local msg="${1:-Failed}" d + _ub_tty || return 0 + _ub_stop + d=$(_ub_depth) + case "$d" in + 256) printf '\r\033[48;5;196m \033[0m %s' "$msg" >&"$_UB_FD" ;; + 16) printf '\r\033[41m \033[0m %s' "$msg" >&"$_UB_FD" ;; + *) printf '\r[!] %s' "$msg" >&"$_UB_FD" ;; + esac + printf '\n' >&"$_UB_FD" +} + +ui_block_close() { + _ub_stop + if [[ -n "$_UB_FD" ]]; then + exec {_UB_FD}>&- 2>/dev/null + _UB_FD="" + fi + return 0 # an EXIT trap's status becomes the script's exit code — never fail here +} + +# ALWAYS install a cleanup trap in the sourcing script: +# trap 'ui_block_close' EXIT INT TERM diff --git a/setup.sh b/setup.sh index d35e86f..ca8561a 100755 --- a/setup.sh +++ b/setup.sh @@ -12,6 +12,10 @@ source "$SCRIPT_DIR/lib/common.sh" source "$SCRIPT_DIR/lib/session.sh" # shellcheck source=lib/ui.sh source "$SCRIPT_DIR/lib/ui.sh" +# shellcheck source=lib/ui-block.sh +source "$SCRIPT_DIR/lib/ui-block.sh" +# never leave a block pulse loop running if the script is interrupted +trap 'ui_block_close' EXIT INT TERM # Full dnf output from quiet transactions lands here (shown on failure). export SETUP_DNF_LOG="${SETUP_DNF_LOG:-/tmp/fedora-setup-dnf-$(id -u).log}" -- 2.47.3 From 35906d4df03c5b217649d7d61596fada73f400ba Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Tue, 27 Oct 2026 22:35:35 +0100 Subject: [PATCH 2/6] Breathing pulse: 3x faster (0.15s -> 0.05s per frame) YuKu: 'the breathing is super slow'. Frame interval down from 150ms to 50ms (~7fps -> ~20fps pulse). Same change in the vendored lib/ui-block.sh helper for consistency. --- lib/common.sh | 2 +- lib/ui-block.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/common.sh b/lib/common.sh index d515ab6..6961e1e 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -141,7 +141,7 @@ ui_quiet_run() { fi fi f=$(( f + 1 )) - sleep 0.15 + sleep 0.05 done local rc=0 diff --git a/lib/ui-block.sh b/lib/ui-block.sh index 259b850..e0d623c 100644 --- a/lib/ui-block.sh +++ b/lib/ui-block.sh @@ -55,7 +55,7 @@ _ub_busy_loop() { else printf '\r[%s] %s' "$i" "$_UB_MSG" >&"$_UB_FD" fi - sleep 0.08 || return 0 + sleep 0.05 || return 0 done done } -- 2.47.3 From 3d21a1c42728cc483c6c970f3aa6e15d91b17404 Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Tue, 27 Oct 2026 22:38:02 +0100 Subject: [PATCH 3/6] Breathing: deep amplitude so the pulse survives flicker fusion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At 20fps the previous narrow ramp (shades 17-33) flicker-fused into an apparent SOLID block on the VM. Amplitude now spans dark navy (17) to bright blue (45) in 12 steps — every frame is visibly different, cycle is 0.6s. Speed unchanged. --- lib/common.sh | 5 ++++- lib/ui-block.sh | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/common.sh b/lib/common.sh index 6961e1e..e5568a2 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -115,7 +115,10 @@ ui_quiet_run() { local -a bg=() case "$depth" in - 256) bg=( "48;5;17" "48;5;19" "48;5;21" "48;5;27" "48;5;33" "48;5;27" "48;5;21" "48;5;19" ) ;; + # Deep-amplitude breathe: dark navy (17) to BRIGHT blue (45). Adjacent + # shades must differ enough to survive flicker fusion — a subtle ramp + # at 20fps reads as a solid block (VM-proven). + 256) bg=( "48;5;17" "48;5;19" "48;5;21" "48;5;27" "48;5;33" "48;5;39" "48;5;45" "48;5;39" "48;5;33" "48;5;27" "48;5;21" "48;5;19" ) ;; 16) bg=( "44" "104" "44" "104" ) ;; esac local -a ch=( "|" "/" "-" "\\" ) diff --git a/lib/ui-block.sh b/lib/ui-block.sh index e0d623c..bc08152 100644 --- a/lib/ui-block.sh +++ b/lib/ui-block.sh @@ -42,7 +42,7 @@ _ub_busy_loop() { local depth pal=() i depth=$(_ub_depth) case "$depth" in - 256) pal=(17 18 19 20 21 27 33 27 21 20 19 18) ;; # blue breathe + 256) pal=(17 19 21 27 33 39 45 39 33 27 21 19) ;; # deep breathe: dark navy to bright blue 16) pal=(44 104 44 104) ;; # blue / bright blue *) pal=("|" "/" "-" "\\") ;; # last-resort spinner esac -- 2.47.3 From 71780291a3c4c5f709bbb587172ceba93a4191ff Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Tue, 27 Oct 2026 22:41:48 +0100 Subject: [PATCH 4/6] TTY: on/off block pulse on the Linux console (shade fusion defeated) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit YuKu tests on the bare Linux VT (not a terminal emulator): my 16-colour fallback alternated blue (44) / bright blue (104), which render nearly identically on VGA consoles -> fused into 'solid blue'. If TERM misreports 256, 48;5;N codes are ignored outright. Fixes: - TERM linux*/console* forces the 16-colour path regardless of tput. - 16-colour mode now PULSES THE BLOCK ON/OFF (2 frames blue block, 2 frames no block, ~2.5Hz) instead of shade alternation — visible on any console hardware, no colour fidelity required. - 256-colour terminals keep the deep 17->45 breathe ramp. Verified: TERM=linux pty shows block/no-block alternation with zero 48;5 codes; TERM=xterm-256color keeps the 8-shade ramp; unattended + piped regressions green. --- lib/common.sh | 24 ++++++++++++++++++++---- lib/ui-block.sh | 10 ++++++++-- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/lib/common.sh b/lib/common.sh index e5568a2..9426176 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -112,6 +112,10 @@ ui_quiet_run() { if (( nc >= 256 )); then depth=256 elif (( nc >= 8 )); then depth=16 fi + # The bare Linux VT is 16-color VGA: 48;5;N codes are ignored there, and + # its blue/bright-blue backgrounds render nearly identically (VM-proven: + # "solid blue, no breathing" on the console). Cap to the 16-color path. + case "${TERM:-}" in linux*|console*) depth=16 ;; esac local -a bg=() case "$depth" in @@ -119,7 +123,9 @@ ui_quiet_run() { # shades must differ enough to survive flicker fusion — a subtle ramp # at 20fps reads as a solid block (VM-proven). 256) bg=( "48;5;17" "48;5;19" "48;5;21" "48;5;27" "48;5;33" "48;5;39" "48;5;45" "48;5;39" "48;5;33" "48;5;27" "48;5;21" "48;5;19" ) ;; - 16) bg=( "44" "104" "44" "104" ) ;; + # On/off pulse, NOT shade alternation: console blues fuse to solid. + # Empty element = frame without the block (block breathes in/out). + 16) bg=( "44" "44" "" "" ) ;; esac local -a ch=( "|" "/" "-" "\\" ) @@ -131,10 +137,20 @@ ui_quiet_run() { | grep -E '^(Installing|Upgrading|Downgrading|Removing|Verifying|Preparing|Cleanup):' \ | tail -n 1 || true) if (( depth >= 16 )); then - if [[ -n "$cur" ]]; then - printf '\r\033[%sm \033[0m %s: %s' "${bg[$(( f % ${#bg[@]} ))]}" "$msg" "$cur" >&2 + local code="${bg[$(( f % ${#bg[@]} ))]}" + if [[ -n "$code" ]]; then + if [[ -n "$cur" ]]; then + printf '\r\033[%sm \033[0m %s: %s' "$code" "$msg" "$cur" >&2 + else + printf '\r\033[%sm \033[0m %s' "$code" "$msg" >&2 + fi else - printf '\r\033[%sm \033[0m %s' "${bg[$(( f % ${#bg[@]} ))]}" "$msg" >&2 + # block "breathes out": just the text that frame + if [[ -n "$cur" ]]; then + printf '\r %s: %s' "$msg" "$cur" >&2 + else + printf '\r %s' "$msg" >&2 + fi fi else if [[ -n "$cur" ]]; then diff --git a/lib/ui-block.sh b/lib/ui-block.sh index bc08152..f5d36a6 100644 --- a/lib/ui-block.sh +++ b/lib/ui-block.sh @@ -31,6 +31,8 @@ _ub_depth() { if [[ "$n" -ge 256 ]]; then echo 256 elif [[ "$n" -ge 8 ]]; then echo 16 else echo 0; fi + # bare Linux VT: cap regardless of what tput reports + case "${TERM:-}" in linux*|console*) echo 16 ;; esac } # paint one background-coloured block (a SPACE) + message @@ -43,7 +45,7 @@ _ub_busy_loop() { depth=$(_ub_depth) case "$depth" in 256) pal=(17 19 21 27 33 39 45 39 33 27 21 19) ;; # deep breathe: dark navy to bright blue - 16) pal=(44 104 44 104) ;; # blue / bright blue + 16) pal=(44 44 "" "") ;; # on/off pulse: console blues fuse *) pal=("|" "/" "-" "\\") ;; # last-resort spinner esac while :; do @@ -51,7 +53,11 @@ _ub_busy_loop() { if [[ "$depth" -eq 256 ]]; then _ub_paint "48;5;$i" "$_UB_MSG" # 256-colour cube background elif [[ "$depth" -eq 16 ]]; then - _ub_paint "$i" "$_UB_MSG" # plain ANSI background (44/104) + if [[ -n "$i" ]]; then + _ub_paint "$i" "$_UB_MSG" # plain ANSI background (blue) + else + printf '\r %s' "$_UB_MSG" >&"$_UB_FD" # block breathes out + fi else printf '\r[%s] %s' "$i" "$_UB_MSG" >&"$_UB_FD" fi -- 2.47.3 From 4a53155c7ebba386e2058e193d41a9997254e1c8 Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Tue, 27 Oct 2026 22:45:43 +0100 Subject: [PATCH 5/6] TTY pulse: constant layout, blue <-> dark grey (no more block-off) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The on/off pulse shifted the whole line by one character during the dark frames (off-frame printed one space fewer than the block frame). Per YuKu: keep the block ALWAYS present and alternate its colour instead — blue (44) <-> dark grey (100, bright black). Layout is constant, pulse is colour-based, nothing moves but the block itself. Also: disable_selinux now mkdir -p's /etc/selinux before writing a fresh config (harness caught a die on a missing parent dir). --- lib/common.sh | 25 ++++++++++--------------- lib/ui-block.sh | 8 ++------ 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/lib/common.sh b/lib/common.sh index 9426176..db04d3c 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -123,9 +123,10 @@ ui_quiet_run() { # shades must differ enough to survive flicker fusion — a subtle ramp # at 20fps reads as a solid block (VM-proven). 256) bg=( "48;5;17" "48;5;19" "48;5;21" "48;5;27" "48;5;33" "48;5;39" "48;5;45" "48;5;39" "48;5;33" "48;5;27" "48;5;21" "48;5;19" ) ;; - # On/off pulse, NOT shade alternation: console blues fuse to solid. - # Empty element = frame without the block (block breathes in/out). - 16) bg=( "44" "44" "" "" ) ;; + # Colour pulse with CONSTANT layout: blue <-> dark grey (bright black). + # Never remove the block on a frame — a missing block shifted the + # whole line by one char on the console (VM-proven). + 16) bg=( "44" "44" "100" "100" ) ;; esac local -a ch=( "|" "/" "-" "\\" ) @@ -138,19 +139,10 @@ ui_quiet_run() { | tail -n 1 || true) if (( depth >= 16 )); then local code="${bg[$(( f % ${#bg[@]} ))]}" - if [[ -n "$code" ]]; then - if [[ -n "$cur" ]]; then - printf '\r\033[%sm \033[0m %s: %s' "$code" "$msg" "$cur" >&2 - else - printf '\r\033[%sm \033[0m %s' "$code" "$msg" >&2 - fi + if [[ -n "$cur" ]]; then + printf '\r\033[%sm \033[0m %s: %s' "$code" "$msg" "$cur" >&2 else - # block "breathes out": just the text that frame - if [[ -n "$cur" ]]; then - printf '\r %s: %s' "$msg" "$cur" >&2 - else - printf '\r %s' "$msg" >&2 - fi + printf '\r\033[%sm \033[0m %s' "$code" "$msg" >&2 fi else if [[ -n "$cur" ]]; then @@ -357,6 +349,9 @@ disable_selinux() { sudo cp "$cfg" "${cfg}.bkp.$(date +%F)" sudo sed -i 's/^SELINUX=.*/SELINUX=disabled/' "$cfg" else + # belt-and-suspenders: on real Fedora /etc/selinux always exists, but + # do not die if it somehow does not + sudo mkdir -p "$(dirname "$cfg")" printf 'SELINUX=disabled\nSELINUXTYPE=targeted\n' | sudo tee "$cfg" >/dev/null fi ok "SELINUX=disabled written to $cfg (backup saved). Reboot to apply." diff --git a/lib/ui-block.sh b/lib/ui-block.sh index f5d36a6..7210ecf 100644 --- a/lib/ui-block.sh +++ b/lib/ui-block.sh @@ -45,7 +45,7 @@ _ub_busy_loop() { depth=$(_ub_depth) case "$depth" in 256) pal=(17 19 21 27 33 39 45 39 33 27 21 19) ;; # deep breathe: dark navy to bright blue - 16) pal=(44 44 "" "") ;; # on/off pulse: console blues fuse + 16) pal=(44 44 100 100) ;; # blue <-> dark grey, constant layout *) pal=("|" "/" "-" "\\") ;; # last-resort spinner esac while :; do @@ -53,11 +53,7 @@ _ub_busy_loop() { if [[ "$depth" -eq 256 ]]; then _ub_paint "48;5;$i" "$_UB_MSG" # 256-colour cube background elif [[ "$depth" -eq 16 ]]; then - if [[ -n "$i" ]]; then - _ub_paint "$i" "$_UB_MSG" # plain ANSI background (blue) - else - printf '\r %s' "$_UB_MSG" >&"$_UB_FD" # block breathes out - fi + _ub_paint "$i" "$_UB_MSG" # blue <-> dark grey pulse else printf '\r[%s] %s' "$i" "$_UB_MSG" >&"$_UB_FD" fi -- 2.47.3 From 0630acf0203b2b01f28cd971d7872bc6d3609460 Mon Sep 17 00:00:00 2001 From: Pathfinder Date: Tue, 27 Oct 2026 22:48:50 +0100 Subject: [PATCH 6/6] Console pulse: one-third speed (150ms frames), 256-ramp untouched MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit YuKu: 'slow the flicker a bit (half or one-third speed)'. The 16-colour blue<->grey pulse now ticks at 150ms (600ms full cycle, calm); the 256-colour terminal breathe keeps its 50ms deep ramp. Per-depth tick variable; same in the vendored helper. Rate proven by pty trace: 8 frames in a 1.2s transaction = 150ms exactly. (Frame-counting via grep -c undercounts — \r overwrites collapse frames onto one line; count matches, not lines.) --- lib/common.sh | 8 +++++++- lib/ui-block.sh | 5 +++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/common.sh b/lib/common.sh index db04d3c..219d35b 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -117,6 +117,12 @@ ui_quiet_run() { # "solid blue, no breathing" on the console). Cap to the 16-color path. case "${TERM:-}" in linux*|console*) depth=16 ;; esac + # Per-depth frame interval: the console colour-pulse runs slower (a fast + # blue/grey flip reads as flicker — YuKu asked for half-to-third speed); + # the 256-colour breathe ramp keeps its 50ms. + local tick=0.05 + (( depth == 16 )) && tick=0.15 + local -a bg=() case "$depth" in # Deep-amplitude breathe: dark navy (17) to BRIGHT blue (45). Adjacent @@ -152,7 +158,7 @@ ui_quiet_run() { fi fi f=$(( f + 1 )) - sleep 0.05 + sleep "$tick" done local rc=0 diff --git a/lib/ui-block.sh b/lib/ui-block.sh index 7210ecf..6845b7f 100644 --- a/lib/ui-block.sh +++ b/lib/ui-block.sh @@ -41,8 +41,9 @@ _ub_paint() { } _ub_busy_loop() { - local depth pal=() i + local depth pal=() i tick=0.05 depth=$(_ub_depth) + [[ "$depth" -eq 16 ]] && tick=0.15 # console pulse: slow, not flicker case "$depth" in 256) pal=(17 19 21 27 33 39 45 39 33 27 21 19) ;; # deep breathe: dark navy to bright blue 16) pal=(44 44 100 100) ;; # blue <-> dark grey, constant layout @@ -57,7 +58,7 @@ _ub_busy_loop() { else printf '\r[%s] %s' "$i" "$_UB_MSG" >&"$_UB_FD" fi - sleep 0.05 || return 0 + sleep "$tick" || return 0 done done } -- 2.47.3