Last active
May 13, 2026 17:49
-
-
Save reinier/787b0d1d9880df8625e3858f5c945d5a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| # start.sh — base Niri + DMS install for CachyOS | |
| # | |
| # Usage: | |
| # curl -fsSL https://install.reinierladan.nl/start | sh | |
| # | |
| # Vendor-aware: detects Framework or Apple hardware and applies the | |
| # appropriate optimizations. Unknown vendors get a sensible generic baseline. | |
| set -euo pipefail | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # Helpers | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| C_RESET='\033[0m'; C_BLUE='\033[1;34m'; C_GREEN='\033[1;32m' | |
| C_YELLOW='\033[1;33m'; C_RED='\033[1;31m'; C_DIM='\033[2m' | |
| log() { printf "${C_BLUE}[start]${C_RESET} %s\n" "$*" >&2; } | |
| ok() { printf "${C_GREEN}[start]${C_RESET} ${C_DIM}✓ %s${C_RESET}\n" "$*" >&2; } | |
| warn() { printf "${C_YELLOW}[start]${C_RESET} %s\n" "$*" >&2; } | |
| die() { printf "${C_RED}[start]${C_RESET} ERROR: %s\n" "$*" >&2; exit 1; } | |
| have() { command -v "$1" >/dev/null 2>&1; } | |
| section() { printf "\n${C_BLUE}━━━ %s ━━━${C_RESET}\n" "$*" >&2; } | |
| pacman_install() { sudo pacman -S --needed --noconfirm "$@" || die "pacman failed: $*"; } | |
| aur_install() { paru -S --needed --noconfirm --skipreview "$@" || die "paru failed: $*"; } | |
| backup_file() { [[ -f "$1" && ! -f "$1.start-bak" ]] && sudo cp -a "$1" "$1.start-bak"; } | |
| detect_cpu_vendor() { | |
| if grep -q "GenuineIntel" /proc/cpuinfo; then echo "intel" | |
| elif grep -q "AuthenticAMD" /proc/cpuinfo; then echo "amd" | |
| else echo "unknown" | |
| fi | |
| } | |
| detect_sys_vendor() { | |
| [[ -f /sys/class/dmi/id/sys_vendor ]] || { echo "unknown"; return; } | |
| local v; v=$(< /sys/class/dmi/id/sys_vendor) | |
| case "$v" in | |
| *[Ff]ramework*) echo "framework" ;; | |
| *Apple*) echo "apple" ;; | |
| *) echo "other:$v" ;; | |
| esac | |
| } | |
| detect_product() { | |
| [[ -f /sys/class/dmi/id/product_name ]] && cat /sys/class/dmi/id/product_name || echo "unknown" | |
| } | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # 1. Preflight | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| preflight() { | |
| section "Preflight" | |
| [[ -f /etc/os-release ]] || die "No /etc/os-release" | |
| grep -qE '^ID(_LIKE)?=.*arch' /etc/os-release || \ | |
| warn "This script expects an Arch-based system (CachyOS preferred)." | |
| have sudo || die "sudo not installed" | |
| sudo -v || die "Need sudo privileges" | |
| while true; do sudo -nv; sleep 60; kill -0 "$$" 2>/dev/null || exit; done 2>/dev/null & | |
| ok "Preflight passed" | |
| } | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # 2. System update + AUR helper | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| base_system() { | |
| section "System update + AUR helper" | |
| sudo pacman -Syu --noconfirm | |
| pacman_install base-devel git curl | |
| if ! have paru; then | |
| log "Installing paru…" | |
| local tmp; tmp=$(mktemp -d) | |
| git -C "$tmp" clone https://aur.archlinux.org/paru-bin.git | |
| (cd "$tmp/paru-bin" && makepkg -si --noconfirm) | |
| rm -rf "$tmp" | |
| fi | |
| ok "Base system + paru ready" | |
| } | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # 3. Remove i3 cruft | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| remove_i3_cruft() { | |
| section "Removing i3 cruft" | |
| local to_remove=() | |
| for pkg in i3-wm i3status i3blocks i3lock dmenu picom rofi feh xss-lock; do | |
| if pacman -Qi "$pkg" >/dev/null 2>&1; then | |
| to_remove+=("$pkg") | |
| fi | |
| done | |
| if (( ${#to_remove[@]} > 0 )); then | |
| log "Removing: ${to_remove[*]}" | |
| sudo pacman -Rns --noconfirm "${to_remove[@]}" || warn "Some packages couldn't be removed cleanly" | |
| else | |
| log "No i3 cruft found, skipping" | |
| fi | |
| ok "Cleanup complete" | |
| } | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # 4. Compositor stack | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| compositor_stack() { | |
| section "Compositor stack (Niri + portals + audio + auth)" | |
| pacman_install \ | |
| niri uwsm \ | |
| xdg-desktop-portal xdg-desktop-portal-gnome xdg-desktop-portal-gtk \ | |
| polkit hyprpolkitagent \ | |
| gnome-keyring libsecret seahorse \ | |
| pipewire pipewire-pulse pipewire-jack wireplumber pavucontrol \ | |
| brightnessctl ddcutil cliphist wl-clipboard \ | |
| networkmanager network-manager-applet | |
| systemctl --user enable pipewire.service pipewire-pulse.service wireplumber.service | |
| systemctl --user enable hyprpolkitagent.service | |
| sudo systemctl enable --now NetworkManager.service | |
| ok "Compositor stack installed" | |
| } | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # 5. DankMaterialShell — AUR-first ordering to avoid quickshell conflict | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| dms_stack() { | |
| section "DankMaterialShell" | |
| # Install quickshell-git FIRST. Its PKGBUILD declares provides=(quickshell) | |
| # and conflicts=(quickshell), so when `dms` is installed afterward and | |
| # declares a quickshell dependency, it's satisfied without pulling in the | |
| # stable package and triggering a conflict. | |
| log "Installing quickshell-git first (avoids conflict with dms's quickshell dep)…" | |
| aur_install quickshell-git | |
| aur_install matugen-bin dgop-bin | |
| # DMS itself — prefer the official extra package, fall back to AUR git. | |
| # Use paru rather than pacman so quickshell-git's `provides=` is honored. | |
| if pacman -Si dms >/dev/null 2>&1; then | |
| aur_install dms | |
| else | |
| aur_install dms-shell-git | |
| fi | |
| pacman_install \ | |
| noto-fonts noto-fonts-emoji noto-fonts-cjk \ | |
| ttf-jetbrains-mono-nerd inter-font ttf-fira-code | |
| aur_install ttf-material-symbols-variable-git | |
| # DMS as a systemd user service (Omarchy-style — no spawn-at-startup needed) | |
| if systemctl --user list-unit-files dms.service >/dev/null 2>&1; then | |
| systemctl --user enable dms.service | |
| log "Enabled dms.service as systemd user unit" | |
| else | |
| warn "dms.service not shipped by the package — falling back to spawn-at-startup in niri config" | |
| fi | |
| # Session-wide environment vars for Qt/GTK theming + Wayland compat | |
| mkdir -p "$HOME/.config/environment.d" | |
| cat > "$HOME/.config/environment.d/90-dms.conf" <<'EOF' | |
| QT_QPA_PLATFORM=wayland | |
| QT_QPA_PLATFORMTHEME=qt6ct | |
| QS_ICON_THEME=Adwaita | |
| XDG_CURRENT_DESKTOP=niri | |
| XDG_SESSION_DESKTOP=niri | |
| EOF | |
| ok "DMS installed and configured" | |
| } | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # 6. dms-greeter — themed greetd login that syncs with user's DMS theme | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| login_stack() { | |
| section "Login stack (greetd + dms-greeter)" | |
| pacman_install greetd | |
| aur_install greetd-dms-greeter-git | |
| sudo mkdir -p /etc/greetd | |
| backup_file /etc/greetd/niri.kdl | |
| sudo tee /etc/greetd/niri.kdl >/dev/null <<'EOF' | |
| // Greeter compositor config — kept minimal so the greeter is the only thing | |
| // visible on the login screen. Do not autostart DMS here. | |
| input { | |
| keyboard { xkb { layout "us"; } } | |
| touchpad { tap; natural-scroll; } | |
| } | |
| layout { | |
| gaps 0 | |
| } | |
| cursor { | |
| xcursor-theme "Adwaita" | |
| xcursor-size 24 | |
| } | |
| EOF | |
| backup_file /etc/greetd/config.toml | |
| sudo tee /etc/greetd/config.toml >/dev/null <<'EOF' | |
| [terminal] | |
| vt = 1 | |
| [default_session] | |
| command = "dms-greeter --command niri -C /etc/greetd/niri.kdl" | |
| user = "greeter" | |
| EOF | |
| if ! grep -q pam_gnome_keyring /etc/pam.d/greetd 2>/dev/null; then | |
| sudo tee -a /etc/pam.d/greetd >/dev/null <<'EOF' | |
| auth optional pam_gnome_keyring.so | |
| session optional pam_gnome_keyring.so auto_start | |
| EOF | |
| fi | |
| for dm in sddm gdm lightdm lxdm plasma-login-manager; do | |
| sudo systemctl disable "$dm.service" 2>/dev/null || true | |
| done | |
| sudo systemctl enable greetd.service | |
| if have dms; then | |
| log "Attempting initial 'dms greeter sync' (may no-op on first install)…" | |
| dms greeter sync 2>/dev/null || log " (no DMS user state yet — sync after first login)" | |
| fi | |
| ok "Login stack configured" | |
| } | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # 7. Auto-sync greeter on DMS theme changes | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| greeter_autosync() { | |
| section "Greeter auto-sync (path unit)" | |
| mkdir -p "$HOME/.config/systemd/user" | |
| cat > "$HOME/.config/systemd/user/dms-greeter-sync.service" <<'EOF' | |
| [Unit] | |
| Description=Sync DMS greeter cache with current user theme | |
| After=graphical-session.target | |
| PartOf=graphical-session.target | |
| [Service] | |
| Type=oneshot | |
| ExecStart=/usr/bin/dms greeter sync | |
| SuccessExitStatus=0 1 | |
| EOF | |
| cat > "$HOME/.config/systemd/user/dms-greeter-sync.path" <<'EOF' | |
| [Unit] | |
| Description=Watch DMS settings for greeter sync trigger | |
| [Path] | |
| PathChanged=%h/.config/DankMaterialShell/settings.json | |
| PathChanged=%h/.config/DankMaterialShell/clsettings.json | |
| TriggerLimitIntervalSec=5s | |
| TriggerLimitBurst=3 | |
| [Install] | |
| WantedBy=default.target | |
| EOF | |
| systemctl --user daemon-reload | |
| systemctl --user enable dms-greeter-sync.path | |
| ok "Greeter will auto-sync when DMS settings change" | |
| } | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # 8. Terminal | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| terminal() { | |
| section "Terminal (ghostty)" | |
| pacman_install ghostty | |
| ok "ghostty installed" | |
| } | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # 9. Hardware tuning — vendor-aware | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| hardware_tuning() { | |
| section "Hardware tuning" | |
| local sys_vendor cpu_vendor product | |
| sys_vendor=$(detect_sys_vendor) | |
| cpu_vendor=$(detect_cpu_vendor) | |
| product=$(detect_product) | |
| log "Detected: vendor=$sys_vendor, cpu=$cpu_vendor, product=$product" | |
| case "$cpu_vendor" in | |
| intel) pacman_install intel-ucode ;; | |
| amd) pacman_install amd-ucode ;; | |
| *) warn "Unknown CPU vendor — skipping microcode" ;; | |
| esac | |
| pacman_install bluez bluez-utils power-profiles-daemon | |
| sudo systemctl enable --now bluetooth.service | |
| sudo systemctl enable --now power-profiles-daemon.service | |
| sudo usermod -aG video,input "$USER" | |
| case "$sys_vendor" in | |
| framework) tune_framework ;; | |
| apple) tune_apple "$product" ;; | |
| *) log "No vendor-specific tuning for $sys_vendor" ;; | |
| esac | |
| ok "Hardware tuning complete" | |
| } | |
| tune_framework() { | |
| log "Framework laptop detected — applying optimizations" | |
| pacman_install fwupd | |
| sudo systemctl enable --now fwupd-refresh.timer | |
| # iwd as NetworkManager's WiFi backend. | |
| # Framework's WiFi (AX210/AX211 Intel or AMD's MediaTek MT7922) works well | |
| # with iwd, and you get better roaming + reconnect behavior — especially | |
| # noticeable with flaky access points like iPhone hotspots. | |
| # Skipped on Apple hardware where Broadcom + iwd is less well-trodden. | |
| framework_wifi_iwd | |
| ok "Framework tuning applied" | |
| } | |
| framework_wifi_iwd() { | |
| log "Configuring iwd as NetworkManager's WiFi backend…" | |
| pacman_install iwd | |
| # NetworkManager: use iwd instead of wpa_supplicant | |
| sudo mkdir -p /etc/NetworkManager/conf.d | |
| sudo tee /etc/NetworkManager/conf.d/wifi-backend.conf >/dev/null <<'EOF' | |
| [device] | |
| wifi.backend=iwd | |
| EOF | |
| # iwd config: only the WiFi layer (association/auth/roaming). | |
| # NetworkManager handles IP, DNS, routing, VPN. | |
| # AddressRandomization=network → per-SSID consistent random MAC. | |
| sudo mkdir -p /etc/iwd | |
| backup_file /etc/iwd/main.conf | |
| sudo tee /etc/iwd/main.conf >/dev/null <<'EOF' | |
| [General] | |
| EnableNetworkConfiguration=false | |
| AddressRandomization=network | |
| [Network] | |
| NameResolvingService=systemd | |
| EOF | |
| # Mask wpa_supplicant BEFORE enabling iwd so NetworkManager can't briefly | |
| # try to talk to a service that's about to disappear. | |
| sudo systemctl disable --now wpa_supplicant.service 2>/dev/null || true | |
| sudo systemctl mask wpa_supplicant.service 2>/dev/null || true | |
| # Enable iwd but don't start it during this live session — that would | |
| # flap the WiFi connection used to run this very script. After reboot | |
| # everything starts in the right order. | |
| sudo systemctl enable iwd.service | |
| log "iwd will take over WiFi after reboot. Verify with:" | |
| log " systemctl status iwd NetworkManager" | |
| log " nmcli device" | |
| log " journalctl -u iwd | grep 'state.*connected'" | |
| } | |
| tune_apple() { | |
| local product="$1" | |
| log "Apple hardware detected ($product) — applying optimizations" | |
| log "Installing Broadcom Wi-Fi driver (broadcom-wl-dkms)…" | |
| pacman_install linux-headers broadcom-wl-dkms | |
| sudo tee /etc/modules-load.d/applesmc.conf >/dev/null <<'EOF' | |
| applesmc | |
| coretemp | |
| EOF | |
| pacman_install fwupd | |
| sudo systemctl enable --now fwupd-refresh.timer 2>/dev/null || true | |
| if [[ "$product" =~ MacBook(8|9|10),1 ]]; then | |
| log "Fanless MacBook detected — configuring deep sleep" | |
| configure_deep_sleep | |
| fi | |
| sudo tee /etc/modprobe.d/hid_apple.conf >/dev/null <<'EOF' | |
| options hid_apple fnmode=2 | |
| EOF | |
| log "initramfs will need regenerating: 'sudo mkinitcpio -P' before reboot" | |
| ok "Apple tuning applied" | |
| } | |
| configure_deep_sleep() { | |
| if [[ -f /etc/default/limine ]]; then | |
| if ! grep -q 'mem_sleep_default=deep' /etc/default/limine; then | |
| sudo sed -i 's/^\(KERNEL_CMDLINE\[default\]=".*\)"/\1 mem_sleep_default=deep"/' /etc/default/limine | |
| have limine-update && sudo limine-update || warn "Run 'sudo limine-update' manually" | |
| fi | |
| elif [[ -f /etc/default/grub ]]; then | |
| if ! grep -q 'mem_sleep_default=deep' /etc/default/grub; then | |
| sudo sed -i 's/^\(GRUB_CMDLINE_LINUX_DEFAULT=".*\)"/\1 mem_sleep_default=deep"/' /etc/default/grub | |
| sudo grub-mkconfig -o /boot/grub/grub.cfg | |
| fi | |
| else | |
| warn "Couldn't find limine or grub config — set mem_sleep_default=deep manually" | |
| fi | |
| } | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # 10. Locale — English only | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| locale_setup() { | |
| section "Locale (English-only)" | |
| backup_file /etc/locale.gen | |
| sudo sed -i 's/^#\(en_US.UTF-8 UTF-8\)/\1/' /etc/locale.gen | |
| sudo locale-gen | |
| backup_file /etc/locale.conf | |
| echo 'LANG=en_US.UTF-8' | sudo tee /etc/locale.conf >/dev/null | |
| pacman_install hunspell hunspell-en_us | |
| ok "Locale configured" | |
| } | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # 11. Theming | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| theming() { | |
| section "Theming (GTK + Qt + cursor)" | |
| pacman_install \ | |
| adw-gtk-theme \ | |
| qt6ct kvantum \ | |
| bibata-cursor-theme | |
| mkdir -p "$HOME/.config/gtk-3.0" "$HOME/.config/gtk-4.0" | |
| cat > "$HOME/.config/gtk-3.0/settings.ini" <<'EOF' | |
| [Settings] | |
| gtk-application-prefer-dark-theme=1 | |
| gtk-theme-name=adw-gtk3-dark | |
| EOF | |
| cat > "$HOME/.config/gtk-4.0/settings.ini" <<'EOF' | |
| [Settings] | |
| gtk-application-prefer-dark-theme=1 | |
| gtk-theme-name=adw-gtk3-dark | |
| EOF | |
| if have gsettings; then | |
| gsettings set org.gnome.desktop.interface color-scheme 'prefer-dark' || true | |
| gsettings set org.gnome.desktop.interface gtk-theme 'adw-gtk3-dark' || true | |
| gsettings set org.gnome.desktop.interface cursor-theme 'Bibata-Modern-Classic' || true | |
| fi | |
| ok "Theming applied" | |
| } | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # 12. Niri starter config — HiDPI-aware, DMS-aware | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| niri_config() { | |
| section "Niri starter config" | |
| if [[ -f "$HOME/.config/niri/config.kdl" ]]; then | |
| log "Existing Niri config detected — leaving alone" | |
| return | |
| fi | |
| local sys_vendor product scale_hint dms_spawn_line | |
| sys_vendor=$(detect_sys_vendor) | |
| product=$(detect_product) | |
| scale_hint="1.0" | |
| case "$sys_vendor:$product" in | |
| framework:*) scale_hint="2.0" ;; | |
| apple:MacBook10,1) scale_hint="1.5" ;; | |
| apple:MacBook9,1) scale_hint="1.5" ;; | |
| apple:MacBook8,1) scale_hint="1.5" ;; | |
| esac | |
| if systemctl --user is-enabled dms.service >/dev/null 2>&1; then | |
| dms_spawn_line='// dms started via systemd user service; no spawn-at-startup needed' | |
| else | |
| dms_spawn_line='spawn-at-startup "dms" "run"' | |
| fi | |
| mkdir -p "$HOME/.config/niri" | |
| cat > "$HOME/.config/niri/config.kdl" <<EOF | |
| // Starter config from start.sh — replace with your real config once ready | |
| // Detected: $sys_vendor / $product → scale=$scale_hint | |
| input { | |
| keyboard { xkb { layout "us"; } } | |
| touchpad { tap; natural-scroll; click-method "clickfinger"; } | |
| focus-follows-mouse | |
| } | |
| // Set scale on your primary output. Confirm the output name with: | |
| // niri msg outputs | |
| // Then replace "eDP-1" below if it differs. | |
| output "eDP-1" { | |
| scale ${scale_hint} | |
| } | |
| layout { | |
| gaps 8 | |
| preset-column-widths { | |
| proportion 0.33333 | |
| proportion 0.5 | |
| proportion 0.66667 | |
| } | |
| default-column-width { proportion 0.5; } | |
| } | |
| // Keyring on session start. DMS itself starts via systemd user service. | |
| spawn-at-startup "gnome-keyring-daemon" "--start" "--components=secrets,ssh" | |
| ${dms_spawn_line} | |
| // DMS popout window rule — future-proofs DMS's floating overlays | |
| window-rule { | |
| match app-id="com.danklinux.dms" | |
| open-floating true | |
| } | |
| // Env vars now live in ~/.config/environment.d/90-dms.conf for session-wide | |
| // scope. Keeping only niri-specific bits here. | |
| binds { | |
| Mod+Return { spawn "ghostty"; } | |
| Mod+D { spawn "dms" "ipc" "call" "spotlight" "toggle"; } | |
| Mod+Q { close-window; } | |
| Mod+Shift+E { quit; } | |
| Mod+Left { focus-column-left; } | |
| Mod+Right { focus-column-right; } | |
| Mod+Up { focus-window-up; } | |
| Mod+Down { focus-window-down; } | |
| Mod+Shift+Left { move-column-left; } | |
| Mod+Shift+Right { move-column-right; } | |
| Mod+1 { focus-workspace 1; } | |
| Mod+2 { focus-workspace 2; } | |
| Mod+3 { focus-workspace 3; } | |
| Mod+4 { focus-workspace 4; } | |
| Mod+R { switch-preset-column-width; } | |
| Mod+F { maximize-column; } | |
| Mod+Shift+F { fullscreen-window; } | |
| XF86AudioRaiseVolume { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "5%+"; } | |
| XF86AudioLowerVolume { spawn "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "5%-"; } | |
| XF86AudioMute { spawn "wpctl" "set-mute" "@DEFAULT_AUDIO_SINK@" "toggle"; } | |
| XF86MonBrightnessUp { spawn "brightnessctl" "set" "5%+"; } | |
| XF86MonBrightnessDown { spawn "brightnessctl" "set" "5%-"; } | |
| } | |
| EOF | |
| ok "Starter Niri config written (scale=${scale_hint})" | |
| } | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # 13. dms doctor — final health check | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| dms_doctor() { | |
| section "dms doctor (health check)" | |
| if ! have dms; then | |
| warn "dms CLI not on PATH — skipping doctor check" | |
| return | |
| fi | |
| if dms doctor; then | |
| ok "dms doctor reports a clean install" | |
| else | |
| warn "dms doctor flagged some issues — review output above. Most resolve after reboot." | |
| fi | |
| } | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # 14. Done | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| post_install() { | |
| section "Done" | |
| local sys_vendor; sys_vendor=$(detect_sys_vendor) | |
| cat <<'EOF' | |
| ╭─ start.sh complete ─────────────────────────────────────╮ | |
| │ │ | |
| │ Reboot, then log in via dms-greeter. │ | |
| │ Niri + DMS will start automatically. │ | |
| │ │ | |
| │ After first login: │ | |
| │ • The greeter will auto-sync to your DMS theme │ | |
| │ whenever you change wallpaper or settings. │ | |
| │ • Run `dms greeter sync` manually if you want to │ | |
| │ force a sync right away (the first time, you'll │ | |
| │ need to log out and back in for group membership │ | |
| │ changes to take effect). │ | |
| │ │ | |
| │ For the personalization layer: │ | |
| │ curl -fsSL https://install.reinierladan.nl/nice | sh │ | |
| │ │ | |
| ╰──────────────────────────────────────────────────────────╯ | |
| EOF | |
| if [[ "$sys_vendor" == "framework" ]]; then | |
| cat <<'EOF' | |
| ╭─ Framework: WiFi backend ────────────────────────────────╮ | |
| │ │ | |
| │ iwd is configured as NetworkManager's WiFi backend. │ | |
| │ Active after reboot. Verify with: │ | |
| │ │ | |
| │ systemctl status iwd NetworkManager │ | |
| │ nmcli device │ | |
| │ journalctl -u iwd | grep 'state.*connected' │ | |
| │ │ | |
| │ MAC randomization is per-SSID (consistent per network, │ | |
| │ random across networks). Edit /etc/iwd/main.conf to │ | |
| │ change this. │ | |
| │ │ | |
| ╰──────────────────────────────────────────────────────────╯ | |
| EOF | |
| fi | |
| if [[ "$sys_vendor" == "apple" ]]; then | |
| cat <<'EOF' | |
| ╭─ Apple hardware notes ──────────────────────────────────╮ | |
| │ │ | |
| │ Before reboot, regenerate initramfs to pick up the │ | |
| │ Broadcom driver and applesmc: │ | |
| │ │ | |
| │ sudo mkinitcpio -P │ | |
| │ │ | |
| │ After reboot: │ | |
| │ • Wi-Fi: should work automatically (broadcom-wl) │ | |
| │ • Function keys behave as F1-F12 (fnmode=2) │ | |
| │ Hold Fn for brightness/volume/media │ | |
| │ • Sleep: deep mode active (better battery) │ | |
| │ • Performance: this is a Y-series 5W CPU. Be kind. │ | |
| │ Lean on Firefox over Chromium for daily browsing. │ | |
| │ │ | |
| ╰──────────────────────────────────────────────────────────╯ | |
| EOF | |
| fi | |
| } | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| # Entry point | |
| # ───────────────────────────────────────────────────────────────────────────── | |
| main() { | |
| preflight | |
| base_system | |
| remove_i3_cruft | |
| compositor_stack | |
| dms_stack | |
| login_stack | |
| greeter_autosync | |
| terminal | |
| hardware_tuning | |
| locale_setup | |
| theming | |
| niri_config | |
| dms_doctor | |
| post_install | |
| } | |
| main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment