aurorae49fa93
hyprlock: glyph-rice's lock screen look, fed by aurora
hyprlock now replicates the lock screen from glyph-rice in aurora's colours: the wallpaper as aurora draws it, a huge Doto clock with a blinking colon, date and weather / now playing in spaced caps, battery top right, the avatar in a ring of dots, your name, and the password pill (typed = dots, empty = the live caret and six unlit dots). - LockArt.qml (in the first screen's Back) saves ~/.cache/aurora/lock-wall.png (the WallView in any look) and lock-face.png (Ring + DotArt avatar) whenever they change; hyprlock can't draw aurora's dots itself. - Theme.qml adds markup colours ($xHex) and $hourFmt/$blink/$batLow to hyprlock-colors.conf. - .local/bin/hypr/lockinfo prints the live labels (clock, weather from aurora's cache + playerctl, battery) as Pango markup.
+194 −43
5 files changed
- M .config/hypr/hyprlock.conf +88 −42
- M .config/quickshell/aurora/Back.qml +5 −0
- A .config/quickshell/aurora/LockArt.qml +49 −0
- M .config/quickshell/aurora/Theme.qml +7 −1
- A .local/bin/hypr/lockinfo +45 −0
| @@ -1,103 +1,149 @@ | |||
| 1 | − | # hyprlock in aurora's Nothing look (after glyph-rice's lock screen): a huge Doto clock, the date in spaced caps, | |
| 2 | − | # your name, the password as round dots in a pill, status in Space Mono at the bottom corners. | |
| 3 | − | # Colours / fonts: matugen's output first as a fallback, then aurora's resolved palette | |
| 4 | − | # (~/.config/aurora/hyprlock-colors.conf, written by aurora's Theme.qml). | |
| 1 | + | # hyprlock in aurora's Nothing look, after glyph-rice's lock screen: the wallpaper as aurora draws it, a huge Doto clock | |
| 2 | + | # (the colon blinks), the date and weather / what's playing in spaced caps, battery top right; at the bottom your face in | |
| 3 | + | # a ring of dots, your name and the password pill: typed characters are dots, empty = the live caret and six unlit dots. | |
| 4 | + | # Colours / fonts / clock settings: matugen's output first as a fallback, then aurora's resolved palette | |
| 5 | + | # (~/.config/aurora/hyprlock-colors.conf, written by aurora's Theme.qml; `$xHex` = for Pango markup). | |
| 6 | + | # Pictures: ~/.cache/aurora/lock-wall.png + lock-face.png (aurora's LockArt.qml). Live labels: ~/.local/bin/hypr/lockinfo. | |
| 7 | + | # Positions = the centres of glyph's 1920x1080 layout (y up from the middle); sizes in pt = px * 3/4. | |
| 5 | 8 | $dot = Doto Black | |
| 6 | 9 | $ui = Space Grotesk | |
| 7 | 10 | $mono = Space Mono | |
| 11 | + | $fgHex = ##e0e0e0 | |
| 12 | + | $s3Hex = ##404040 | |
| 13 | + | $greyHex = ##909090 | |
| 14 | + | $liveHex = ##e0d080 | |
| 15 | + | $errHex = ##ffb4ab | |
| 16 | + | $hourFmt = %H | |
| 17 | + | $blink = 1 | |
| 18 | + | $batLow = 15 | |
| 8 | 19 | source = $HOME/.cache/matugen/hyprlock.conf | |
| 9 | 20 | source = $HOME/.config/aurora/hyprlock-colors.conf | |
| 10 | 21 | ||
| 11 | 22 | general { | |
| 12 | 23 | hide_cursor = true | |
| 13 | 24 | ignore_empty_input = true | |
| 25 | + | fail_timeout = 2500 | |
| 26 | + | } | |
| 27 | + | ||
| 28 | + | # glyph's timing: everything comes in over 1.1s with aurora's glide, leaves in 0.45s, typed dots pop in 180ms | |
| 29 | + | animations { | |
| 30 | + | enabled = true | |
| 31 | + | bezier = glide, 0.25, 1, 0.5, 1 | |
| 32 | + | animation = fadeIn, 1, 11, glide | |
| 33 | + | animation = fadeOut, 1, 4.5, glide | |
| 34 | + | animation = inputFieldDots, 1, 1.8, glide | |
| 35 | + | animation = inputFieldColors, 1, 3, glide | |
| 36 | + | animation = inputFieldWidth, 1, 3, glide | |
| 14 | 37 | } | |
| 15 | 38 | ||
| 16 | 39 | background { | |
| 17 | 40 | monitor = | |
| 41 | + | path = ~/.cache/aurora/lock-wall.png | |
| 18 | 42 | color = $bg | |
| 19 | 43 | } | |
| 20 | 44 | ||
| 21 | − | # -- time / date -- | |
| 45 | + | # -- date · clock · weather and music -- | |
| 22 | 46 | label { | |
| 23 | 47 | monitor = | |
| 24 | − | # round dots: Pango takes the variation axes after the size, so they go in the markup, not font_family | |
| 25 | − | text = cmd[update:1000] echo "<span font_desc='Doto 190 @ROND=100,wght=900'>$(date +%H:%M)</span>" | |
| 48 | + | text = cmd[update:60000] echo "<span size='10.5pt' letter_spacing='1505' text_transform='uppercase'>$(date '+%A · %-d %B')</span>" | |
| 26 | 49 | color = $fg | |
| 27 | − | font_size = 190 | |
| 50 | + | font_size = 10 | |
| 51 | + | font_family = $mono | |
| 52 | + | position = 0, 360 | |
| 53 | + | halign = center | |
| 54 | + | valign = center | |
| 55 | + | } | |
| 56 | + | ||
| 57 | + | label { | |
| 58 | + | monitor = | |
| 59 | + | # Doto 400px; round dots need the variation axes in the markup | |
| 60 | + | text = cmd[update:500] ~/.local/bin/hypr/lockinfo clock '$hourFmt' $blink 'Doto 300 @ROND=100,wght=900' | |
| 61 | + | color = $fg | |
| 62 | + | font_size = 300 | |
| 28 | 63 | font_family = $dot | |
| 29 | − | position = 0, 210 | |
| 64 | + | position = 0, 140 | |
| 65 | + | halign = center | |
| 66 | + | valign = center | |
| 67 | + | } | |
| 68 | + | ||
| 69 | + | label { | |
| 70 | + | monitor = | |
| 71 | + | text = cmd[update:15000] ~/.local/bin/hypr/lockinfo info | |
| 72 | + | color = $grey | |
| 73 | + | font_size = 9 | |
| 74 | + | font_family = $mono | |
| 75 | + | position = 0, -69 | |
| 30 | 76 | halign = center | |
| 31 | 77 | valign = center | |
| 32 | 78 | } | |
| 33 | 79 | ||
| 80 | + | # -- battery, top right -- | |
| 34 | 81 | label { | |
| 35 | 82 | monitor = | |
| 36 | − | text = cmd[update:60000] echo "<span letter_spacing='3000'>$(date '+%A · %d %B · week %V' | tr a-z A-Z)</span>" | |
| 83 | + | text = cmd[update:30000] ~/.local/bin/hypr/lockinfo battery $batLow '$errHex' '$fgHex' | |
| 37 | 84 | color = $grey | |
| 38 | − | font_size = 12 | |
| 85 | + | font_size = 9 | |
| 39 | 86 | font_family = $mono | |
| 40 | − | position = 0, 40 | |
| 87 | + | position = -44, -36 | |
| 88 | + | halign = right | |
| 89 | + | valign = top | |
| 90 | + | } | |
| 91 | + | ||
| 92 | + | # -- you -- | |
| 93 | + | image { | |
| 94 | + | monitor = | |
| 95 | + | path = ~/.cache/aurora/lock-face.png | |
| 96 | + | size = 104 | |
| 97 | + | rounding = 0 | |
| 98 | + | border_size = 0 | |
| 99 | + | position = 0, -220 | |
| 41 | 100 | halign = center | |
| 42 | 101 | valign = center | |
| 43 | 102 | } | |
| 44 | 103 | ||
| 45 | − | # -- who -- | |
| 46 | 104 | label { | |
| 47 | 105 | monitor = | |
| 48 | − | text = cmd[update:0] echo "$USER" | |
| 106 | + | text = <span size='16.5pt'>$USER</span> | |
| 49 | 107 | color = $fg | |
| 50 | − | font_size = 22 | |
| 108 | + | font_size = 16 | |
| 51 | 109 | font_family = $ui | |
| 52 | − | position = 0, -80 | |
| 110 | + | position = 0, -298 | |
| 53 | 111 | halign = center | |
| 54 | 112 | valign = center | |
| 55 | 113 | } | |
| 56 | 114 | ||
| 57 | − | # -- password: round dots in a pill -- | |
| 115 | + | # -- password: dots in a pill; empty = the live caret and six unlit dots -- | |
| 58 | 116 | input-field { | |
| 59 | 117 | monitor = | |
| 60 | − | size = 360, 58 | |
| 118 | + | size = 380, 58 | |
| 61 | 119 | rounding = -1 | |
| 62 | 120 | outline_thickness = 1 | |
| 63 | 121 | outer_color = $s3 | |
| 64 | − | inner_color = $s2 | |
| 122 | + | inner_color = $s1 | |
| 65 | 123 | font_color = $fg | |
| 66 | 124 | font_family = $mono | |
| 67 | − | check_color = $fill | |
| 125 | + | check_color = $grey | |
| 68 | 126 | fail_color = $err | |
| 69 | 127 | capslock_color = $live | |
| 70 | − | dots_size = 0.24 | |
| 71 | − | dots_spacing = 0.55 | |
| 128 | + | dots_size = 0.19 | |
| 129 | + | dots_spacing = 1 | |
| 72 | 130 | dots_rounding = -1 | |
| 73 | 131 | dots_center = true | |
| 74 | 132 | fade_on_empty = false | |
| 75 | − | placeholder_text = <span letter_spacing='2000'>PASSWORD</span> | |
| 76 | − | fail_text = <span letter_spacing='2000'>$FAIL · $ATTEMPTS</span> | |
| 77 | − | position = 0, -150 | |
| 133 | + | placeholder_text = <span foreground='$liveHex'>│</span> <span foreground='$s3Hex' size='20.5pt' letter_spacing='8400'>●●●●●●</span> | |
| 134 | + | fail_text = <span foreground='$errHex' size='9pt' letter_spacing='1290' text_transform='uppercase'>wrong password · try again</span> | |
| 135 | + | position = 0, -357 | |
| 78 | 136 | halign = center | |
| 79 | 137 | valign = center | |
| 80 | 138 | } | |
| 81 | 139 | ||
| 82 | − | # -- status line -- | |
| 83 | 140 | label { | |
| 84 | 141 | monitor = | |
| 85 | − | text = cmd[update:0] echo "<span letter_spacing='2000'>$(echo "$USER@$(cat /etc/hostname)" | tr a-z A-Z)</span>" | |
| 142 | + | text = <span letter_spacing='1290' text_transform='uppercase'>enter password</span> | |
| 86 | 143 | color = $grey | |
| 87 | − | font_size = 10 | |
| 144 | + | font_size = 9 | |
| 88 | 145 | font_family = $mono | |
| 89 | − | position = 40, 30 | |
| 90 | − | halign = left | |
| 91 | − | valign = bottom | |
| 92 | − | } | |
| 93 | − | ||
| 94 | − | label { | |
| 95 | − | monitor = | |
| 96 | − | text = cmd[update:5000] echo "<span letter_spacing='2000'>$(mpc current 2>/dev/null | tr a-z A-Z | sed 's/&/\&/g; s/</\</g') BATTERY $(cat /sys/class/power_supply/BAT0/capacity)%</span>" | |
| 97 | − | color = $grey | |
| 98 | − | font_size = 10 | |
| 99 | − | font_family = $mono | |
| 100 | − | position = -40, 30 | |
| 101 | − | halign = right | |
| 102 | − | valign = bottom | |
| 146 | + | position = 0, -411 | |
| 147 | + | halign = center | |
| 148 | + | valign = center | |
| 103 | 149 | } | |
| @@ -45,4 +45,9 @@ PanelWindow { | |||
| 45 | 45 | anchors.fill: parent | |
| 46 | 46 | path: Wall.current | |
| 47 | 47 | } | |
| 48 | + | // hyprlock's wallpaper + avatar pictures, from the first screen | |
| 49 | + | Loader { | |
| 50 | + | active: win.modelData === Quickshell.screens[0] | |
| 51 | + | sourceComponent: LockArt { view: wall } | |
| 52 | + | } | |
| 48 | 53 | } | |
| @@ -0,0 +1,49 @@ | |||
| 1 | + | import QtQuick | |
| 2 | + | import Quickshell | |
| 3 | + | import Quickshell.Io | |
| 4 | + | ||
| 5 | + | // hyprlock's pictures (hypr/hyprlock.conf; hyprlock can't draw aurora's dots): the wallpaper exactly as Back draws it | |
| 6 | + | // (any Settings.wallLook) and your face (~/.face, else DotArt's gradient) in a ring of dots, saved as | |
| 7 | + | // ~/.cache/aurora/lock-wall.png / lock-face.png whenever they change. No wallpaper = no lock-wall.png (hyprlock shows $bg). | |
| 8 | + | // One screen's Back holds it: aurora has one wallpaper for every monitor, hyprlock scales it. | |
| 9 | + | Item { | |
| 10 | + | id: root | |
| 11 | + | ||
| 12 | + | required property WallView view // Back's (not `wall`: `wall: wall` would bind to itself) | |
| 13 | + | readonly property string dir: Quickshell.env("HOME") + "/.cache/aurora" | |
| 14 | + | ||
| 15 | + | // everything that changes the pictures; saved once it all settled (the wallpaper wave, the look's blend, colour waves) | |
| 16 | + | readonly property string key: [view.shown, view.opaque, view.look, view.pitch, view.bright, view.width, view.height, | |
| 17 | + | Theme.bg, Theme.fg, Theme.fill, Theme.s1, Theme.s3, hasFace].join("|") | |
| 18 | + | onKeyChanged: settle.restart() | |
| 19 | + | Timer { id: settle; interval: 2500; onTriggered: root.save() } | |
| 20 | + | ||
| 21 | + | function save() { | |
| 22 | + | if (view.opaque) view.grabToImage(r => r.saveToFile(dir + "/lock-wall.png")) | |
| 23 | + | else Quickshell.execDetached(["rm", "-f", dir + "/lock-wall.png"]) | |
| 24 | + | face.grabToImage(r => r.saveToFile(dir + "/lock-face.png")) | |
| 25 | + | } | |
| 26 | + | ||
| 27 | + | property bool hasFace: false // checked first: a missing ~/.face would only warn in DotArt | |
| 28 | + | FileView { | |
| 29 | + | path: Quickshell.env("HOME") + "/.face" | |
| 30 | + | printErrors: false | |
| 31 | + | onLoaded: root.hasFace = true | |
| 32 | + | onLoadFailed: root.hasFace = false | |
| 33 | + | } | |
| 34 | + | ||
| 35 | + | // the avatar as glyph's lock screen draws it; off-screen, only ever grabbed | |
| 36 | + | Item { | |
| 37 | + | id: face | |
| 38 | + | x: -width - 100 | |
| 39 | + | width: 104 | |
| 40 | + | height: 104 | |
| 41 | + | Ring { anchors.fill: parent; anchors.margins: 4; n: 32; dot: 5 } | |
| 42 | + | DotArt { | |
| 43 | + | anchors.fill: parent | |
| 44 | + | anchors.margins: 22 | |
| 45 | + | url: root.hasFace ? "file://" + Quickshell.env("HOME") + "/.face" : "" | |
| 46 | + | step: 3 | |
| 47 | + | } | |
| 48 | + | } | |
| 49 | + | } | |
| @@ -97,17 +97,23 @@ Singleton { | |||
| 97 | 97 | ||
| 98 | 98 | // ---- hyprlock ----------------------------------------------------- | |
| 99 | 99 | // hyprlock stays a separate process (crash safety); it sources ~/.config/aurora/hyprlock-colors.conf, | |
| 100 | − | // written here so the lock uses the resolved palette (incl. the settings-picked accent). | |
| 100 | + | // written here so the lock uses the resolved palette (incl. the settings-picked accent). `$xHex` = "##rrggbb" for | |
| 101 | + | // Pango markup (hyprlang reads "##" as "#"), plus the clock/battery settings its labels need (~/.local/bin/hypr/lockinfo). | |
| 102 | + | // Its pictures (the wallpaper as drawn here, the avatar ring) are LockArt's. | |
| 101 | 103 | readonly property string lockFile: Quickshell.env("HOME") + "/.config/aurora/hyprlock-colors.conf" | |
| 102 | 104 | readonly property string lockConf: { | |
| 103 | 105 | function c(v) { | |
| 104 | 106 | var h = n => ("0" + Math.round(n * 255).toString(16)).slice(-2) | |
| 105 | 107 | return "rgba(" + h(v.r) + h(v.g) + h(v.b) + h(v.a) + ")" | |
| 106 | 108 | } | |
| 109 | + | function x(v) { return "##" + hex(v).toLowerCase() } | |
| 107 | 110 | return ["# generated by aurora (Theme.qml); edit the palette there, not here", | |
| 108 | 111 | "$bg = " + c(bg), "$fg = " + c(fg), "$fgDim = " + c(fgDim), "$s1 = " + c(s1), "$s2 = " + c(s2), "$s3 = " + c(s3), | |
| 109 | 112 | "$mute = " + c(mute), "$grey = " + c(grey), "$fill = " + c(fill), "$fillFg = " + c(fillFg), "$live = " + c(live), | |
| 110 | 113 | "$err = " + c(err), "$dot = " + dot + " Black", "$ui = " + ui, "$mono = " + mono, | |
| 114 | + | "$fgHex = " + x(fg), "$s3Hex = " + x(s3), "$greyHex = " + x(grey), "$liveHex = " + x(live), "$errHex = " + x(err), | |
| 115 | + | "$hourFmt = " + (Settings.clock24 ? "%H" : "%-I"), "$blink = " + (Settings.blink ? 1 : 0), | |
| 116 | + | "$batLow = " + Settings.batLow, | |
| 111 | 117 | ""].join("\n") | |
| 112 | 118 | } | |
| 113 | 119 | onLockConfChanged: lockTimer.restart() | |
| @@ -0,0 +1,45 @@ | |||
| 1 | + | #!/bin/sh | |
| 2 | + | # hyprlock's live labels in aurora's look (~/.config/hypr/hyprlock.conf); prints Pango markup. | |
| 3 | + | # Colours and settings come from aurora's Theme.qml (~/.config/aurora/hyprlock-colors.conf) as arguments. | |
| 4 | + | # lockinfo clock HOURFMT BLINK FONT HH:MM in FONT (a Pango font_desc); the colon dims every other half second if BLINK=1 | |
| 5 | + | # lockinfo info weather from aurora's cache (if < 3h old) · what's playing | |
| 6 | + | # lockinfo battery LOW ERR FG battery glyph (FG, ERR at or below LOW% on battery) + percentage | |
| 7 | + | ||
| 8 | + | esc() { sed 's/&/\&/g; s/</\</g; s/>/\>/g'; } | |
| 9 | + | # aurora's Lb: Space Mono caps, tracking .14em (the label's font_size is 9pt = 12px) | |
| 10 | + | lb() { printf "<span letter_spacing='1290' text_transform='uppercase'>%s</span>" "$1"; } | |
| 11 | + | ||
| 12 | + | case "$1" in | |
| 13 | + | clock) | |
| 14 | + | set -- $(date +"$2 %M %N") "$3" "$4" | |
| 15 | + | colon=":" | |
| 16 | + | [ "$4" = 1 ] && [ "${3%"${3#?}"}" -ge 5 ] && colon="<span alpha='20%'>:</span>" | |
| 17 | + | printf "<span font_desc='%s'>%s%s%s</span>" "$5" "$1" "$colon" "$2" | |
| 18 | + | ;; | |
| 19 | + | info) | |
| 20 | + | f="$HOME/.cache/aurora/weather.json" | |
| 21 | + | w=$([ -r "$f" ] && jq -r 'select(now * 1000 - .fetched < 3 * 3600 * 1000) | .raw.current | .weather_code as $c | |
| 22 | + | | "\(.temperature_2m | round)° " + (if $c <= 1 then "clear" elif $c == 2 then "partly cloudy" | |
| 23 | + | elif $c == 3 then "overcast" elif $c < 50 then "fog" elif $c < 60 then "drizzle" elif $c < 70 then "rain" | |
| 24 | + | elif $c < 80 then "snow" elif $c < 83 then "showers" elif $c < 90 then "snow showers" else "thunder" end)' "$f" 2>/dev/null) | |
| 25 | + | m=$(playerctl metadata --format '{{title}} {{artist}}' 2>/dev/null) | |
| 26 | + | t=${m%% *} a=${m#* } | |
| 27 | + | [ -n "$t" ] && m="$t${a:+ — $a}" || m="" | |
| 28 | + | line=$(printf '%s\n%s\n' "$w" "$m" | sed '/^$/d' | esc | sed ':a;N;$!ba;s/\n/ · /') | |
| 29 | + | [ -n "$line" ] && lb "$line" | |
| 30 | + | ;; | |
| 31 | + | battery) | |
| 32 | + | b=$(ls -d /sys/class/power_supply/BAT* 2>/dev/null | head -n 1) | |
| 33 | + | [ -n "$b" ] || exit 0 | |
| 34 | + | p=$(cat "$b/capacity") s=$(cat "$b/status") | |
| 35 | + | # glyphs = Theme.qml's batIcon: charging, on AC, else 10 levels (Theme.batLevels) | |
| 36 | + | case "$s" in | |
| 37 | + | Charging) g=F0084 ;; | |
| 38 | + | Discharging) g=$(echo "F007A F007B F007C F007D F007E F007F F0080 F0081 F0082 F0079" | cut -d' ' -f$((p >= 100 ? 10 : p / 10 + 1))) ;; | |
| 39 | + | *) g=F06A5 ;; | |
| 40 | + | esac | |
| 41 | + | colour=$4 | |
| 42 | + | [ "$s" = Discharging ] && [ "$p" -le "$2" ] && colour=$3 | |
| 43 | + | printf "<span font_desc='JetBrainsMono Nerd Font 12.75' foreground='%s'>&#x%s;</span> %s" "$colour" "$g" "$(lb "$p%")" | |
| 44 | + | ;; | |
| 45 | + | esac | |