From 7a1304355a269333d1ae33d25a0f9e83adbec15e Mon Sep 17 00:00:00 2001 From: anshifmonz Date: Wed, 2 Sep 2026 10:31:31 +0530 Subject: [PATCH 1/4] feat(hypr/shaders): add GLSL and Frag screen shader presets --- .../hypr/shaders/blue-light-filter-25.glsl | 43 ++++++++++++++++++ .../hypr/shaders/blue-light-filter-50.glsl | 45 +++++++++++++++++++ .../hypr/shaders/blue-light-filter-75.glsl | 45 +++++++++++++++++++ dotfiles/.config/hypr/shaders/greyscale.frag | 11 +++++ .../.config/hypr/shaders/invert-colors.glsl | 10 +++++ dotfiles/.config/hypr/shaders/nightlight.frag | 11 +++++ dotfiles/.config/hypr/shaders/sepia.frag | 14 ++++++ 7 files changed, 179 insertions(+) create mode 100644 dotfiles/.config/hypr/shaders/blue-light-filter-25.glsl create mode 100644 dotfiles/.config/hypr/shaders/blue-light-filter-50.glsl create mode 100644 dotfiles/.config/hypr/shaders/blue-light-filter-75.glsl create mode 100644 dotfiles/.config/hypr/shaders/greyscale.frag create mode 100644 dotfiles/.config/hypr/shaders/invert-colors.glsl create mode 100644 dotfiles/.config/hypr/shaders/nightlight.frag create mode 100644 dotfiles/.config/hypr/shaders/sepia.frag diff --git a/dotfiles/.config/hypr/shaders/blue-light-filter-25.glsl b/dotfiles/.config/hypr/shaders/blue-light-filter-25.glsl new file mode 100644 index 000000000..c3f1da24a --- /dev/null +++ b/dotfiles/.config/hypr/shaders/blue-light-filter-25.glsl @@ -0,0 +1,43 @@ +#version 300 es +precision highp float; +in vec2 v_texcoord; +uniform sampler2D tex; +out vec4 fragColor; + +const float temperature = 3000.0; +const float temperatureStrength = 0.25; + +#define WithQuickAndDirtyLuminancePreservation +const float LuminancePreservationFactor = 1.0; + +// function from https://www.shadertoy.com/view/4sc3D7 +// valid from 1000 to 40000 K (and additionally 0 for pure full white) +vec3 colorTemperatureToRGB(const in float temperature) { + // values from: http://blenderartists.org/forum/showthread.php?270332-OSL-Goodness&p=2268693&viewfull=1#post2268693 + mat3 m = (temperature <= 6500.0) ? mat3(vec3(0.0, -2902.1955373783176, -8257.7997278925690), + vec3(0.0, 1669.5803561666639, 2575.2827530017594), + vec3(1.0, 1.3302673723350029, 1.8993753891711275)) + : mat3(vec3(1745.0425298314172, 1216.6168361476490, -8257.7997278925690), + vec3(-2666.3474220535695, -2173.1012343082230, 2575.2827530017594), + vec3(0.55995389139931482, 0.70381203140554553, 1.8993753891711275)); + return mix(clamp(vec3(m[0] / (vec3(clamp(temperature, 1000.0, 40000.0)) + m[1]) + m[2]), vec3(0.0), vec3(1.0)), + vec3(1.0), smoothstep(1000.0, 0.0, temperature)); +} + +void main() { + vec4 pixColor = texture(tex, v_texcoord); + + // RGB + vec3 color = vec3(pixColor[0], pixColor[1], pixColor[2]); + +#ifdef WithQuickAndDirtyLuminancePreservation + color *= mix(1.0, dot(color, vec3(0.2126, 0.7152, 0.0722)) / max(dot(color, vec3(0.2126, 0.7152, 0.0722)), 1e-5), + LuminancePreservationFactor); +#endif + + color = mix(color, color * colorTemperatureToRGB(temperature), temperatureStrength); + + vec4 outCol = vec4(color, pixColor[3]); + + fragColor = outCol; +} diff --git a/dotfiles/.config/hypr/shaders/blue-light-filter-50.glsl b/dotfiles/.config/hypr/shaders/blue-light-filter-50.glsl new file mode 100644 index 000000000..20199138f --- /dev/null +++ b/dotfiles/.config/hypr/shaders/blue-light-filter-50.glsl @@ -0,0 +1,45 @@ +#version 300 es +// from https://github.com/hyprwm/Hyprland/issues/1140#issuecomment-1335128437 + +precision highp float; +in vec2 v_texcoord; +uniform sampler2D tex; +out vec4 fragColor; + +const float temperature = 3000.0; +const float temperatureStrength = 0.5; + +#define WithQuickAndDirtyLuminancePreservation +const float LuminancePreservationFactor = 1.0; + +// function from https://www.shadertoy.com/view/4sc3D7 +// valid from 1000 to 40000 K (and additionally 0 for pure full white) +vec3 colorTemperatureToRGB(const in float temperature) { + // values from: http://blenderartists.org/forum/showthread.php?270332-OSL-Goodness&p=2268693&viewfull=1#post2268693 + mat3 m = (temperature <= 6500.0) ? mat3(vec3(0.0, -2902.1955373783176, -8257.7997278925690), + vec3(0.0, 1669.5803561666639, 2575.2827530017594), + vec3(1.0, 1.3302673723350029, 1.8993753891711275)) + : mat3(vec3(1745.0425298314172, 1216.6168361476490, -8257.7997278925690), + vec3(-2666.3474220535695, -2173.1012343082230, 2575.2827530017594), + vec3(0.55995389139931482, 0.70381203140554553, 1.8993753891711275)); + return mix(clamp(vec3(m[0] / (vec3(clamp(temperature, 1000.0, 40000.0)) + m[1]) + m[2]), vec3(0.0), vec3(1.0)), + vec3(1.0), smoothstep(1000.0, 0.0, temperature)); +} + +void main() { + vec4 pixColor = texture(tex, v_texcoord); + + // RGB + vec3 color = vec3(pixColor[0], pixColor[1], pixColor[2]); + +#ifdef WithQuickAndDirtyLuminancePreservation + color *= mix(1.0, dot(color, vec3(0.2126, 0.7152, 0.0722)) / max(dot(color, vec3(0.2126, 0.7152, 0.0722)), 1e-5), + LuminancePreservationFactor); +#endif + + color = mix(color, color * colorTemperatureToRGB(temperature), temperatureStrength); + + vec4 outCol = vec4(color, pixColor[3]); + + fragColor = outCol; +} diff --git a/dotfiles/.config/hypr/shaders/blue-light-filter-75.glsl b/dotfiles/.config/hypr/shaders/blue-light-filter-75.glsl new file mode 100644 index 000000000..df53e504a --- /dev/null +++ b/dotfiles/.config/hypr/shaders/blue-light-filter-75.glsl @@ -0,0 +1,45 @@ +#version 300 es +// from https://github.com/hyprwm/Hyprland/issues/1140#issuecomment-1335128437 + +precision highp float; +in vec2 v_texcoord; +uniform sampler2D tex; +out vec4 fragColor; + +const float temperature = 3000.0; +const float temperatureStrength = 0.75; + +#define WithQuickAndDirtyLuminancePreservation +const float LuminancePreservationFactor = 1.0; + +// function from https://www.shadertoy.com/view/4sc3D7 +// valid from 1000 to 40000 K (and additionally 0 for pure full white) +vec3 colorTemperatureToRGB(const in float temperature) { + // values from: http://blenderartists.org/forum/showthread.php?270332-OSL-Goodness&p=2268693&viewfull=1#post2268693 + mat3 m = (temperature <= 6500.0) ? mat3(vec3(0.0, -2902.1955373783176, -8257.7997278925690), + vec3(0.0, 1669.5803561666639, 2575.2827530017594), + vec3(1.0, 1.3302673723350029, 1.8993753891711275)) + : mat3(vec3(1745.0425298314172, 1216.6168361476490, -8257.7997278925690), + vec3(-2666.3474220535695, -2173.1012343082230, 2575.2827530017594), + vec3(0.55995389139931482, 0.70381203140554553, 1.8993753891711275)); + return mix(clamp(vec3(m[0] / (vec3(clamp(temperature, 1000.0, 40000.0)) + m[1]) + m[2]), vec3(0.0), vec3(1.0)), + vec3(1.0), smoothstep(1000.0, 0.0, temperature)); +} + +void main() { + vec4 pixColor = texture(tex, v_texcoord); + + // RGB + vec3 color = vec3(pixColor[0], pixColor[1], pixColor[2]); + +#ifdef WithQuickAndDirtyLuminancePreservation + color *= mix(1.0, dot(color, vec3(0.2126, 0.7152, 0.0722)) / max(dot(color, vec3(0.2126, 0.7152, 0.0722)), 1e-5), + LuminancePreservationFactor); +#endif + + color = mix(color, color * colorTemperatureToRGB(temperature), temperatureStrength); + + vec4 outCol = vec4(color, pixColor[3]); + + fragColor = outCol; +} diff --git a/dotfiles/.config/hypr/shaders/greyscale.frag b/dotfiles/.config/hypr/shaders/greyscale.frag new file mode 100644 index 000000000..068dbae3a --- /dev/null +++ b/dotfiles/.config/hypr/shaders/greyscale.frag @@ -0,0 +1,11 @@ +#version 300 es +precision mediump float; +in vec2 v_texcoord; +out vec4 fragColor; +uniform sampler2D tex; + +void main() { + vec4 color = texture(tex, v_texcoord); + float gray = dot(color.rgb, vec3(0.299, 0.587, 0.114)); + fragColor = vec4(vec3(gray), color.a); +} diff --git a/dotfiles/.config/hypr/shaders/invert-colors.glsl b/dotfiles/.config/hypr/shaders/invert-colors.glsl new file mode 100644 index 000000000..ec50c29f5 --- /dev/null +++ b/dotfiles/.config/hypr/shaders/invert-colors.glsl @@ -0,0 +1,10 @@ +#version 300 es +precision highp float; +in vec2 v_texcoord; +uniform sampler2D tex; +out vec4 fragColor; + +void main() { + vec4 pixColor = texture(tex, v_texcoord); + fragColor = vec4(1.0 - pixColor.r, 1.0 - pixColor.g, 1.0 - pixColor.b, pixColor.a); +} diff --git a/dotfiles/.config/hypr/shaders/nightlight.frag b/dotfiles/.config/hypr/shaders/nightlight.frag new file mode 100644 index 000000000..7e982cd0d --- /dev/null +++ b/dotfiles/.config/hypr/shaders/nightlight.frag @@ -0,0 +1,11 @@ +#version 300 es +precision mediump float; +in vec2 v_texcoord; +out vec4 fragColor; +uniform sampler2D tex; + +void main() { + vec4 color = texture(tex, v_texcoord); + vec3 warm = vec3(color.r * 1.0, color.g * 0.82, color.b * 0.45); + fragColor = vec4(warm, color.a); +} diff --git a/dotfiles/.config/hypr/shaders/sepia.frag b/dotfiles/.config/hypr/shaders/sepia.frag new file mode 100644 index 000000000..c58fa388a --- /dev/null +++ b/dotfiles/.config/hypr/shaders/sepia.frag @@ -0,0 +1,14 @@ +#version 300 es +precision mediump float; +in vec2 v_texcoord; +out vec4 fragColor; +uniform sampler2D tex; + +void main() { + vec4 color = texture(tex, v_texcoord); + vec3 sepia; + sepia.r = dot(color.rgb, vec3(0.393, 0.769, 0.189)); + sepia.g = dot(color.rgb, vec3(0.349, 0.686, 0.168)); + sepia.b = dot(color.rgb, vec3(0.272, 0.534, 0.131)); + fragColor = vec4(sepia, color.a); +} From 4b6e5a9f41fdf3d55bbec7cc18c33937a33dc356 Mon Sep 17 00:00:00 2001 From: anshifmonz Date: Wed, 2 Sep 2026 10:37:34 +0530 Subject: [PATCH 2/4] feat(hypr/scripts): add native screen-filter utility with rofi selector --- .../.config/hypr/scripts/screen-filter.sh | 317 ++++++++++++++++++ 1 file changed, 317 insertions(+) create mode 100755 dotfiles/.config/hypr/scripts/screen-filter.sh diff --git a/dotfiles/.config/hypr/scripts/screen-filter.sh b/dotfiles/.config/hypr/scripts/screen-filter.sh new file mode 100755 index 000000000..a08b9f1b7 --- /dev/null +++ b/dotfiles/.config/hypr/scripts/screen-filter.sh @@ -0,0 +1,317 @@ +#!/usr/bin/env bash + +set -Eeuo pipefail + +SHADER_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/hypr/shaders" +STATE_FILE="${XDG_STATE_HOME:-$HOME/.local/state}/hypr/screen-filter" +APP_NAME="Screen Filter" +NOTIFICATION_ID="screen-filter" + +if [[ -z "${HYPRLAND_INSTANCE_SIGNATURE:-}" ]] || ! command -v hyprctl >/dev/null 2>&1; then + echo "Error: Hyprland instance not detected or hyprctl missing." >&2 + exit 1 +fi + +mkdir -p "$SHADER_DIR" + +notify() { + local title="$1" + local msg="$2" + local icon="${3:-video-display}" + local timeout="${4:-1500}" + + if command -v notify-send >/dev/null 2>&1; then + notify-send "$title" "$msg" \ + -a "$APP_NAME" \ + -i "$icon" \ + -h "string:x-canonical-private-synchronous:$NOTIFICATION_ID" \ + -t "$timeout" 2>/dev/null || true + fi +} + +save_state() { + local filter_name="$1" + mkdir -p "$(dirname "$STATE_FILE")" 2>/dev/null || true + echo "$filter_name" > "$STATE_FILE" 2>/dev/null || true +} + +apply_shader() { + local target="${1:-}" + hyprctl eval "hl.config({ decoration = { screen_shader = '$target' } })" >/dev/null 2>&1 || \ + hyprctl keyword decoration:screen_shader "$target" >/dev/null 2>&1 +} + +get_active_shader() { + local path + path=$(hyprctl getoption decoration:screen_shader 2>/dev/null | awk -F': ' '/str:/ {print $2}' | tr -d '[]' | xargs) + if [[ -n "$path" && "$path" != "EMPTY" && "$path" != "null" ]]; then + echo "$path" + else + echo "" + fi +} + +get_available_filters() { + local available=("none") + local default_order=("greyscale" "nightlight" "sepia" "invert-colors") + + for name in "${default_order[@]}"; do + if [[ -f "$SHADER_DIR/${name}.frag" || -f "$SHADER_DIR/${name}.glsl" ]]; then + available+=("$name") + fi + done + + while IFS= read -r -d '' file; do + local base + base="$(basename "$file")" + base="${base%.*}" + + local exists=0 + for item in "${available[@]}"; do + if [[ "$item" == "$base" ]]; then + exists=1 + break + fi + done + [[ $exists -eq 0 ]] && available+=("$base") + done < <(find "$SHADER_DIR" -maxdepth 1 \( -name "*.frag" -o -name "*.glsl" \) -print0 2>/dev/null) + + printf '%s\n' "${available[@]}" +} + +resolve_shader_file() { + local name="$1" + if [[ -f "$SHADER_DIR/${name}.frag" ]]; then + echo "$SHADER_DIR/${name}.frag" + elif [[ -f "$SHADER_DIR/${name}.glsl" ]]; then + echo "$SHADER_DIR/${name}.glsl" + else + echo "" + fi +} + +format_title() { + local raw="$1" + if [[ "$raw" == "none" ]]; then + echo "Turn Off (Disabled)" + return + fi + if [[ "$raw" == "greyscale" ]]; then + echo "Grayscale" + return + fi + if [[ "$raw" =~ ^blue-light-filter-([0-9]+)$ ]]; then + echo "Blue Light Filter (${BASH_REMATCH[1]}%)" + return + fi + echo "$raw" | sed -E 's/[-_]+/ /g' | awk '{for(i=1;i<=NF;i++) $i=toupper(substr($i,1,1)) tolower(substr($i,2))}1' +} + +cycle_filter() { + mapfile -t FILTERS < <(get_available_filters) + + if (( ${#FILTERS[@]} <= 1 )); then + apply_shader "" + save_state "none" + notify "🖥️ $APP_NAME" "No shader files found in $SHADER_DIR" "dialog-warning" 2500 + exit 0 + fi + + local current_path + current_path="$(get_active_shader)" + local current_filter="none" + + if [[ -n "$current_path" ]]; then + local filename + filename="$(basename "$current_path")" + current_filter="${filename%.*}" + fi + + local current_idx=0 + for i in "${!FILTERS[@]}"; do + if [[ "${FILTERS[$i]}" == "$current_filter" ]]; then + current_idx=$i + break + fi + done + + local next_idx=$(( (current_idx + 1) % ${#FILTERS[@]} )) + local next_filter="${FILTERS[$next_idx]}" + + if [[ "$next_filter" == "none" ]]; then + apply_shader "" + save_state "none" + notify "🖥️ $APP_NAME" "Filter Disabled" "video-display" 1500 + else + local target_file + target_file="$(resolve_shader_file "$next_filter")" + if [[ -n "$target_file" && -f "$target_file" ]]; then + apply_shader "$target_file" + save_state "$next_filter" + local display_name + display_name="$(format_title "$next_filter")" + notify "🖥️ $APP_NAME" "Active: $display_name" "video-display" 1500 + else + apply_shader "" + save_state "none" + notify "🖥️ $APP_NAME" "Filter Disabled (Missing File)" "dialog-warning" 2000 + fi + fi +} + +rofi_menu() { + if ! command -v rofi >/dev/null 2>&1; then + echo "Error: rofi is not installed." >&2 + exit 1 + fi + + mapfile -t available_raw < <(get_available_filters) + if (( ${#available_raw[@]} == 0 )); then + notify "🖥️ $APP_NAME" "No shader files found in $SHADER_DIR" "dialog-warning" 2500 + exit 0 + fi + + local current_path + current_path="$(get_active_shader)" + local current_filter="none" + if [[ -n "$current_path" ]]; then + local filename + filename="$(basename "$current_path")" + current_filter="${filename%.*}" + fi + + local rofi_lines=() + local mapping=() + local active_idx=0 + + for idx in "${!available_raw[@]}"; do + local name="${available_raw[$idx]}" + local display + display="$(format_title "$name")" + + if [[ "$name" == "$current_filter" ]]; then + active_idx=$idx + display="✓ $display (Active)" + else + display=" $display" + fi + + rofi_lines+=("$display") + mapping+=("$name") + done + + local rofi_theme_arg=() + local rofi_dir="${XDG_CONFIG_HOME:-$HOME/.config}/rofi" + if [[ -f "$rofi_dir/config-compact.rasi" ]]; then + rofi_theme_arg=(-config "$rofi_dir/config-compact.rasi") + elif [[ -f "$rofi_dir/config-short.rasi" ]]; then + rofi_theme_arg=(-config "$rofi_dir/config-short.rasi") + elif [[ -f "$rofi_dir/config.rasi" ]]; then + rofi_theme_arg=(-config "$rofi_dir/config.rasi") + fi + + local lines_count=${#rofi_lines[@]} + local selected_idx + selected_idx=$(printf '%s\n' "${rofi_lines[@]}" | rofi -dmenu -i -replace "${rofi_theme_arg[@]}" -no-show-icons -l "$lines_count" -p "Screen Filter" -selected-row "$active_idx" -format "i" 2>/dev/null || true) + + if [[ -z "$selected_idx" ]]; then + exit 0 + fi + + local chosen="${mapping[$selected_idx]}" + if [[ "$chosen" == "none" ]]; then + apply_shader "" + save_state "none" + notify "🖥️ $APP_NAME" "Filter Disabled" "video-display" 1500 + else + local target_file + target_file="$(resolve_shader_file "$chosen")" + if [[ -n "$target_file" && -f "$target_file" ]]; then + apply_shader "$target_file" + save_state "$chosen" + local display_name + display_name="$(format_title "$chosen")" + notify "🖥️ $APP_NAME" "Active: $display_name" "video-display" 1500 + fi + fi +} + +restore_state() { + if [[ -f "$STATE_FILE" ]]; then + local saved_filter + saved_filter=$(<"$STATE_FILE") + if [[ -n "$saved_filter" && "$saved_filter" != "none" ]]; then + local target_file + target_file="$(resolve_shader_file "$saved_filter")" + if [[ -n "$target_file" && -f "$target_file" ]]; then + apply_shader "$target_file" + exit 0 + fi + fi + fi + apply_shader "" +} + +case "${1:-cycle}" in + cycle|next) + cycle_filter + ;; + -m|--menu|menu|rofi) + rofi_menu + ;; + restore|init) + restore_state + ;; + off|none|clear|disable) + apply_shader "" + save_state "none" + notify "🖥️ $APP_NAME" "Filter Disabled" "video-display" 1500 + ;; + status) + active="$(get_active_shader)" + if [[ -n "$active" ]]; then + echo "Active shader: $(basename "$active") ($active)" + else + echo "Active shader: None (Disabled)" + fi + ;; + list) + echo "Available shaders in $SHADER_DIR:" + get_available_filters + ;; + set|on) + if [[ -z "${2:-}" ]]; then + echo "Usage: $(basename "$0") set " >&2 + exit 1 + fi + target_file="$(resolve_shader_file "$2")" + if [[ -n "$target_file" ]]; then + apply_shader "$target_file" + save_state "$2" + display_name="$(format_title "$2")" + notify "🖥️ $APP_NAME" "Active: $display_name" "video-display" 1500 + else + echo "Error: Shader '$2' not found in $SHADER_DIR" >&2 + exit 1 + fi + ;; + -h|--help|help) + cat < Directly enable a specific shader + status Show currently active shader + list List all discoverable shaders + help, -h Show this help message +EOF + ;; + *) + echo "Unknown argument: $1. Use --help for usage." >&2 + exit 1 + ;; +esac From 251be5d8d89aaa15f11f7f682c296491bb416a3b Mon Sep 17 00:00:00 2001 From: anshifmonz Date: Wed, 2 Sep 2026 10:46:49 +0530 Subject: [PATCH 3/4] feat(hypr/conf): add keybindings for screen-filter cycling and menu --- dotfiles/.config/hypr/conf/keybindings/default.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dotfiles/.config/hypr/conf/keybindings/default.lua b/dotfiles/.config/hypr/conf/keybindings/default.lua index b8ac506bc..d2c98bec9 100644 --- a/dotfiles/.config/hypr/conf/keybindings/default.lua +++ b/dotfiles/.config/hypr/conf/keybindings/default.lua @@ -110,6 +110,9 @@ hl.bind(mainMod .. " + CTRL + L", hl.dsp.exec_cmd("~/.config/ml4w/scripts/ml4w-p hl.bind(mainMod .. " + SHIFT + H", hl.dsp.exec_cmd("~/.config/ml4w/scripts/ml4w-toggle-hyprsunset"), { description = "Toggle Hyprsunset" }) hl.bind(mainMod .. " + Tab", hl.dsp.exec_cmd("qs -p ~/.local/share/quickshell-overview ipc call overview toggle"), { description = "Open Select Window Menu" }) hl.bind("CTRL + ALT + T", hl.dsp.exec_cmd("~/.config/ml4w/themes/themes.sh"), { description = "Open Select Window Menu" }) +hl.bind(mainMod .. " + SHIFT + N", hl.dsp.exec_cmd("~/.config/hypr/scripts/screen-filter.sh"), { description = "Cycle screen color filters" }) +hl.bind(mainMod .. " + CTRL + N", hl.dsp.exec_cmd("~/.config/hypr/scripts/screen-filter.sh --menu"), { description = "Open screen filter menu" }) +hl.bind(mainMod .. " + ALT + N", hl.dsp.exec_cmd("~/.config/hypr/scripts/screen-filter.sh off"), { description = "Disable screen color filters" }) -- Special workspace (scratchpad) hl.bind(mainMod .. " + S", hl.dsp.workspace.toggle_special("scratchpad"), { description = "Toggle special workspace scratchpad" }) From 2480598122c10ea6019dbdc7ae8d6d4b3c94b472 Mon Sep 17 00:00:00 2001 From: anshifmonz Date: Wed, 2 Sep 2026 10:48:28 +0530 Subject: [PATCH 4/4] feat(hypr/conf): restore saved screen-filter state on autostart --- dotfiles/.config/hypr/conf/autostart.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dotfiles/.config/hypr/conf/autostart.lua b/dotfiles/.config/hypr/conf/autostart.lua index b35b3bbcf..f936d6ffc 100644 --- a/dotfiles/.config/hypr/conf/autostart.lua +++ b/dotfiles/.config/hypr/conf/autostart.lua @@ -53,4 +53,7 @@ hl.on("hyprland.start", function () -- Start autostart cleanup hl.exec_cmd("~/.config/hypr/scripts/cleanup.sh") + + -- Restore screen filter + hl.exec_cmd("~/.config/hypr/scripts/screen-filter.sh restore") end)