feat(plymouth): centred skull logo + boot-log tail, drop spinner

Rework the M-Archy splash: scale the skull to ~42% of screen height and
centre it instead of filling the screen, then draw the latest 3 boot-log
lines beneath it (fed by both the status and display-message callbacks).
Drops the imagemagick-generated dot.png throbber and its refresh loop.

Render the logo at 600px (down from 1920px) since it is no longer
full-screen, and only pull in imagemagick for the transparent-placeholder
fallback. migrate-to-lightdm purges the stale dot.png before re-running the
module so upgraded installs end up byte-clean. Update docs and module
labels ("skull logo + boot-log tail"), and simplify bg-skull.svg.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
feat/astal-menu
Amir Alexander Abdelbaki 2026-07-04 03:18:44 +02:00
parent 29f6c62008
commit 48c756d3e2
9 changed files with 103 additions and 138 deletions

View File

@ -35,7 +35,7 @@ The TUI walks you through:
- `core` — 100+ base system packages - `core` — 100+ base system packages
- `svc` — core services (NetworkManager, cronie, fail2ban, greetd) - `svc` — core services (NetworkManager, cronie, fail2ban, greetd)
- `shell` — zsh, Neovim, Yazi, Micro, Starship - `shell` — zsh, Neovim, Yazi, Micro, Starship
- `plymouth` — boot splash screen (skull logo + magenta spinner, **on by default**) - `plymouth` — boot splash screen (skull logo + boot-log tail, **on by default**)
3. **Desktop Environment** — HyprLua, Niri, Hyprland, Sway, KDE Plasma, GNOME, COSMIC, XFCE, LXQt, or none 3. **Desktop Environment** — HyprLua, Niri, Hyprland, Sway, KDE Plasma, GNOME, COSMIC, XFCE, LXQt, or none
4. **Applications** — checklist of ~50 optional apps (see [Modules](modules.md)) 4. **Applications** — checklist of ~50 optional apps (see [Modules](modules.md))
5. **Colorway** — optional; enter hex values to customise the CyberQueer palette 5. **Colorway** — optional; enter hex values to customise the CyberQueer palette

View File

@ -133,7 +133,7 @@ bash ~/Dotfiles/setup/install-modules.sh
| `timeshift` | system snapshot and backup with autosnap | | `timeshift` | system snapshot and backup with autosnap |
| `zfs` | zfs-dkms kernel module | | `zfs` | zfs-dkms kernel module |
| `wprs` | Wayland proxy for remote sessions (wprs-git, AUR) | | `wprs` | Wayland proxy for remote sessions (wprs-git, AUR) |
| `plymouth` | boot splash — bundled skull logo and spinner | | `plymouth` | boot splash — bundled skull logo + boot-log tail |
| `plymouth-custom` | boot splash with a user-supplied image | | `plymouth-custom` | boot splash with a user-supplied image |
| `lightdm` | LightDM GTK greeter, cyberqueer-themed (HyprLua default) | | `lightdm` | LightDM GTK greeter, cyberqueer-themed (HyprLua default) |
| `ly` | ly TUI display manager, cyberqueer-themed | | `ly` | ly TUI display manager, cyberqueer-themed |

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -212,7 +212,7 @@ SELECTED=$(dialog --backtitle "$BACKTITLE" \
"ffmpeg" "FFmpeg extras thumbnailer · GStreamer codecs" off \ "ffmpeg" "FFmpeg extras thumbnailer · GStreamer codecs" off \
"localtunnel" "LocalTunnel expose localhost via tunnel" off \ "localtunnel" "LocalTunnel expose localhost via tunnel" off \
"butter" "butter btrfs snapshot backup (AUR)" off \ "butter" "butter btrfs snapshot backup (AUR)" off \
"plymouth" "Plymouth boot splash — skull logo + spinner" off \ "plymouth" "Plymouth boot splash — skull logo + boot-log tail" off \
"plymouth-custom" "Plymouth (custom) boot splash — supply your own image" off \ "plymouth-custom" "Plymouth (custom) boot splash — supply your own image" off \
"lightdm" "LightDM GTK greeter, cyberqueer-themed" off \ "lightdm" "LightDM GTK greeter, cyberqueer-themed" off \
"ly" "ly TUI display manager, cyberqueer" off \ "ly" "ly TUI display manager, cyberqueer" off \

View File

@ -49,7 +49,7 @@ localtunnel|system|expose localhost over a public URL|off|
timeshift|system|system snapshot and backup with autosnap|on| timeshift|system|system snapshot and backup with autosnap|on|
zfs|system|zfs-dkms kernel module|off| zfs|system|zfs-dkms kernel module|off|
wprs|system|Wayland proxy for remote sessions (wprs-git, AUR)|off| wprs|system|Wayland proxy for remote sessions (wprs-git, AUR)|off|
plymouth|system|boot splash — bundled skull logo and spinner|on|plymouth-custom plymouth|system|boot splash — bundled skull logo + boot-log tail|on|plymouth-custom
plymouth-custom|system|boot splash with a user-supplied image|off|plymouth plymouth-custom|system|boot splash with a user-supplied image|off|plymouth
lightdm|system|LightDM GTK greeter, cyberqueer-themed (HyprLua default)|off|ly lightdm|system|LightDM GTK greeter, cyberqueer-themed (HyprLua default)|off|ly
ly|system|ly TUI display manager, cyberqueer-themed|off|lightdm ly|system|ly TUI display manager, cyberqueer-themed|off|lightdm

View File

@ -1,9 +1,9 @@
#!/bin/bash #!/bin/bash
# plymouth.sh — Plymouth boot splash installer # plymouth.sh — Plymouth boot splash installer
# #
# Installs the M-Archy Plymouth theme: the transparent skull/CRT artwork scaled # Installs the M-Archy Plymouth theme: the magenta skull-monitor logo centred
# to fill the screen over a dark background, with a magenta spinning-dot # on a dark background, with the latest 3 boot-log lines polled underneath it
# animation near the bottom. # as plain text (no spinner).
# #
# SVG NOTE: Plymouth's image loader (ply-image) is PNG-only — it links against # SVG NOTE: Plymouth's image loader (ply-image) is PNG-only — it links against
# libpng and has no SVG or gdk-pixbuf dependency. The ply-image.h header is # libpng and has no SVG or gdk-pixbuf dependency. The ply-image.h header is
@ -19,14 +19,13 @@
# #
# Steps: # Steps:
# 1. Install plymouth (extra repo) # 1. Install plymouth (extra repo)
# 2. Install librsvg (rsvg-convert) if logo is SVG; imagemagick for dot # 2. Install librsvg (rsvg-convert) if logo is SVG
# 3. Produce logo.png (native 1920 px wide) from the resolved source # 3. Produce logo.png (600 px wide) from the resolved source
# 4. Generate a 10×10 magenta dot.png for the spinner # 4. Write the m-archy theme (.plymouth descriptor + .script animation)
# 5. Write the m-archy theme (.plymouth descriptor + .script animation) # 5. Register with plymouth-set-default-theme
# 6. Register with plymouth-set-default-theme # 6. Inject plymouth / sd-plymouth hook into /etc/mkinitcpio.conf
# 7. Inject plymouth / sd-plymouth hook into /etc/mkinitcpio.conf # 7. Add 'quiet splash' to GRUB_CMDLINE_LINUX_DEFAULT
# 8. Add 'quiet splash' to GRUB_CMDLINE_LINUX_DEFAULT # 8. Regenerate GRUB config and initramfs
# 9. Regenerate GRUB config and initramfs
set -euo pipefail set -euo pipefail
source "$(dirname "${BASH_SOURCE[0]}")/../../lib/logging.sh" source "$(dirname "${BASH_SOURCE[0]}")/../../lib/logging.sh"
@ -54,22 +53,17 @@ fi
log "Installing Plymouth..." log "Installing Plymouth..."
sudo pacman -S --noconfirm --needed plymouth sudo pacman -S --noconfirm --needed plymouth
# ── Ensure conversion tools ───────────────────────────────────────────────────
# imagemagick is always needed for the spinner dot.
# librsvg (rsvg-convert) is only needed when the logo source is an SVG.
if ! command -v convert &>/dev/null; then
log "Installing imagemagick (dot generation)..."
sudo pacman -S --noconfirm --needed imagemagick
fi
# ── Produce logo.png ────────────────────────────────────────────────────────── # ── Produce logo.png ──────────────────────────────────────────────────────────
TMP_LOGO="$(mktemp /tmp/plymouth-logo.XXXXXX.png)" TMP_LOGO="$(mktemp /tmp/plymouth-logo.XXXXXX.png)"
TMP_DOT="/tmp/plymouth-dot.png" trap 'rm -f "$TMP_LOGO"' EXIT
trap 'rm -f "$TMP_LOGO" "$TMP_DOT"' EXIT
if [[ -z "$LOGO_SRC" ]]; then if [[ -z "$LOGO_SRC" ]]; then
warn "No logo source found — using transparent placeholder." warn "No logo source found — using transparent placeholder."
convert -size 1920x1080 xc:transparent "$TMP_LOGO" if ! command -v convert &>/dev/null; then
log "Installing imagemagick (placeholder generation)..."
sudo pacman -S --noconfirm --needed imagemagick
fi
convert -size 600x600 xc:transparent "$TMP_LOGO"
elif [[ "${LOGO_SRC,,}" == *.png ]]; then elif [[ "${LOGO_SRC,,}" == *.png ]]; then
log "Using PNG directly: $LOGO_SRC" log "Using PNG directly: $LOGO_SRC"
cp "$LOGO_SRC" "$TMP_LOGO" cp "$LOGO_SRC" "$TMP_LOGO"
@ -79,29 +73,22 @@ else
log "Installing librsvg (rsvg-convert) for SVG→PNG conversion..." log "Installing librsvg (rsvg-convert) for SVG→PNG conversion..."
sudo pacman -S --noconfirm --needed librsvg sudo pacman -S --noconfirm --needed librsvg
fi fi
# Render at native width so the full-screen splash keeps detail when the # Render at 600 px wide — the skull is centred (not full-screen), and the
# Plymouth script scales it to the display resolution. # Plymouth script scales it down to a fraction of the display height, so we
log "Converting $LOGO_SRC → PNG (1920 px wide)..." # only need enough resolution to stay crisp on high-DPI panels.
rsvg-convert -w 1920 "$LOGO_SRC" -o "$TMP_LOGO" log "Converting $LOGO_SRC → PNG (600 px wide)..."
rsvg-convert -w 600 "$LOGO_SRC" -o "$TMP_LOGO"
fi fi
# ── Generate spinner dot ──────────────────────────────────────────────────────
# 10×10 magenta circle — centred at (5,5), radius 4 px
convert -size 10x10 xc:transparent \
-fill '#E40046' \
-draw 'circle 5,5 5,1' \
"$TMP_DOT"
# ── Install theme files ─────────────────────────────────────────────────────── # ── Install theme files ───────────────────────────────────────────────────────
log "Installing M-Archy Plymouth theme..." log "Installing M-Archy Plymouth theme..."
sudo mkdir -p "$THEME_DIR" sudo mkdir -p "$THEME_DIR"
sudo cp "$TMP_LOGO" "$THEME_DIR/logo.png" sudo cp "$TMP_LOGO" "$THEME_DIR/logo.png"
sudo cp "$TMP_DOT" "$THEME_DIR/dot.png"
sudo tee "$THEME_DIR/m-archy.plymouth" > /dev/null <<'EOF' sudo tee "$THEME_DIR/m-archy.plymouth" > /dev/null <<'EOF'
[Plymouth Theme] [Plymouth Theme]
Name=M-Archy Name=M-Archy
Description=M-Archy boot splash — skull logo with spinning dots Description=M-Archy boot splash — centred skull logo with a boot-log tail
ModuleName=script ModuleName=script
[script] [script]
@ -110,7 +97,7 @@ ScriptFile=/usr/share/plymouth/themes/m-archy/m-archy.script
EOF EOF
sudo tee "$THEME_DIR/m-archy.script" > /dev/null <<'EOF' sudo tee "$THEME_DIR/m-archy.script" > /dev/null <<'EOF'
# M-Archy Plymouth splash — full-screen skull background + magenta spinner # M-Archy Plymouth splash — centred skull logo + latest 3 boot-log lines.
Window.SetBackgroundTopColor (0.10, 0.10, 0.10); Window.SetBackgroundTopColor (0.10, 0.10, 0.10);
Window.SetBackgroundBottomColor (0.07, 0.07, 0.07); Window.SetBackgroundBottomColor (0.07, 0.07, 0.07);
@ -118,47 +105,65 @@ Window.SetBackgroundBottomColor (0.07, 0.07, 0.07);
screen_width = Window.GetWidth (); screen_width = Window.GetWidth ();
screen_height = Window.GetHeight (); screen_height = Window.GetHeight ();
# Full-screen skull background. bg-skull.svg is a 1920x1080 composition with a # ── Skull logo, centred ───────────────────────────────────────────────────────
# transparent field, so we scale it to fill the display and pin it at the # logo.png is the tight skull-monitor artwork (roughly square). Scale it to a
# origin; the transparent areas reveal the dark background gradient above. # fraction of the screen height, preserving aspect ratio, then centre it and
logo.image = Image ("logo.png"); # nudge it up a little so the log lines below have room to breathe.
scaled = logo.image.Scale (screen_width, screen_height); logo.image = Image ("logo.png");
target_h = screen_height * 0.42;
scale = target_h / logo.image.GetHeight ();
scaled = logo.image.Scale (logo.image.GetWidth () * scale, target_h);
logo.sprite = Sprite (scaled); logo.sprite = Sprite (scaled);
logo.sprite.SetX (0); logo.sprite.SetX ((screen_width - scaled.GetWidth ()) / 2);
logo.sprite.SetY (0); logo.sprite.SetY ((screen_height - scaled.GetHeight ()) / 2 - screen_height * 0.08);
logo.sprite.SetZ (10); logo.sprite.SetZ (10);
# 12-dot spinner near the bottom of the screen. The centre is a fixed fraction # ── Boot-log tail — latest 3 lines ────────────────────────────────────────────
# of the screen height (not derived from the logo size) so it stays put # A rolling buffer of the three most recent status/message strings Plymouth
# regardless of the source image's dimensions. # hands us, drawn as centred text beneath the logo. The newest line is the
num_dots = 12; # brightest; older lines fade back.
dot_r = 5; num_lines = 3;
orbit = 35; line_gap = 26; # px between successive baselines
cx = screen_width / 2; text_top = Math.Int (screen_height * 0.72); # y of the oldest (top) line
cy = Math.Int (screen_height * 0.93);
dot.image = Image ("dot.png");
for (i = 0; i < num_dots; i++) { for (i = 0; i < num_lines; i++) {
dot[i].sprite = Sprite (dot.image); log_line[i] = "";
dot[i].sprite.SetZ (20); log_sprite[i] = Sprite ();
log_sprite[i].SetZ (20);
} }
frame = 0; fun draw_lines () {
for (i = 0; i < num_lines; i++) {
fun refresh_callback () { # Empty slots (before the buffer fills) stay hidden — Image.Text ("")
frame++; # is unreliable across Plymouth versions, so never render it.
step = 2 * Math.Pi / num_dots; if (log_line[i] == "") {
for (i = 0; i < num_dots; i++) { log_sprite[i].SetOpacity (0);
angle = step * i + frame * 0.15; } else {
dot[i].sprite.SetX (Math.Int (cx + Math.Cos (angle) * orbit - dot_r)); shade = 0.40 + 0.25 * i; # 0.40, 0.65, 0.90 top→bottom
dot[i].sprite.SetY (Math.Int (cy + Math.Sin (angle) * orbit - dot_r)); image = Image.Text (log_line[i], shade, shade, shade);
t = (i + Math.Int (frame / 4) % num_dots) % num_dots; log_sprite[i].SetImage (image);
f = t / num_dots; log_sprite[i].SetX ((screen_width - image.GetWidth ()) / 2);
dot[i].sprite.SetOpacity (0.15 + 0.85 * f * f); log_sprite[i].SetY (text_top + i * line_gap);
log_sprite[i].SetOpacity (1);
}
} }
} }
Plymouth.SetRefreshFunction (refresh_callback); fun push_line (text) {
# Scroll the buffer up by one line and append the newcomer at the bottom.
for (i = 0; i < num_lines - 1; i++) {
log_line[i] = log_line[i + 1];
}
log_line[num_lines - 1] = text;
draw_lines ();
}
# Both callbacks feed the same tail: systemd unit progress arrives via the
# status function, explicit `plymouth display-message` strings via the message
# function.
Plymouth.SetUpdateStatusFunction (fun (status) { push_line (status); });
Plymouth.SetDisplayMessageFunction (fun (text) { push_line (text); });
EOF EOF
# ── Register theme ──────────────────────────────────────────────────────────── # ── Register theme ────────────────────────────────────────────────────────────

View File

@ -272,7 +272,7 @@ if [[ "$AF_RUN_TUI" == "true" ]]; then
"timeshift" "timeshift system snapshot and backup with autosnap" on \ "timeshift" "timeshift system snapshot and backup with autosnap" on \
"zfs" "zfs zfs-dkms kernel module" off \ "zfs" "zfs zfs-dkms kernel module" off \
"wprs" "wprs Wayland proxy for remote sessions (wprs-git, AUR)" off \ "wprs" "wprs Wayland proxy for remote sessions (wprs-git, AUR)" off \
"plymouth" "plymouth boot splash — bundled skull logo and spinner" on \ "plymouth" "plymouth boot splash — bundled skull logo + boot-log tail" on \
"plymouth-custom" "plymouth-custom boot splash with a user-supplied image" off \ "plymouth-custom" "plymouth-custom boot splash with a user-supplied image" off \
"lightdm" "lightdm LightDM GTK greeter, cyberqueer-themed (HyprLua default)" off \ "lightdm" "lightdm LightDM GTK greeter, cyberqueer-themed (HyprLua default)" off \
"ly" "ly ly TUI display manager, cyberqueer-themed" off \ "ly" "ly ly TUI display manager, cyberqueer-themed" off \

View File

@ -14,13 +14,21 @@
# reboot yourself. # reboot yourself.
# 3. Runs the lightdm module (installs LightDM + lightdm-gtk-greeter, deploys # 3. Runs the lightdm module (installs LightDM + lightdm-gtk-greeter, deploys
# the cyberqueer greeter config + skull background, enables lightdm.service). # the cyberqueer greeter config + skull background, enables lightdm.service).
# 4. Runs the plymouth module (skull splash, initramfs + GRUB cmdline) unless # 4. Purges obsolete Plymouth artifacts left by earlier versions of this repo
# (e.g. the spinner's dot.png) so an upgraded install ends up byte-clean.
# 5. Runs the plymouth module (skull splash, initramfs + GRUB cmdline) unless
# --no-plymouth is given. # --no-plymouth is given.
# #
# It reuses the real module scripts under optional-Modules/apps/ so there is no # It reuses the real module scripts under optional-Modules/apps/ so there is no
# duplicated install logic — this tool only handles detection, teardown of the # duplicated install logic — this tool only handles detection, teardown of the
# OLD display manager, and orchestration. # OLD display manager, and orchestration.
# #
# Double duty: on a machine that is ALREADY on Plymouth + LightDM (an install
# migrated by an earlier version of this repo) re-running simply refreshes the
# greeter config and re-installs the current Plymouth theme — the clean upgrade
# path from the old full-screen-skull + spinner splash to the centred-skull +
# boot-log-tail one.
#
# Safe to re-run (idempotent). Reboot to complete the switch. # Safe to re-run (idempotent). Reboot to complete the switch.
# #
# Usage: # Usage:
@ -177,6 +185,19 @@ run bash "$APPS/lightdm.sh"
# ── 5. Plymouth splash (delegated to the module) ────────────────────────────── # ── 5. Plymouth splash (delegated to the module) ──────────────────────────────
if (( DO_PLYMOUTH )); then if (( DO_PLYMOUTH )); then
# Upgrade cleanup: the current theme is a centred skull + boot-log tail. The
# previous version scaled the skull full-screen and drew a spinning-dot
# throbber from dot.png. That file is now dead weight — strip it (and any
# other stale theme assets) BEFORE re-running the module, so it is neither
# rendered nor baked into the initramfs that plymouth.sh rebuilds.
THEME_DIR="/usr/share/plymouth/themes/m-archy"
for stale in "$THEME_DIR/dot.png"; do
if [[ -e "$stale" ]]; then
log "Removing obsolete Plymouth asset: $stale"
run sudo rm -f "$stale"
fi
done
log "Setting up the Plymouth splash via the plymouth module..." log "Setting up the Plymouth splash via the plymouth module..."
run bash "$APPS/plymouth.sh" run bash "$APPS/plymouth.sh"
else else

View File

@ -589,7 +589,7 @@ else
"timeshift" "timeshift system snapshot and backup with autosnap" on \ "timeshift" "timeshift system snapshot and backup with autosnap" on \
"zfs" "zfs zfs-dkms kernel module" off \ "zfs" "zfs zfs-dkms kernel module" off \
"wprs" "wprs Wayland proxy for remote sessions (wprs-git, AUR)" off \ "wprs" "wprs Wayland proxy for remote sessions (wprs-git, AUR)" off \
"plymouth" "plymouth boot splash — bundled skull logo and spinner" on \ "plymouth" "plymouth boot splash — bundled skull logo + boot-log tail" on \
"plymouth-custom" "plymouth-custom boot splash with a user-supplied image" off \ "plymouth-custom" "plymouth-custom boot splash with a user-supplied image" off \
"lightdm" "lightdm LightDM GTK greeter, cyberqueer-themed (HyprLua default)" off \ "lightdm" "lightdm LightDM GTK greeter, cyberqueer-themed (HyprLua default)" off \
"ly" "ly ly TUI display manager, cyberqueer-themed" off \ "ly" "ly ly TUI display manager, cyberqueer-themed" off \