#!/bin/bash #=============================================================================== # generate-grub-background.sh — build the Felhom GRUB boot background (scripts v1.22.0, R-38). # # Turns Viktor's square brand card (website/assets/og-image_2.png, 1017x1016) into a GRUB-friendly # 1024x768 PNG. Runs INSIDE the felhom-iso-assistant container (needs ImageMagick); called by # iso-repack.sh. # # THE LAYOUT, AND WHY: # # * 1024x768 canvas — gfxterm-safe. The stock PVE grub.cfg already asks for `gfxmode=1024x768`, so # this is the mode the ISO's GRUB is known to get on real firmware. Anything larger risks a # fallback to 800x600 and a scaled/cropped background. # # * The card is scaled to 500x500 and composited TOP-CENTERED (y=16). That deliberately leaves the # bottom ~250px empty: it is where felhom-theme.txt positions the boot menu (top=70%) and the # countdown label (top=84%). Menu text therefore never lands on the cloud/wordmark/tagline. If # you change CARD or CARD_Y here, move `boot_menu.top` in felhom-theme.txt to match. # # * THE GRID. The card carries a subtle background grid (4px lines of #0D131A on #0D1117, every # 131px) and Viktor asked for it to stay visible. Two things could destroy it: the downscale # (handled — at 500/1017 the lines land at ~2px, still legible), and the letterbox fill. A flat # navy fill would leave an obvious 500px square of grid floating in a plain field. # # So the grid is drawn across the WHOLE canvas first, PHASE-LOCKED to where the card's own grid # will land, in the card's own line color — then the card is composited on top. Inside the card # region the card's real grid shows; outside, the drawn continuation lines up exactly. The seam # is invisible because the card's background (#0D1117) is also the canvas fill. # # The phase-lock math: source line centers are x=81.5+n*131, y=21.5+n*131 (measured, not guessed # — sampled from og-image_2.png). Scale s=CARD/SRC_W maps them onto the canvas, offset by the # card's origin. Line width scales the same way. # # Usage: generate-grub-background.sh #=============================================================================== set -euo pipefail SRC="${1:?source card PNG required}" OUT="${2:?output PNG path required}" # --- canvas --------------------------------------------------------------------------------------- CW=1024; CH=768 BG="#0D1117" # the card's own background — the letterbox must be seamless, not merely "navy" GRID="#0D131A" # the card's own grid line color (sampled) # --- card placement (keep in sync with felhom-theme.txt boot_menu.top) ------------------------------ CARD=500; CARD_X=262; CARD_Y=16 # --- measured properties of og-image_2.png ---------------------------------------------------------- SRC_W=1017 # source width; the card is square (1017x1016) PITCH=131 # grid pitch in source px V0=81.5 # center of the first vertical grid line, source px H0=21.5 # center of the first horizontal grid line, source px LINE=4 # grid line width in source px command -v magick >/dev/null && IM=magick || IM=convert [[ -f "$SRC" ]] || { echo "generate-grub-background: source card not found: $SRC" >&2; exit 2; } # Refuse a source whose geometry no longer matches the measured constants above — a silently swapped # asset would misplace every grid line, and the result only shows up on a boot screen nobody re-checks. GEOM="$($IM identify -format '%wx%h' "$SRC")" [[ "$GEOM" == "1017x1016" ]] || { echo "generate-grub-background: source card is ${GEOM}, expected 1017x1016." >&2 echo " The grid phase-lock constants (PITCH/V0/H0/LINE) were measured against that geometry." >&2 echo " Re-measure them for the new asset before changing this check." >&2 exit 3 } S=$(awk -v c="$CARD" -v w="$SRC_W" 'BEGIN{printf "%.6f", c/w}') # card scale factor P=$(awk -v p="$PITCH" -v s="$S" 'BEGIN{printf "%.4f", p*s}') # canvas grid pitch LW=$(awk -v l="$LINE" -v s="$S" 'BEGIN{printf "%.2f", l*s}') # canvas grid line width # Walk n outward far enough to cover the canvas in both axes from the card-anchored origin. draw="" for n in $(seq -20 40); do x=$(awk -v a="$CARD_X" -v v="$V0" -v s="$S" -v p="$P" -v n="$n" 'BEGIN{printf "%.2f", a+v*s+n*p}') if awk -v x="$x" -v w="$CW" 'BEGIN{exit !(x>-2 && x-2 && y&2; exit 4; } # PNG24 (no palette, no alpha): GRUB's png module reads plain 8-bit RGB reliably; an indexed or # 16-bit PNG is where "the background silently doesn't render" comes from. $IM -size "${CW}x${CH}" xc:"$BG" \ -stroke "$GRID" -strokewidth "$LW" -draw "$draw" -stroke none \ \( "$SRC" -resize "${CARD}x${CARD}!" \) -geometry "+${CARD_X}+${CARD_Y}" -composite \ -depth 8 "PNG24:$OUT" [[ -s "$OUT" ]] || { echo "generate-grub-background: produced no output" >&2; exit 5; } OGEOM="$($IM identify -format '%wx%h %[channels] %[depth]' "$OUT")" echo "generate-grub-background: $OUT ($OGEOM, $(stat -c%s "$OUT") bytes)"