launcher
Modified: February 14, 2026 7:58 PM Category: Coding Notes List: Projects Created: November 18, 2025 8:37 AM Master Type: Notes Hide: No Starred: No Status: Unassigned
#!/bin/bash
set -euo pipefail
# ======================================================
# LAUNCHER (Colorful version with Professional toggle)
# ======================================================
if [ "${MODE:-standard}" = "professional" ]; then
source "/Users/laurenkillingsworth/Scripts/pro.sh"
exit 0
fi
# ---------------------------
# Default fallback palette (Palette 0)
# ---------------------------
BORDERC=$'\e[1;32m'
TIPSC=$'\e[1;33m'
TOGGLEC=$'\e[1;31m'
MENUC=$'\e[1;36m'
HIGHLIGHTC=$'\e[1;35m'
MISCC=$'\e[1;37m'
NC=$'\e[0m'
SUBMENUC=$'\e[1;36m'
QUITC=$'\e[1;31m'
TEXTC=$'\e[1;33m'
# ---------------------------
# Load palette definitions
# ---------------------------
source "/Users/laurenkillingsworth/Scripts/organize/palettes.sh"
source "/Users/laurenkillingsworth/Scripts/organize/themes.sh"
source "/Users/laurenkillingsworth/Scripts/organize/glitch.sh"
source "/Users/laurenkillingsworth/Scripts/organize/captainwhiskers.sh"
source "/Users/laurenkillingsworth/Scripts/organize/printfonts.sh"
CURRENT_THEME="space"
# ---------------------------
# CONFIG
# ---------------------------
NUM_PALETTES=131
DEFAULT_PALETTE=20
PALETTE_CHOSEN=${PALETTE_CHOSEN:-$DEFAULT_PALETTE}
CURRENT_THEME="${PALETTE_THEMES[$PALETTE_CHOSEN]}"
set_symbol_theme "$CURRENT_THEME"
set_whiskers_theme "$CURRENT_THEME"
# ---------------------------
# HELPER: Load predefined palette
# ---------------------------
load_palette() {
local n="$1"
if ! [[ "$n" =~ ^[0-9]+$ ]] || [ "$n" -lt 0 ] || [ "$n" -gt "$NUM_PALETTES" ]; then
n=0
fi
eval BORDERC="\$PALETTE${n}_BORDERC"
eval TIPSC="\$PALETTE${n}_TIPSC"
eval TOGGLEC="\$PALETTE${n}_TOGGLEC"
eval MENUC="\$PALETTE${n}_MENUC"
eval HIGHLIGHTC="\$PALETTE${n}_HIGHLIGHTC"
eval MISCC="\$PALETTE${n}_MISCC"
eval NC="\$PALETTE${n}_NC"
eval SUBMENUC="\$PALETTE${n}_SUBMENUC"
eval ALERTC="\$PALETTE${n}_ALERTC"
eval TEXTC="\$PALETTE${n}_TEXTC"
LIGHT_SUBMENU="${SUBMENUC}\033[2m"
}
# ---------------------------
# HELPER: Load random ANSI palette
# ---------------------------
load_random_palette() {
local MIN_RANDOM_COLOR=16
local MAX_RANDOM_COLOR=255
local RANGE=$((MAX_RANDOM_COLOR - MIN_RANDOM_COLOR + 1))
BORDERC=$'\e[38;5;'$((MIN_RANDOM_COLOR + RANDOM % RANGE))'m'
TIPSC=$'\e[38;5;'$((MIN_RANDOM_COLOR + RANDOM % RANGE))'m'
TOGGLEC=$'\e[38;5;'$((MIN_RANDOM_COLOR + RANDOM % RANGE))'m'
MENUC=$'\e[38;5;'$((MIN_RANDOM_COLOR + RANDOM % RANGE))'m'
HIGHLIGHTC=$'\e[38;5;'$((MIN_RANDOM_COLOR + RANDOM % RANGE))'m'
MISCC=$'\e[38;5;'$((MIN_RANDOM_COLOR + RANDOM % RANGE))'m'
SUBMENUC=$'\e[38;5;'$((MIN_RANDOM_COLOR + RANDOM % RANGE))'m'
ALERTC=$'\e[38;5;'$((MIN_RANDOM_COLOR + RANDOM % RANGE))'m'
TEXTC=$'\e[38;5;'$((MIN_RANDOM_COLOR + RANDOM % RANGE))'m'
NC=$'\e[0m'
LIGHT_SUBMENU="${SUBMENUC}\033[2m"
PALETTE_CHOSEN="RANDOM"
}
# ---------------------------
# Theme routing (palette β symbols / glitches / Whiskers)
# ---------------------------
apply_theme_for_palette() {
local theme
if [ "$PALETTE_CHOSEN" = "RANDOM" ]; then
theme="space"
else
theme="${PALETTE_THEMES[$PALETTE_CHOSEN]}"
fi
CURRENT_THEME="$theme"
set_symbol_theme "$theme"
set_whiskers_theme "$theme"
}
# ---------------------------
# HELPER SWATCHES
# ---------------------------
print_palette_swatch() {
local index="$1"
eval "G=\$PALETTE${index}_BORDERC"
eval "Y=\$PALETTE${index}_TIPSC"
eval "R=\$PALETTE${index}_TOGGLEC"
eval "C=\$PALETTE${index}_MENUC"
eval "M=\$PALETTE${index}_HIGHLIGHTC"
eval "W=\$PALETTE${index}_MISCC"
eval "N=\$PALETTE${index}_NC"
local prefix=" "
[ "$index" -eq "$PALETTE_CHOSEN" ] && prefix="β€"
printf "%s %2d) %s %bβ %b%bβ %b%bβ %b%bβ %b%bβ %b%bβ %b\n" \
"$prefix" "$index" "${PALETTE_NAMES[$index]:-PALETTE_$index}" \
"$G" "$N" "$Y" "$N" "$R" "$N" "$C" "$N" "$M" "$N" "$W" "$N"
}
draw_palette_swatches() {
for i in $(seq 0 $NUM_PALETTES); do
print_palette_swatch "$i"
done
}
# ---------------------------
# Startup palette selection
# ---------------------------
choose_initial_palette() {
CHANCE=20
if (( RANDOM % 131 < CHANCE )); then
PALETTE_CHOSEN=$(( RANDOM % (NUM_PALETTES + 1) ))
load_palette "$PALETTE_CHOSEN"
else
PALETTE_CHOSEN=$DEFAULT_PALETTE
load_palette "$PALETTE_CHOSEN"
fi
apply_theme_for_palette
}
# ---------------------------
# Palette names
# ---------------------------
# ---------------------------
# Load captain whiskers
# ---------------------------
SHOW_SUBMENU=false
SHOW_ANSI_SUBMENU=false
source "/Users/laurenkillingsworth/Scripts/organize/captainwhiskers.sh"
# ---------------------------
# Glitch text
# ---------------------------
glitch_text() {
local text="$1"
local glitch_chance=${2:-20}
local result=""
for ((i=0;i<${#text};i++)); do
local char="${text:i:1}"
if (( RANDOM % 100 < glitch_chance )); then
local glitch_type=$(( RANDOM % 10 ))
if (( glitch_type < 7 )); then
result+="${CURRENT_GLITCHES[$RANDOM % ${#CURRENT_GLITCHES[@]}]}"
elif (( glitch_type == 7 )); then
result+="${CURRENT_GLITCHES[$RANDOM % ${#CURRENT_GLITCHES[@]}]}"
else
result+="${CURRENT_GLITCHES[$RANDOM % ${#CURRENT_GLITCHES[@]}]}"
fi
if (( RANDOM % 12 == 0 )); then
result+="?"
fi
else
result+="$char"
fi
done
echo "$result"
}
# ---------------------------
# Print centered text
# ---------------------------
print_centered() {
local color="$1"
local text="$2"
local width="$3"
# Apply theme glyphs (letters + digits) to visible text
if [ -n "${CURRENT_THEME:-}" ]; then
text="$(apply_print_font "$CURRENT_THEME" "$text")"
fi
[ ${#text} -gt $width ] && text="${text:0:$width}"
text="${text//%/%%}"
local pad_left=$(( (width - ${#text}) / 2 ))
local pad_right=$(( width - ${#text} - pad_left ))
local left_pad="" right_pad=""
for ((i=0;i<pad_left;i++)); do
if (( RANDOM % 20 < 18 )); then left_pad+=" "; else left_pad+="${CURRENT_SYMBOLS[$((RANDOM % ${#CURRENT_SYMBOLS[@]}))]}"; fi
done
for ((i=0;i<pad_right;i++)); do
if (( RANDOM % 25 < 23 )); then right_pad+=" "; else right_pad+="${CURRENT_SYMBOLS[$((RANDOM % ${#CURRENT_SYMBOLS[@]}))]}"; fi
done
left_pad="${left_pad//%/%%}"
right_pad="${right_pad//%/%%}"
printf "%bβ%s%s%sβ%b\n" "$color" "$left_pad" "$text" "$right_pad" "$NC"
}
# ---------------------------
# Shimmering stars
# ---------------------------
generate_stars() {
local count=$1
local output=""
for i in $(seq 1 $count); do
if (( RANDOM % 3 < 2 )); then
output+=" "
else
output+="${CURRENT_SYMBOLS[$((RANDOM % ${#CURRENT_SYMBOLS[@]}))]}"
fi
done
echo "$output"
}
# ---------------------------
# ANSI code extractor
# ---------------------------
ansi_code() {
local var="$1"
echo "$var" | sed -E 's/\\e\[38;5;([0-9]+)m/\1/'
}
# ---------------------------
# Run phase scripts
# ---------------------------
run_with_phase() {
local script="$1"
local args="${2:-}"
local completion_msg="${3:-Done!}"
script -q /dev/null bash "$script" $args
echo -e "${BORDERC}${completion_msg}${NC}"
sleep 2
clear
}
# ---------------------------
# Detect volumes
# ---------------------------
detect_volume() {
local candidateVolumes=()
local cache_file="$HOME/.hbc_volumes_cache"
for vol in /Volumes/HBC*; do
[ -d "$vol" ] && candidateVolumes+=("$vol")
done
if [ ${#candidateVolumes[@]} -eq 0 ]; then
echo -e "${TOGGLEC}No volumes matching HBC### found.${NC}"
exit 1
fi
if [ ${#candidateVolumes[@]} -gt 1 ]; then
echo -e "${TIPSC}Multiple candidate volumes detected:${NC}"
select TOP_FOLDER in "${candidateVolumes[@]}"; do
if [ -n "$TOP_FOLDER" ]; then
echo -e "${BORDERC}Selected volume: $TOP_FOLDER${NC}"
break
else
echo -e "${TOGGLEC}Invalid selection.${NC}"
fi
done
else
TOP_FOLDER="${candidateVolumes[0]}"
echo -e "${BORDERC}Detected volume: $TOP_FOLDER${NC}"
fi
local vol_name
vol_name="$(basename "$TOP_FOLDER")"
if [ -f "$cache_file" ] && grep -qxF "$vol_name" "$cache_file"; then
return 0
fi
if [ ! -f "$TOP_FOLDER/config.sh" ]; then
read -rp "$(echo -e "${TIPSC}No config.sh found for $vol_name. Initialize now? [y/N]: ${NC}")" initChoice
case "$initChoice" in
[Yy]* )
read -rp "Enter enclosure type: " userEnclosure
run_with_phase "$SCRIPT_FOLDER/newvolume.sh" "$vol_name $userEnclosure $SCRIPT_FOLDER" "β
New volume initialized."
;;
* )
echo -e "${TOGGLEC}Cannot proceed without config.sh. Exiting.${NC}"
exit 1
;;
esac
fi
echo "$vol_name" >> "$cache_file"
}
# ---------------------------
# Draw menu
# ---------------------------
draw_menu() {
local show_submenu="${1:-false}"
local ascii_banner_lines=(
"βββ ββββββββββ βββββββ βββββββββββ βββ"
"βββ βββββββββββββββββββ βββββββββββ βββ"
"βββββββββββββββββββ ββββββββββββββββ"
"βββββββββββββββββββ ββββββββββββββββ"
"βββ βββββββββββββββββββββββββββββββββ βββ"
"βββ βββββββββ βββββββββββββββββββββ βββ"
)
local max_len=0
for line in "${ascii_banner_lines[@]}"; do
(( ${#line} > max_len )) && max_len=${#line}
done
local border_width=$(( max_len + 4 ))
inner_width=$(( border_width - 2 ))
local header="Detected volume: ${TOP_FOLDER:-None}"
local left_extra="βββ "
local top_content="$left_extra$header"
local top_len=${#top_content}
local fill_len=$(( border_width - top_len - 2 ))
(( fill_len < 0 )) && fill_len=0
printf "${BORDERC}β%s%sβ${NC}\n" "$top_content" "$(printf 'β%.0s' $(seq 1 $fill_len))"
local star_fill=$(generate_stars "$inner_width")
printf "%bβ%sβ%b\n" "$BORDERC" "$star_fill" "$NC"
for line in "${ascii_banner_lines[@]}"; do
print_centered "$BORDERC" "$line" "$inner_width"
done
star_fill=$(generate_stars "$inner_width")
printf "%bβ%sβ%b\n" "$BORDERC" "$star_fill" "$NC"
for i in $(seq 1 $((1 + RANDOM % 2))); do
local line="${CURRENT_WHISKERS[$((RANDOM % ${#CURRENT_WHISKERS[@]}))]}"
line="$(glitch_text "$line" 5)"
print_centered "$TIPSC" "$line" "$inner_width"
done
printf "${BORDERC}β %sβ£${NC}\n" "$(printf 'β%.0s' $(seq 1 $inner_width))"
local options=(
"[1 Autocrop] [2 Make Positives]"
"[3 Export Derivatives] [4 Convert Derivatives]"
"[5 Organize All] [6 Create New Volume]"
"[7 Chained Batch Edits]"
"[P Palettes] [X Random] [A ANSI]"
"[Q Quit] [M Mode] [R Reload]"
)
for opt in "${options[@]}"; do
local color="$MENUC"
if [[ "$opt" =~ \[Q ]] || [[ "$opt" =~ \[R ]] || [[ "$opt" =~ \[P ]] || [[ "$opt" =~ \[X ]]; then
color="$HIGHLIGHTC"
fi
print_centered "$color" "$opt" "$inner_width"
if [[ "$opt" =~ \[7 ]] && [ "$show_submenu" = true ]; then
local suboptions=(
"1 Phase One | 2 Phase Two | 3 Phase Three"
"4 Phases One and Two | E Escape"
)
local bullet="β’"
for sub in "${suboptions[@]}"; do
print_centered "$LIGHT_SUBMENU" " $bullet $sub" "$inner_width"
done
fi
done
if [ "$SHOW_ANSI_SUBMENU" = true ]; then
local color_names=(BORDERS TIPS TOGGLES MENU HIGHLIGHTS MISCELLANEOUS SUBMENUS ALERTS TEXT)
local color_vars=("$BORDERC" "$TIPSC" "$TOGGLEC" "$MENUC" "$HIGHLIGHTC" "$MISCC" "$SUBMENUC" "$ALERTC" "$TEXTC")
for i in "${!color_names[@]}"; do
code=$(echo "${color_vars[i]}" | sed -E 's/\x1b\[38;5;([0-9]+)m/\1/')
print_centered "${color_vars[i]}" "β ${color_names[i]} = $code" "$inner_width"
done
fi
printf "${BORDERC}β %sβ£${NC}\n" "$(printf 'β%.0s' $(seq 1 $inner_width))"
star_fill=$(generate_stars "$inner_width")
printf "%bβ%sβ%b\n" "$BORDERC" "$star_fill" "$NC"
local archive_text="Hooks Β© 1907"
local stars_total=$(( inner_width - ${#archive_text} - 2 ))
local left_stars_count=$(( stars_total / 2 ))
local right_stars_count=$(( stars_total - left_stars_count ))
local left_stars=$(generate_stars $left_stars_count)
local right_stars=$(generate_stars $right_stars_count)
print_centered "$TIPSC" "$left_stars $archive_text $right_stars" "$inner_width"
local theme_text="Theme: "
if [ "$PALETTE_CHOSEN" = "RANDOM" ]; then
theme_text+="Random Colors"
else
theme_text+="${PALETTE_NAMES[PALETTE_CHOSEN]}"
fi
theme_text="$(apply_print_font "$CURRENT_THEME" "$theme_text")"
local fill_len=$(( inner_width - ${#theme_text} ))
(( fill_len < 0 )) && fill_len=0
local left_fill=$(( fill_len / 2 ))
local right_fill=$(( fill_len - left_fill ))
star_fill=$(generate_stars "$inner_width")
printf "%bβ%sβ%b\n" "$BORDERC" "$star_fill" "$NC"
printf "%bβ%s%s%sβ%b\n" "$BORDERC" \
"$(printf 'β%.0s' $(seq 1 $left_fill))" \
"$theme_text" \
"$(printf 'β%.0s' $(seq 1 $right_fill))" \
"$NC"
}
# ---------------------------
# Main loop
# ---------------------------
main_loop() {
detect_volume
if [ -f "$TOP_FOLDER/config.sh" ]; then
source "$TOP_FOLDER/config.sh"
else
echo -e "${TOGGLEC}Error: config.sh not found in $TOP_FOLDER${NC}"
exit 1
fi
choose_initial_palette
while true; do
clear
draw_menu "$SHOW_SUBMENU"
echo
read -rp "$(printf "${MISCC}Choose an option: ${NC}")" choice
choice="${choice//[\[\] ]/}"
if [ "$SHOW_ANSI_SUBMENU" = true ]; then
SHOW_ANSI_SUBMENU=false
continue
fi
case "$choice" in
1) run_with_phase "/Users/laurenkillingsworth/Scripts/organize/autocrop.sh" "$TOP_FOLDER" "β
Autocrop complete." ;;
2) run_with_phase "/Users/laurenkillingsworth/Scripts/organize/adjust.sh" "$TOP_FOLDER" "β
Digital positive complete." ;;
3) run_with_phase "/Users/laurenkillingsworth/Scripts/organize/export.sh" "$TOP_FOLDER" "β
Export as TIFF complete." ;;
4) run_with_phase "/Users/laurenkillingsworth/Scripts/organize/convertjpg.sh" "$TOP_FOLDER" "β
Convert to JPG complete." ;;
5) run_with_phase "/Users/laurenkillingsworth/Scripts/organize/sortfilter.sh" "$TOP_FOLDER" "β
Sort and filter complete." ;;
6)
read -rp "Enter new volume name: " userVolume
read -rp "Enter enclosure type: " userEnclosure
run_with_phase "$SCRIPT_FOLDER/newvolume.sh" "$userVolume $userEnclosure $SCRIPT_FOLDER" "β
New volume created."
;;
7)
SHOW_SUBMENU=true
while true; do
clear
draw_menu "$SHOW_SUBMENU"
read -rp "$(printf "${MISCC}Choose a batch phase: ${NC}")" subchoice
subchoice="${subchoice//[\[\] ]/}"
case "$subchoice" in
1) run_with_phase "$SCRIPT_FOLDER/phase1.sh" "$TOP_FOLDER" "β
Phase 1 complete." ;;
2) run_with_phase "$SCRIPT_FOLDER/phase2.sh" "$TOP_FOLDER" "β
Phase 2 complete." ;;
3) run_with_phase "$SCRIPT_FOLDER/phase3.sh" "$TOP_FOLDER" "β
Phase 3 complete." ;;
4)
run_with_phase "$SCRIPT_FOLDER/phase1.sh" "$TOP_FOLDER" "β
Phase 1 complete."
run_with_phase "$SCRIPT_FOLDER/phase2.sh" "$TOP_FOLDER" "β
Phase 2 complete."
;;
E|e) echo -e "${HIGHLIGHTC}Returning to the main menuβ¦${NC}"; break ;;
*) print_centered "$TOGGLEC" "β οΈ Invalid choice." "$inner_width"; sleep 1 ;;
esac
done
SHOW_SUBMENU=false
;;
P|p)
SHOW_SUBMENU=true
while true; do
clear
draw_menu "$SHOW_SUBMENU"
echo -e "${MENUC}Palette Preview β Select a palette (0-${NUM_PALETTES}) or E to exit:${NC}"
draw_palette_swatches
read -rp "Enter palette number to preview or E to exit: " pal_choice
if [[ "$pal_choice" =~ ^[0-9]+$ ]] && [ "$pal_choice" -ge 0 ] && [ "$pal_choice" -le "$NUM_PALETTES" ]; then
load_palette "$pal_choice"
clear
echo -e "${MENUC}Previewing Palette $pal_choice β Press Enter to commit, any other key to return.${NC}"
draw_menu "$SHOW_SUBMENU"
read -rp "" preview_choice
if [ -z "$preview_choice" ]; then
PALETTE_CHOSEN="$pal_choice"
apply_theme_for_palette
echo -e "${BORDERC}β
Palette $pal_choice loaded!${NC}"
sleep 1
break
else
load_palette "$PALETTE_CHOSEN"
apply_theme_for_palette
fi
elif [[ "$pal_choice" =~ ^[Ee]$ ]]; then
load_palette "$PALETTE_CHOSEN"
apply_theme_for_palette
break
else
echo -e "${TOGGLEC}β οΈ Invalid selection.${NC}"
sleep 1
fi
done
SHOW_SUBMENU=false
;;
X|x)
load_random_palette
apply_theme_for_palette
echo -e "${BORDERC}β
Random colors loaded!${NC}"
sleep 1
;;
A|a)
SHOW_ANSI_SUBMENU=true
;;
Q|q)
echo -e "${ALERTC}Exitingβ¦${NC}"
exit 0
;;
R|r)
# safe random palette: only pick indices that EXIST
local max_index=$(( ${#PALETTE_THEMES[@]} - 1 ))
PALETTE_CHOSEN=$(( RANDOM % (max_index + 1) ))
load_palette "$PALETTE_CHOSEN"
apply_theme_for_palette
continue
;;
M|m)
echo "Switching to Simple mode..."
SCRIPT_FOLDER="/Users/laurenkillingsworth/Scripts"
MODE=professional
source "$SCRIPT_FOLDER/pro.sh"
exit 0
;;
*)
echo -e "${TEXTC}β οΈ Invalid choice.${NC}"
sleep 1
;;
esac
done
}
# ---------------------------
# Start launcher
# ---------------------------
main_loop