theme: Unify colorscheme based on wallpaper - scripts - various script and utils
HTML git clone git://z3bra.org/scripts
DIR Log
DIR Files
DIR Refs
---
DIR commit 63cf988f5aec9f4b91667d8bb53c5c902cd6ce6e
DIR parent eeb0649ba53d5feb0e4d009688ccfc83a5ef299b
HTML Author: Willy Goiffon <dev@z3bra.org>
Date: Thu, 20 Aug 2026 23:21:38 +0000
theme: Unify colorscheme based on wallpaper
Diffstat:
A theme | 182 +++++++++++++++++++++++++++++++
1 file changed, 182 insertions(+), 0 deletions(-)
---
DIR diff --git a/theme b/theme
@@ -0,0 +1,182 @@
+#!/bin/sh
+
+themedir="${XDG_CONFIG_DIR:-$HOME/.config}/theme"
+
+usage() {
+ echo "usage: $(basename $0) [-dlr] [-fb color[,secondary]] [-p name] [[-c name] file]" >&2
+}
+
+preset() {
+ theme="${themedir}/$1"
+ if [ ! -e "$theme" ]; then
+ printf '%s: No such theme\n' "$1" >&2
+ exit 1
+ fi
+
+ . $theme
+ ln -sf $img $HOME/.bg.png
+}
+
+# Compute perceived brightness of an #RGB color
+# https://en.wikipedia.org/wiki/Rec._709#The_Y'C'BC'R_color_space
+mood() {
+ hex=${1#\#}
+ r="0x$(echo $hex|cut -b1-2)"
+ g="0x$(echo $hex|cut -b3-4)"
+ b="0x$(echo $hex|cut -b5-6)"
+ l=$(printf '%d*0.2126 + %d*0.7152 + %d*0.0722\n' $r $g $b|bc|cut -d. -f1)
+ [ $l -gt 128 ] && echo 'light' || echo 'dark'
+}
+
+pastel() {
+ printf '#'
+ case $mood in
+ dark) seq 0 96|shuf|head -n3|xargs printf '%02x';;
+ light) seq 170 240|shuf|head -n3|xargs printf '%02x';;
+ esac
+}
+
+mktheme() {
+ if [ ! -e "$img" ]; then
+ printf '%s: No such file or directory\n' "$image" >&2
+ exit 1
+ fi
+
+ # display picture and colorspace
+ 2ff <$img|lel -a -w 540 -h 304 &
+ colors -pn16 <$img|hex2col
+
+ printf 'bg: '; read bg
+ printf 'dm: '; read dm
+ printf 'fg: '; read fg
+ printf 'hl: '; read hl
+
+ path=$(readlink -f $img|sed "s,$HOME,\$HOME,")
+ printf 'img="%s"\nbg="%s,%s"\nfg="%s,%s"\n' "$path" "$bg" "$dm" "$fg" "$hl" \
+ |tee "$HOME/.config/theme/${1}"
+}
+
+repack() {
+ (cd $1; pack >/dev/null 2>&1)
+}
+
+setup_lowlife() {
+ sed -ri \
+ -e "/color_unfocus/s/0x[0-9a-f]+/0x${dm#\#}/" \
+ -e "/color_focus/s/0x[0-9a-f]+/0x${hl#\#}/" \
+ $HOME/build/lowlife/config.h
+ repack $HOME/build/lowlife
+ pkill lowlife; nohup lowlife >/dev/null &
+}
+
+setup_menuw() {
+ sed -i \
+ -e "/background =/s/=.*/= 0x${bg#\#};/" \
+ -e "/foreground =/s/=.*/= 0x${hl#\#};/" \
+ $HOME/build/menuw/config.h
+ repack $HOME/build/menuw
+ pkill menuw; nohup rootmenu >/dev/null &
+}
+
+setup_foot() {
+ [ "$mood" = "dark" ] && theme=1 || theme=2
+ sed -i \
+ -e "/foreground/s/=.*/=${fg#\#}/" \
+ -e "/background/s/=.*/=${bg#\#}/" \
+ -e "/initial-color-theme/s/=.*/=${theme}/" \
+ $HOME/.config/foot/foot.ini
+}
+
+setup_vis() {
+ sed -i \
+ -e "/color_high =/s/=.*/= '$hl'/" \
+ -e "/color_low =/s/=.*/= '$dm'/" \
+ $HOME/.config/vis/themes/simple.lua
+}
+
+setup_tofi() {
+ sed -i \
+ -e "/^text-color/s/=.*/= $fg/" \
+ -e "/^prompt-color/s/=.*/= $dm/" \
+ -e "/^selection-color/s/=.*/= $hl/" \
+ -e "/^background-color/s/=.*/= $bg/" \
+ $HOME/.config/tofi/config
+}
+
+setup_waybar() {
+ # Make sure waybar contrasts with the background filling color
+ # When theme is "light", fg/bg colors are swapped
+ [ "$mood" = "$(mood $fill)" ] && c=$hl || c=$dm
+ sed -ri "/^#(clock|battery)/s/color:.*;/color:${c};/" $HOME/.config/waybar/style.css
+}
+
+now=$(date +%H%M)
+case $(date +%H) in
+0[7-9]|1*) mood=light;;
+0[0-6]|2*) mood=dark;;
+esac
+
+while getopts "hdlrc:f:b:p:m:" OPT; do
+ case $OPT in
+ c) create=$OPTARG;;
+ d) dryrun=1;;
+ f) fg="$OPTARG";;
+ b) bg="$OPTARG";;
+ l) ls $themedir; exit 0;;
+ r) preset=$(ls $themedir|shuf|head -n1);;
+ m) mood="$OPTARG";;
+ p) preset="$OPTARG";;
+ h) usage; exit 0;;
+ *) usage; exit 1;;
+ esac
+done
+shift $((OPTIND - 1))
+
+if [ -n "$preset" ]; then
+ preset $preset
+else
+ preset $(ls $themedir|shuf|head -n1)
+fi
+
+if [ -n "$create" ]; then
+ img=${1:-$HOME/.bg.png}
+ mktheme "$create"
+fi
+
+# Invert colors for light themes
+if [ "$mood" = "light" ]; then
+ tmp=$fg
+ fg=$bg
+ bg=$tmp
+fi
+
+hl=${fg#*,}
+dm=${bg#*,}
+fg=${fg%,*}
+bg=${bg%,*}
+
+# Use first pixel to compute filler color using raw farbfeld.
+# Pixelspace is 16 bits, so we must do a quick cut(1) dance to get the
+# color as 8 bits
+alpha=$(<$img png2ff|xxd -c0 -p|cut -b45-46)
+rgb=$(<$img png2ff|xxd -c0 -p|cut -b33-34,37-38,41-42)
+
+# Use random pastel colors for transparent pixel (unless specified in theme)
+case "$alpha" in
+00) fill=${fill:-$(pastel)} ;;
+ *) fill="#${rgb}" ;;
+esac
+
+if [ ${dryrun:-0} -eq 1 ]; then
+ readlink -f $img
+ 2ff <$img|lel -a -w 540 -h 304 &
+ printf "%s\n" "$bg" "$dm" "$fg" "$hl"|hex2col
+ exit 0
+fi
+
+pkill swaybg; swaybg -c "$fill" -i $img -m ${mode:-fit} 2>/dev/null &
+setup_foot &
+setup_waybar &
+setup_menuw &
+setup_tofi &
+setup_vis &