diff --git a/alacritty/alacritty.toml b/alacritty/alacritty.toml index c90ff73..c6a5d4c 100644 --- a/alacritty/alacritty.toml +++ b/alacritty/alacritty.toml @@ -13,7 +13,7 @@ position = "None" dynamic_padding = true decorations = "None" -## Fully opaque, no blur. Persona surfaces are flat ink on flat ground — +## Fully opaque, no blur. YoRHa surfaces are flat and opaque — ## glass and translucency read as a different design language entirely. opacity = 1.0 blur = false @@ -28,7 +28,7 @@ columns = 82 lines = 24 ## Blank space added around the window in pixels. Roomier than the old 3/0 — -## the text needs to sit inside the crimson border, not against it. +## the text needs to sit inside the border, not against it. [window.padding] x = 12 y = 8 @@ -107,7 +107,7 @@ ipc_socket = true ## GENERAL -------------------------------------------------------- ## Import additional configuration files. -import = ["~/.config/alacritty/catppuccin-mocha.toml", "~/.config/alacritty/fonts.toml"] +import = ["~/.config/alacritty/yorha.toml", "~/.config/alacritty/fonts.toml"] [[keyboard.bindings]] key = "Return" diff --git a/alacritty/yorha.toml b/alacritty/yorha.toml new file mode 100644 index 0000000..5ae9218 --- /dev/null +++ b/alacritty/yorha.toml @@ -0,0 +1,64 @@ +# YoRHa dark — matched to ~/.config/quickshell/config/Theme.qml. +# +# The ground and the text are the space-1 wallpaper's void and sage grey. The +# eight hues are the same few steps of earth NieR's world is painted in — +# rust, moss, sand, dusk — pulled down to sit in that void without glowing. +# Selection and search invert, the way NieR's cursor does. + +[colors.primary] +background = "#0f110e" +foreground = "#ccd2cb" +dim_foreground = "#79847a" +bright_foreground = "#eef1ea" + +[colors.cursor] +text = "#0f110e" +cursor = "#eef1ea" + +[colors.vi_mode_cursor] +text = "#0f110e" +cursor = "#bcc1bf" + +[colors.search.matches] +foreground = "#0f110e" +background = "#9fa7a2" + +[colors.search.focused_match] +foreground = "#0f110e" +background = "#eef1ea" + +[colors.footer_bar] +foreground = "#0f110e" +background = "#9fa7a2" + +[colors.hints.start] +foreground = "#0f110e" +background = "#c9b27c" + +[colors.hints.end] +foreground = "#0f110e" +background = "#9fa7a2" + +[colors.selection] +text = "#0f110e" +background = "#bcc1bf" + +[colors.normal] +black = "#20241f" +red = "#c8684f" +green = "#8fa37e" +yellow = "#c9b27c" +blue = "#7f9aa8" +magenta = "#a48ba0" +cyan = "#86a8a0" +white = "#bcc1bf" + +[colors.bright] +black = "#545c52" +red = "#d98068" +green = "#a5b893" +yellow = "#d8c491" +blue = "#96afbc" +magenta = "#b8a0b4" +cyan = "#9cbdb4" +white = "#eef1ea" diff --git a/dunst/dunstrc b/dunst/dunstrc index ff630eb..22bd503 100644 --- a/dunst/dunstrc +++ b/dunst/dunstrc @@ -1,22 +1,22 @@ [global] -corner_radius = 4 +corner_radius = 0 transparency = 90 -frame_color = "#89b4fa" +frame_color = "#545c52" frame_width = 1 separator_color= frame -highlight = "#cba6f7" +highlight = "#eef1ea" [urgency_low] -background = "#1e1e2e" -foreground = "#cdd6f4" +background = "#0f110e" +foreground = "#ccd2cb" timeout = 4 [urgency_normal] -background = "#1e1e2e" -foreground = "#cdd6f4" +background = "#0f110e" +foreground = "#ccd2cb" timeout = 6 [urgency_critical] -background = "#1e1e2e" -foreground = "#cdd6f4" -frame_color = "#f38ba8" +background = "#0f110e" +foreground = "#ccd2cb" +frame_color = "#c8684f" diff --git a/fish/conf.d/takemi_theme.fish b/fish/conf.d/takemi_theme.fish deleted file mode 100644 index 6d87c0e..0000000 --- a/fish/conf.d/takemi_theme.fish +++ /dev/null @@ -1,52 +0,0 @@ -# Mocha — matched to ~/.config/quickshell/config/Theme.qml, -# ~/.config/alacritty/catppuccin-mocha.toml and ~/.config/nvim/lua/takemi.lua. -# -# Catppuccin Mocha's own fish theme (themes/Catppuccin Mocha.theme), with the -# selection and pager rows carried over from the Takemi layout: a solid accent -# block with crust punched out of it, rather than a tinted surface. The shell -# selects with a blue slab and marks with mauve; the prompt should not -# disagree. -# -# Note that `fish_config` writing a theme from the web UI will recreate -# fish_frozen_theme.fish, which sorts before this file and so would lose. - -set --global fish_color_normal cdd6f4 -set --global fish_color_command 89b4fa -set --global fish_color_keyword f38ba8 -set --global fish_color_param f2cdcd -set --global fish_color_option a6e3a1 -set --global fish_color_quote a6e3a1 -set --global fish_color_escape eba0ac -set --global fish_color_operator f5c2e7 -set --global fish_color_redirection f5c2e7 -set --global fish_color_end fab387 -set --global fish_color_comment 7f849c --italics -set --global fish_color_error f38ba8 --bold -set --global fish_color_cancel f38ba8 -set --global fish_color_gray 6c7086 -set --global fish_color_autosuggestion 6c7086 -set --global fish_color_selection 11111b --background=89b4fa -set --global fish_color_search_match 11111b --background=cba6f7 -set --global fish_color_match 11111b --background=89b4fa -set --global fish_color_history_current --bold -set --global fish_color_valid_path --underline -set --global fish_color_cwd f9e2af --bold -set --global fish_color_cwd_root f38ba8 --bold -set --global fish_color_user 94e2d5 -set --global fish_color_host 89b4fa --bold -set --global fish_color_host_remote a6e3a1 -set --global fish_color_status f38ba8 - -set --global fish_pager_color_progress 6c7086 --background=313244 -set --global fish_pager_color_background -set --global fish_pager_color_prefix cba6f7 --bold -set --global fish_pager_color_completion cdd6f4 -set --global fish_pager_color_description 6c7086 -set --global fish_pager_color_secondary_background --background=181825 -set --global fish_pager_color_secondary_completion cdd6f4 -set --global fish_pager_color_secondary_description 6c7086 -set --global fish_pager_color_secondary_prefix cba6f7 --bold -set --global fish_pager_color_selected_background --background=89b4fa -set --global fish_pager_color_selected_completion 11111b -set --global fish_pager_color_selected_description 11111b -set --global fish_pager_color_selected_prefix 11111b --bold diff --git a/fish/conf.d/yorha_theme.fish b/fish/conf.d/yorha_theme.fish new file mode 100644 index 0000000..ae99bf1 --- /dev/null +++ b/fish/conf.d/yorha_theme.fish @@ -0,0 +1,51 @@ +# YoRHa dark — matched to ~/.config/quickshell/config/Theme.qml and +# ~/.config/alacritty/yorha.toml. +# +# Commands are the planet light, arguments the sage text, strings moss, +# anything wrong the hull red. Selection and the pager's current row invert — +# a light slab with the void punched out of it, the same cursor the shell +# draws. +# +# Note that `fish_config` writing a theme from the web UI will recreate +# fish_frozen_theme.fish, which sorts before this file and so would lose. + +set --global fish_color_normal ccd2cb +set --global fish_color_command eef1ea --bold +set --global fish_color_keyword c9b27c +set --global fish_color_param bcc1bf +set --global fish_color_option 9cbdb4 +set --global fish_color_quote 8fa37e +set --global fish_color_escape c9b27c +set --global fish_color_operator 9fa7a2 +set --global fish_color_redirection 9fa7a2 +set --global fish_color_end 79847a +set --global fish_color_comment 545c52 +set --global fish_color_error c8684f --bold +set --global fish_color_cancel c8684f +set --global fish_color_gray 545c52 +set --global fish_color_autosuggestion 545c52 +set --global fish_color_selection 0f110e --background=bcc1bf +set --global fish_color_search_match 0f110e --background=eef1ea +set --global fish_color_match 0f110e --background=bcc1bf +set --global fish_color_history_current --bold +set --global fish_color_valid_path --underline +set --global fish_color_cwd c9b27c --bold +set --global fish_color_cwd_root c8684f --bold +set --global fish_color_user 9cbdb4 +set --global fish_color_host eef1ea --bold +set --global fish_color_host_remote 8fa37e +set --global fish_color_status c8684f + +set --global fish_pager_color_progress 79847a --background=161915 +set --global fish_pager_color_background +set --global fish_pager_color_prefix eef1ea --bold +set --global fish_pager_color_completion ccd2cb +set --global fish_pager_color_description 79847a +set --global fish_pager_color_secondary_background --background=0c0d0b +set --global fish_pager_color_secondary_completion ccd2cb +set --global fish_pager_color_secondary_description 79847a +set --global fish_pager_color_secondary_prefix eef1ea --bold +set --global fish_pager_color_selected_background --background=eef1ea +set --global fish_pager_color_selected_completion 0f110e +set --global fish_pager_color_selected_description 0f110e +set --global fish_pager_color_selected_prefix 0f110e --bold diff --git a/hypr/hyprpaper.conf b/hypr/hyprpaper.conf index eb4f51c..11171c1 100644 --- a/hypr/hyprpaper.conf +++ b/hypr/hyprpaper.conf @@ -1,6 +1,6 @@ wallpaper { monitor = - path = ~/.wallpapers/arch.png + path = ~/.wallpapers/space-1.jpg fit_mode = cover } diff --git a/hypr/lua/look.lua b/hypr/lua/look.lua index 2df09f5..28937f8 100644 --- a/hypr/lua/look.lua +++ b/hypr/lua/look.lua @@ -1,5 +1,5 @@ --- Persona × Mocha — Persona 5 shapes on the Catppuccin Mocha palette, matched --- to ~/.config/quickshell. +-- YoRHa dark — NieR:Automata's interface language on the space-1 wallpaper's +-- palette, matched to ~/.config/quickshell. -- -- Everything static about how the desktop is painted. Motion lives next door -- in lua/animations.lua. @@ -9,17 +9,20 @@ local c = require("lua/palette") hl.config({ -- https://wiki.hypr.land/Configuring/Basics/Variables/ general = { + -- Measured from the quickshell hull's opening, not the screen edge: the + -- hull reserves its own exclusive zones. 10px clears the opening's 18px + -- corner radius, so a tiled window never touches the rim. gaps_in = 5, - gaps_out = { top = 6, right = 8, bottom = 8, left = 8 }, + gaps_out = 10, - border_size = 2, + border_size = 1, col = { active_border = c.activeBorder, - -- Surface-level, not outline: an idle window's frame is structure, + -- Overlay, not outline: an idle window's frame is structure, -- and the outline grey was bright enough to compete with the -- focused border. - inactive_border = c.surfaceAlt, + inactive_border = c.overlay, }, resize_on_border = false, @@ -32,29 +35,29 @@ hl.config({ }, decoration = { - -- Persona 5 has no rounded corners. Neither do we. + -- NieR panels are plain rectangles. The only curve on screen is the + -- porthole the quickshell hull cuts round the desktop. rounding = 0, -- Fully opaque, both states. Flat ink on flat ground. active_opacity = 1.0, inactive_opacity = 1.0, - -- A hard crust offset, the same printed drop the shell's panels - -- carry, rather than a soft blur. Sharp with a 1px range leaves a - -- clean band down the right and bottom edges only. + -- A soft, wide shadow: windows float in the opening rather than + -- being printed onto it. Dark against the planet light, invisible + -- against the void, which is how a shadow behaves out there. shadow = { enabled = true, - sharp = true, - range = 1, - offset = { 4, 4 }, - color = c.ink, - color_inactive = c.ink, + sharp = false, + range = 24, + render_power = 3, + offset = { 0, 6 }, + color = "rgba(000000aa)", + color_inactive = "rgba(00000066)", }, - -- Off. Blur is the signature of the glass-and-frost look, which is the - -- opposite of what this theme is doing — every surface here is opaque, - -- flat and hard-edged. With nothing translucent left to blur it also - -- costs three render passes for no visible result. + -- Off. Every surface here is opaque, so there is nothing to blur, and + -- blur would cost three render passes for no visible result. blur = { enabled = false, }, diff --git a/hypr/lua/palette.lua b/hypr/lua/palette.lua index a19fe90..7943d64 100644 --- a/hypr/lua/palette.lua +++ b/hypr/lua/palette.lua @@ -1,6 +1,7 @@ --- Mocha palette — kept in step with ~/.config/quickshell/config/Theme.qml. +-- YoRHa dark palette — kept in step with ~/.config/quickshell/config/Theme.qml. -- --- Catppuccin Mocha ground, blue accent, mauve alarm. Nothing else carries hue. +-- The wallpaper's grey-green void for the ground, its planet light as the +-- accent, the hull's red indicator as the alarm. Nothing else carries hue. -- -- Returned as a table, so every module that paints something does -- local c = require("lua/palette") @@ -9,44 +10,45 @@ local c = {} -- ---------------------------------------------------------------- THE KNOBS --- Two colours in this setup: blue for anything live (window borders, group --- indicators, focus), mauve for anything wrong. Change these lines and every +-- Two colours in this setup: the planet light for anything live (window +-- borders, group indicators, focus), the hull red for anything wrong. Change these lines and every -- painted edge recolours with them. -- -- Keep them in step with `accent` / `alarm` in -- ~/.config/quickshell/config/Theme.qml, which is what colours the shell. -- Those are the only places the colours are written. -c.accent = "rgb(89b4fa)" -c.alarm = "rgb(cba6f7)" +c.accent = "rgb(eef1ea)" +c.alarm = "rgb(c8684f)" -c.accentDim = "rgb(5a7dc0)" -c.accentSoft = "rgb(b4befe)" +c.accentDim = "rgb(8e978d)" +c.accentSoft = "rgb(bcc1bf)" -- ------------------------------------------------------------------ neutrals -c.ink = "rgb(11111b)" +c.ink = "rgb(090a08)" -c.base = "rgb(1e1e2e)" -c.mantle = "rgb(181825)" -c.surface = "rgb(313244)" -c.surfaceAlt = "rgb(45475a)" -c.overlay = "rgb(585b70)" -c.outline = "rgb(6c7086)" +c.base = "rgb(0f110e)" +c.mantle = "rgb(0c0d0b)" +c.surface = "rgb(161915)" +c.surfaceAlt = "rgb(20241f)" +c.overlay = "rgb(383e35)" +c.outline = "rgb(545c52)" -c.text = "rgb(cdd6f4)" -c.subtext = "rgb(a6adc8)" -c.muted = "rgb(7f849c)" +c.text = "rgb(ccd2cb)" +c.subtext = "rgb(9fa7a2)" +c.muted = "rgb(79847a)" -- Semantic aliases, so existing references resolve without inventing hues. c.primary = c.text -c.primaryDim = "rgb(9399b2)" +c.primaryDim = "rgb(8e978d)" c.glow = c.accent c.blue = c.accent c.deep = c.surfaceAlt c.warn = c.alarm c.ok = c.text --- Blue into lavender, on the diagonal. Both ends are the accent's own family, --- so the border never reads as two colours arguing. -c.activeBorder = { colors = { c.accent, c.accentSoft }, angle = 135 } +-- The focused window is lit by the planet: full light at the top-left, the +-- suit's grey at the far corner. One family, so it reads as light falling +-- across the frame rather than as two colours. +c.activeBorder = { colors = { c.accent, c.accentDim }, angle = 135 } return c diff --git a/quickshell/README.md b/quickshell/README.md index 32e6f97..bf6ec6d 100644 --- a/quickshell/README.md +++ b/quickshell/README.md @@ -1,10 +1,12 @@ -# Takemi — Persona × Mocha +# Takemi — YoRHa dark -A Persona 5 flavoured Quickshell desktop for Hyprland, painted in Catppuccin -Mocha. Blue for anything live, mauve for anything wrong, the Mocha greys for -everything else, and no gradients anywhere. Everything leans by the same 14°, -corners are chopped rather than rounded, and every surface is one continuous -slab divided by hairlines rather than a cluster of floating cards. +A NieR:Automata flavoured Quickshell desktop for Hyprland, kept dark and lit +like its wallpaper: a lone figure at a porthole, the void outside, one planet's +light. The planet white for anything live, the hull red for anything wrong, +grey-green for everything else. Hairlines, square markers, corner ticks, +letter-spaced capitals, and selection shown by inverting the row. The bar, the +rail and a thin border are one hull around the desktop, and the desktop is the +porthole cut out of it. Replaces Waybar, dunst and hyprlock. @@ -25,29 +27,30 @@ costs 2.5% of the width, where another 48px strip along the bottom would have cost 4.4% of the height on top of what the bar already takes. ``` -┌────────────────────────────────────────────┐ -│ ◆ │ 1 2 3 │ window title ♪ TRACK │ 42% │ 00:09 │ bar — 48px exclusive -├────────────────────────────────────────────┤ -│ ▐█▌│ rail — 48px exclusive -│ windows ▐ ▌│ -│ ▐ ▌│ -│ ▐ ▌│ -└────────────────────────────────────────────┘ +████████████████████████████████████████████████ +█ ◉ │ 1 2 3 │ window title ♪ TRACK │ CPU │ 20:04 █ bar — 40px, part of the hull +█╭──────────────────────────────────────────╮ ▐▌█ +█│ │ ▐▌█ rail — 48px, part of the hull +█│ windows │ ▐▌█ +█│ │ ▐▌█ +█╰──────────────────────────────────────────╯ █ frame — 8px left and bottom +████████████████████████████████████████████████ ``` -- **bar** — one slab: identity and workspaces on the left; the focused window, - the player, the CPU/MEM/GPU readout and the clock on the right. -- **rail** — one slab: network, bluetooth, audio, mic, backlight, battery, tray, +- **hull** — `bar/Frame.qml`: one surface round the whole screen, with the + desktop as a rounded opening. The bar and the rail sit on it. +- **bar** — identity and workspaces on the left; the focused window, the + player, the CPU/MEM/GPU readout and the clock on the right. +- **rail** — network, bluetooth, audio, mic, backlight, battery, tray, notifications, power. Popouts open leftward, into the screen. -Each permanent surface is a single continuous `ChromeSurface` with modules -divided by sheared hairlines. `BarPill` is chromeless by default — a module is -*content inside* a surface, not a surface of its own — and marks hover with an -accent underline. Pass `standalone: true` for the rare thing that really is its -own panel. +Modules are divided by hairlines. `BarPill` is chromeless by default — a module +is *content inside* the hull, not a surface of its own — and marks hover with +an accent underline. Pass `standalone: true` for the rare thing that really is +its own panel. -The shell uses three deliberate surface tiers. **Chrome** (`ChromeSurface`) is -the calm, texture-free bar, rail, and tooltip layer. **Transient** +The shell uses three deliberate surface tiers. **Chrome** (the hull and +`ChromeSurface`) is the calm, texture-free bar, rail, and tooltip layer. **Transient** (`PopoutSurface`) is reserved for expressive menus and detail panels, with one clear composition and stronger separation from the desktop. **Cinematic** (`P5Backdrop`) belongs only to scene-scale experiences such as power and lock; @@ -56,7 +59,7 @@ it is never used as decoration inside ordinary chrome or popouts. ``` shell.qml entrypoint — bar, rail, power menu, toasts, OSD per screen config/ palette, type scale, geometry, motion curves -components/ the P5 primitives: panels, sliders, list rows, print-shadowed text +components/ the primitives: panels, sliders, list rows, display text services/ data sources, all singletons bar/ the two surfaces and their modules popouts/ hover panels hanging off rail and bar modules @@ -204,39 +207,45 @@ means restarting Hyprland from a TTY. `power-profiles-daemon` is not installed (TLP is), so the power-profile switching in `services/Battery.qml` stays dormant. Nothing else depends on it. -The display face is Archivo Black, set italic almost everywhere. Change -`Theme.fontDisplay` and everything follows. +The display face is Noto Sans, upright and widely tracked — the nearest free +face to NieR's FOT-Rodin that is already installed. Change `Theme.fontDisplay` +and everything follows. ## Palette discipline -Catppuccin Mocha, spent on two hues. **Hue is meaning**; nothing gets a colour -for decoration. +YoRHa dark: NieR:Automata's interface language, painted from the wallpaper +(`~/.wallpapers/space-1.jpg`) rather than from the game's beige. Two hues, and +**hue is meaning**; nothing gets a colour for decoration. -- **Blue (`accent`, Mocha blue)** means live: the focused workspace, the - selected row, the hovered control, a channel that is on, an unread badge. -- **Mauve (`alarm`, Mocha mauve)** means wrong or destructive: critical battery, - an urgent workspace, a critical notification, reboot and shut down. -- **Grey** is everything else, and that includes *off*. A muted speaker, a - muted mic and Do Not Disturb drop to `muted` grey with their off glyph. They - used to be painted in the accent, which made a silenced channel look the most - alive thing on the rail. -- **Crust (`ink`)** is structure: the hard keyline, the offset under display - type and panels, the text on an accent slab. +- **Light (`accent`, `#eef1ea`)** means live: the focused workspace, the + selected row, the hovered control, a channel that is on, an unread badge. It + is the planet's white, barely a colour at all — NieR marks attention with + brightness and inversion, not with hue. +- **Red (`alarm`, `#c8684f`)** means wrong or destructive: critical battery, an + urgent workspace, a critical notification, reboot and shut down. It is the + hull's indicator lights, the only warm thing in the wallpaper. +- **Grey-green** is everything else, and that includes *off*. A muted speaker, + a muted mic and Do Not Disturb drop to `muted` grey with their off glyph. +- **Ink** is the text on an inverted slab and the faint drop under display + type. -**Selection is an inverted slab.** Focus and selection fill with the accent and -print their text in crust (about 9:1). Hover stays on the surface tone with an -accent mark. Destructive-active is the same slab in mauve. The `treatment*` -tokens in `Theme.qml` encode all of this; use them rather than picking colours -per widget. +**Selection is the NieR cursor.** Focus and selection invert the row: a slab of +the light with ink punched out of it. Hover lifts the surface one step and +brings the marker up to full light, but never inverts. Destructive-active is +the same slab in red. The `treatment*` tokens in `Theme.qml` encode all of +this; use them rather than picking colours per widget. -**Print, not blur.** Display text (`SplitText`) carries one hard crust offset. -The blue and mauve ghosts appear only while `glitch()` runs. Drawn permanently -1.6px off the body, they read as a focus problem on Mocha's pastels rather than -as misregistered print. The lock screen and the power menu are the exceptions; -they are the cinematic surfaces and keep their split. +**Markers, not slashes.** The current row, a button under the pointer and the +end of a header rule carry a small square (`Theme.marker`). Popouts are framed +by corner ticks (`Theme.tick`) in their tone colour; the border itself is +structure and stays neutral. + +**Flicker, not print.** Display text (`SplitText`) is upright, tracked by +`Theme.tracking`, on a one-pixel soft drop. The two ghosts either side of it +appear only while `glitch()` runs — NieR's brief data-corruption flicker. **Texture is tiered.** Chrome (bar, rail, tooltips) and transient panels -(popouts, OSD, toasts) are flat. Stripes and halftone live only in +(popouts, OSD, toasts) are flat. The hairline grid and the dot wash live only in `P5Backdrop`, behind the lock screen and the power menu. **Type has a floor.** Nothing renders below `Theme.fsMicro` (10px). @@ -245,60 +254,60 @@ they are the cinematic surfaces and keep their split. | File | Covers | |---|---| -| `quickshell/config/Theme.qml` | the shell: `accent`, `alarm` and the neutral ramp | -| `hypr/lua/palette.lua` | window borders, groups, shadows | -| `alacritty/catppuccin-mocha.toml` | the terminal (stock Mocha, cursor in the accent) | +| `quickshell/config/Theme.qml` | the shell: `accent`, `alarm`, the neutral ramp, the hull | +| `hypr/lua/palette.lua` | window borders, groups | +| `alacritty/yorha.toml` | the terminal | +| `fish/conf.d/yorha_theme.fish` | the prompt and pager | -Everything else derives. `accentDim` and `accentSoft` come off `accent`, `glow` -*is* `accent`, and `primary` is plain `text`. `Theme.heat()` is a continuous -text → blue → mauve ramp, so a CPU figure that has gone mauve means the same -thing as a battery that has gone mauve. Tray icons are flattened to one colour -(subtext, the accent on hover) for the same reason: app brand colours wreck the -palette faster than anything else in the shell. nm-applet and blueman are -hidden from the tray, since the rail already shows network and bluetooth, but -keep running as the secret and pairing agents. +Everything else derives. `glow` *is* `accent`, and `primary` is plain `text`. +`Theme.heat()` is a continuous text → light → red ramp, so a CPU figure that +has gone red means the same thing as a battery that has gone red. Tray icons +are flattened to one colour (subtext, the accent on hover) for the same reason: +app brand colours wreck the palette faster than anything else in the shell. +nm-applet and blueman are hidden from the tray, since the rail already shows +network and bluetooth, but keep running as the secret and pairing agents. ## The rest of the desktop - **Hyprland** — `hypr/lua/look.lua`. No rounding, no blur, both opacities at - `1.0`. The active border runs blue into lavender and the inactive border is - `surfaceAlt`. The window shadow is a sharp 4px crust offset, the same printed - drop the shell's panels carry, not a soft glow. -- **Alacritty** — `alacritty/catppuccin-mocha.toml`, selected by the `import` - in `alacritty.toml`. Stock Mocha except for the cursor, which is the accent. - `takemi.toml` is left in place, unreferenced. -- **Neovim** — the `catppuccin` plugin, flavour mocha, configured in - `nvim/lua/plugins/ui.lua`. Blue is the accent there too. `colors/takemi.lua` - is left in place, unused. -- **Fish** — `fish/conf.d/takemi_theme.fish` is Catppuccin Mocha's fish theme - with the Takemi selection rows: a solid accent block with crust punched out. + `1.0`, 1px borders. The active border runs from the light into the suit's + grey; the inactive border is `overlay`. The shadow is soft and wide, so + windows float in the opening rather than being printed onto it. `gaps_out` + is measured from the hull's opening, since the hull reserves its own zones. +- **Alacritty** — `alacritty/yorha.toml`, selected by the `import` in + `alacritty.toml`. Muted earth hues on the void; selection inverts. + The Catppuccin and `takemi.toml` files are left in place, unreferenced. +- **Neovim** — still the `catppuccin` plugin, flavour mocha, configured in + `nvim/lua/plugins/ui.lua`. Not yet moved to the YoRHa palette. +- **GTK and Qt** — still `catppuccin-mocha-blue`. Not yet moved either. +- **Fish** — `fish/conf.d/yorha_theme.fish`. - **The launcher** — no external theming to keep in step, because it is part of this shell (`launcher/`). Fuzzel is gone; `takemi-dmenu` stands in for `fuzzel --dmenu` where a script needs a picker. - **No glass anywhere.** Alacritty is `opacity = 1.0, blur = false`, and - Hyprland's `decoration:blur` is disabled. Blur is the signature of the - frosted-glass look, which is the opposite of flat ink on flat ground — and - with nothing translucent left it was costing three render passes for no - visible result. + Hyprland's `decoration:blur` is disabled. -There are **no gradients in this shell**; every fill is flat. `Theme.sheen` -still exists as a no-op property because a teal-to-transparent wash on every -panel was once the biggest source of murk in the design. +There are **no gradients in the chrome**; every fill is flat. `Theme.sheen` +still exists as a no-op property so old call sites need not be chased down. ## Geometry discipline -**One angle, one chamfer, everywhere.** `Theme.skew` is `tan(14°)` and every -edge in the shell leans by exactly that, in the same direction; every corner is -chopped by exactly `Theme.cut`. A vertical panel (the rail) leans its horizontal -edges by a fraction of its *width*, which works out to the same 14°. +**The hull.** Borrowed from caelestia's screen border: the bar, the rail and a +thin band down the left and along the bottom (`Theme.frame`) are one surface, +drawn by `bar/Frame.qml` on the bottom layer, and the desktop is a rounded +opening cut out of it (`Theme.frameRadius`). Read against the wallpaper, you are +inside the ship and the windows sit in the porthole. The bar and the rail draw +no surface of their own and ignore exclusive zones; Frame reserves all four +zones itself, so every piece is placed from the screen edge. -This is deliberate and was learned the hard way. An earlier pass gave every -module a different lean, chamfer and height from per-index variance tables, on -the theory that Persona geometry is "chaotic". It isn't — Persona UI is -meticulously clean, and the chaos lives in composition and motion, not in each -element being a different shape. Randomised geometry just reads as noise. If you -find yourself adding a variance table, don't. +**Rectangles, everywhere else.** NieR panels are plain boxes. `Theme.skew` and +`Theme.cut` are both `0`, so `P5Panel`, `Skew` and `Geom` all collapse to +rectangles; the knobs are kept so a shape can be brought back on purpose. The +porthole's curve is the only one on screen, which is what lets it read. -Each surface is **one continuous slab**, with modules divided by sheared -hairline rules rather than by gaps. A row of separate floating cards reads as -clutter; that is what the dividers exist to avoid. +**Motion glides.** No overshoot anywhere: things ease in on `OutCubic` or +`OutExpo` and settle. NieR's interface is calm and mechanical. + +Each surface is **one continuous slab**, with modules divided by hairline rules +rather than by gaps. A row of separate floating cards reads as clutter; that is +what the dividers exist to avoid. diff --git a/quickshell/ask/AskPanel.qml b/quickshell/ask/AskPanel.qml index 6dbfcb6..09a7f88 100644 --- a/quickshell/ask/AskPanel.qml +++ b/quickshell/ask/AskPanel.qml @@ -394,7 +394,7 @@ PanelWindow { NumberAnimation { target: drop; property: "y" from: -shell.height; to: 0 - duration: Theme.durSlow; easing.type: Easing.OutBack + duration: Theme.durSlow; easing.type: Easing.OutCubic } } diff --git a/quickshell/assets/dots.png b/quickshell/assets/dots.png new file mode 100644 index 0000000..d995f0b Binary files /dev/null and b/quickshell/assets/dots.png differ diff --git a/quickshell/assets/grid.png b/quickshell/assets/grid.png new file mode 100644 index 0000000..b3c3f7a Binary files /dev/null and b/quickshell/assets/grid.png differ diff --git a/quickshell/bar/ActiveWindow.qml b/quickshell/bar/ActiveWindow.qml index 2bf6657..35be165 100644 --- a/quickshell/bar/ActiveWindow.qml +++ b/quickshell/bar/ActiveWindow.qml @@ -51,13 +51,12 @@ Item { elide: Text.ElideRight font.pixelSize: Theme.fsSmall font.family: Theme.fontDisplay - font.italic: true font.weight: Font.DemiBold renderType: Text.NativeRendering } // Accent duplicate: visible only during the landing transition. The - // small opposing offset gives the title Persona's rough print snap + // small opposing offset gives the title NieR's brief corruption flicker // without leaving permanent motion in the bar. Text { id: ghost @@ -144,7 +143,7 @@ Item { NumberAnimation { target: label; property: "x" from: -10; to: 0 - duration: Theme.durBase; easing.type: Easing.OutBack + duration: Theme.durBase; easing.type: Easing.OutCubic } NumberAnimation { target: label; property: "opacity" diff --git a/quickshell/bar/Bar.qml b/quickshell/bar/Bar.qml index abe04a5..9e461e8 100644 --- a/quickshell/bar/Bar.qml +++ b/quickshell/bar/Bar.qml @@ -27,29 +27,16 @@ PanelWindow { right: true } - margins { - top: Theme.barMargin - left: Theme.barMargin - right: Theme.barMargin - } - + // Flush with the screen edge and drawn on nothing: the hull behind it is + // painted by Frame, which is what joins the bar, the rail and the border + // into one surface. Exclusive zones are Frame's job too, so every piece + // of the hull is placed from the screen edge rather than from whichever + // piece the compositor happened to arrange first. + exclusionMode: ExclusionMode.Ignore implicitHeight: Theme.barHeight - exclusiveZone: Theme.barHeight + Theme.barMargin color: "transparent" - // Calm permanent chrome: one opaque slab with no texture or offset copy. - ChromeSurface { - id: slab - anchors.fill: parent - lean: Theme.skew - chop: Theme.cut - chopCorners: [1, 3] - padding: 0 - active: true - slashWidth: 5 - } - - readonly property real edgeInset: Theme.barHeight * Theme.skew + Theme.padM + readonly property real edgeInset: Theme.padM // ------------------------------------------------------------------ left Row { @@ -108,25 +95,18 @@ PanelWindow { } } - // A hairline rule between modules, sheared to the house angle. This is what - // divides the bar now — gaps between cards are what made it look scattered. + // A hairline rule between modules. This is what divides the bar — gaps + // between cards are what made it look scattered. component Divider: Item { anchors.verticalCenter: parent.verticalCenter implicitWidth: Theme.padM * 2 implicitHeight: Theme.barHeight - // A leaning hairline needs a box wide enough to hold the lean: at 20px - // tall the top edge sits 20 * skew ≈ 5px right of the bottom one, so a - // 1px-wide Skew folded into a bowtie instead. Width is the lean plus the - // stroke the rule should actually read as. - readonly property real ruleWeight: 1.5 - readonly property real ruleHeight: 20 - - Skew { + Rectangle { anchors.centerIn: parent - width: parent.ruleHeight * Theme.skew + parent.ruleWeight - height: parent.ruleHeight - color: Theme.alpha(Theme.outline, 0.5) + width: 1 + height: 16 + color: Theme.alpha(Theme.outline, 0.6) } } } diff --git a/quickshell/bar/Clock.qml b/quickshell/bar/Clock.qml index 38f4175..b2165ce 100644 --- a/quickshell/bar/Clock.qml +++ b/quickshell/bar/Clock.qml @@ -70,7 +70,6 @@ BarPill { font.family: Theme.fontDisplay font.pixelSize: Theme.fsTitle font.weight: Theme.weightDisplay - font.italic: true font.letterSpacing: 0.5 } diff --git a/quickshell/bar/Frame.qml b/quickshell/bar/Frame.qml new file mode 100644 index 0000000..d324e60 --- /dev/null +++ b/quickshell/bar/Frame.qml @@ -0,0 +1,121 @@ +import QtQuick +import QtQuick.Shapes +import Quickshell +import Quickshell.Wayland +import "root:/config" + +// The hull: one surface for the bar, the rail and the thin band down the left +// and along the bottom, with the desktop as a rounded opening cut out of it. +// The idea is caelestia's screen border; the reading is the wallpaper's — you +// are inside the ship, and the windows sit in the porthole. +// +// The hull lives on the bottom layer, under every window. Hyprland's gaps keep +// tiled windows inside the opening, so nothing ever has to be drawn over a +// window; a floating window dragged onto the frame simply covers it, and a +// fullscreen one hides it, which is what should happen in both cases. +// +// The bar and the rail draw no surface of their own and ignore exclusive +// zones, so every piece is placed from the screen edge. The four zones are +// reserved here instead, by windows that draw nothing — that way the usable +// area is exactly the opening, whichever surface the compositor arranges +// first. +Scope { + id: root + + required property var modelData + + PanelWindow { + id: hull + + screen: root.modelData + + WlrLayershell.layer: WlrLayer.Bottom + WlrLayershell.namespace: "takemi-frame" + WlrLayershell.keyboardFocus: WlrKeyboardFocus.None + exclusionMode: ExclusionMode.Ignore + + anchors { + top: true + bottom: true + left: true + right: true + } + + color: "transparent" + mask: Region {} + + // The opening, in window coordinates. + readonly property real x0: Theme.frame + readonly property real y0: Theme.barHeight + readonly property real x1: width - Theme.railWidth + readonly property real y1: height - Theme.frame + readonly property real r: Theme.frameRadius + + readonly property string opening: { + const x0 = hull.x0, y0 = hull.y0, x1 = hull.x1, y1 = hull.y1, r = hull.r; + return `M ${x0 + r} ${y0} H ${x1 - r} A ${r} ${r} 0 0 1 ${x1} ${y0 + r}` + + ` V ${y1 - r} A ${r} ${r} 0 0 1 ${x1 - r} ${y1}` + + ` H ${x0 + r} A ${r} ${r} 0 0 1 ${x0} ${y1 - r}` + + ` V ${y0 + r} A ${r} ${r} 0 0 1 ${x0 + r} ${y0} Z`; + } + + Shape { + anchors.fill: parent + preferredRendererType: Shape.CurveRenderer + + // The hull itself: the whole screen, minus the opening. + ShapePath { + fillColor: Theme.hull + fillRule: ShapePath.OddEvenFill + strokeColor: "transparent" + + PathSvg { + path: `M 0 0 H ${hull.width} V ${hull.height} H 0 Z ` + hull.opening + } + } + + // The rim — a hairline round the opening, the lit edge of the + // porthole in the wallpaper. + ShapePath { + fillColor: "transparent" + strokeColor: Theme.rim + strokeWidth: 1 + + PathSvg { + path: hull.opening + } + } + } + } + + ExclusionZone { + anchors.top: true + exclusiveZone: Theme.barHeight + } + + ExclusionZone { + anchors.right: true + exclusiveZone: Theme.railWidth + } + + ExclusionZone { + anchors.bottom: true + exclusiveZone: Theme.frame + } + + ExclusionZone { + anchors.left: true + exclusiveZone: Theme.frame + } + + component ExclusionZone: PanelWindow { + screen: root.modelData + WlrLayershell.layer: WlrLayer.Bottom + WlrLayershell.namespace: "takemi-frame-zone" + WlrLayershell.keyboardFocus: WlrKeyboardFocus.None + color: "transparent" + mask: Region {} + implicitWidth: 1 + implicitHeight: 1 + } +} diff --git a/quickshell/bar/MediaPill.qml b/quickshell/bar/MediaPill.qml index fadb305..84b9a1c 100644 --- a/quickshell/bar/MediaPill.qml +++ b/quickshell/bar/MediaPill.qml @@ -109,7 +109,6 @@ BarPill { font.pixelSize: Theme.fsSmall font.family: Theme.fontDisplay font.weight: Font.DemiBold - font.italic: true renderType: Text.NativeRendering } @@ -217,7 +216,7 @@ BarPill { id: titleGlitch NumberAnimation { target: artFrame; property: "rotation" - from: -8; to: 0; duration: Theme.durSlow; easing.type: Easing.OutBack + from: -8; to: 0; duration: Theme.durSlow; easing.type: Easing.OutCubic } } diff --git a/quickshell/bar/Rail.qml b/quickshell/bar/Rail.qml index 5f0c778..3fdfafa 100644 --- a/quickshell/bar/Rail.qml +++ b/quickshell/bar/Rail.qml @@ -30,30 +30,14 @@ PanelWindow { right: true } - margins { - top: Theme.barHeight + Theme.barMargin * 2 - bottom: Theme.barMargin - right: Theme.barMargin - } - + // Hangs from the underside of the bar, flush with the screen edge. Like + // the bar it draws no surface of its own; see Frame. + margins.top: Theme.barHeight + exclusionMode: ExclusionMode.Ignore implicitWidth: Theme.railWidth - exclusiveZone: Theme.railWidth + Theme.barMargin color: "transparent" - // The same calm permanent-chrome preset used by the top bar. - ChromeSurface { - id: slab - anchors.fill: parent - vertical: true - lean: Theme.skew - chop: Theme.cut - chopCorners: [1, 3] - padding: 0 - active: true - slashWidth: 5 - } - - readonly property real edgeInset: Theme.railWidth * Theme.skew + Theme.padM + readonly property real edgeInset: Theme.padM // ------------------------------------------------------------------- top Column { @@ -183,25 +167,16 @@ PanelWindow { } } - // The rail's counterpart to the bar's divider: a horizontal hairline, - // sheared to the same angle the rail's own edges lean at. + // The rail's counterpart to the bar's divider: a horizontal hairline. component Divider: Item { implicitWidth: Theme.railWidth implicitHeight: Theme.padM + 4 - // Same correction as the bar's divider, on the other axis: a 22px rule - // rises 22 * skew ≈ 5px across its run, so the box has to be that tall - // plus the weight of the stroke. At height 1 the polygon inverted and - // the rule rendered as a stubby wedge sitting left of centre. - readonly property real ruleWeight: 1.5 - readonly property real ruleWidth: 22 - - Skew { + Rectangle { anchors.centerIn: parent - width: parent.ruleWidth - height: parent.ruleWidth * Theme.skew + parent.ruleWeight - vertical: true - color: Theme.alpha(Theme.outline, 0.5) + width: 16 + height: 1 + color: Theme.alpha(Theme.outline, 0.6) } } diff --git a/quickshell/bar/RailIcon.qml b/quickshell/bar/RailIcon.qml index db86e60..33bb753 100644 --- a/quickshell/bar/RailIcon.qml +++ b/quickshell/bar/RailIcon.qml @@ -147,7 +147,7 @@ Item { scale: root.hovered ? 1.08 : 1.0 Behavior on scale { - NumberAnimation { duration: Theme.durBase; easing.type: Easing.OutBack } + NumberAnimation { duration: Theme.durBase; easing.type: Easing.OutCubic } } onAlarmChanged: if (alarm) glyph.bump() diff --git a/quickshell/bar/Resources.qml b/quickshell/bar/Resources.qml index 45dcf66..b39ac01 100644 --- a/quickshell/bar/Resources.qml +++ b/quickshell/bar/Resources.qml @@ -121,7 +121,6 @@ BarPill { font.family: Theme.fontDisplay font.pixelSize: Theme.fsBody font.weight: Theme.weightDisplay - font.italic: true font.letterSpacing: 0.5 renderType: Text.NativeRendering diff --git a/quickshell/bar/Sigil.qml b/quickshell/bar/Sigil.qml index 5c7e8a8..7d64a79 100644 --- a/quickshell/bar/Sigil.qml +++ b/quickshell/bar/Sigil.qml @@ -12,33 +12,15 @@ BarPill { required property var screenRef accent: Theme.accent - slash: true padding: Theme.padS - lean: Theme.skew implicitWidth: Theme.barHeight + contentPad onClicked: Actions.toggleLauncher() onRightClicked: Actions.reloadShell() - // The wordmark. Was the Death arcana skull (nf-md-skull, U+F068C) — a - // pictogram in a shell that otherwise says everything in heavy italic - // type. SplitText puts it in the display face with the ink print - // offset every other heading carries, so the house mark is built out of - // the same parts as the rest of the bar. - SplitText { - id: mark + Porthole { anchors.centerIn: parent - text: "P5" - pixelSize: Theme.fsLarge - letterSpacing: 0 - color: root.hovered ? Theme.accent : Theme.primary - } - - // Kick the ghosts out and let them snap back. The skull could spin a full - // turn and still read as a skull; a wordmark upside down just reads as - // broken, so the click gets the glitch instead. - Connections { - target: root - function onClicked() { mark.glitch(); } + size: 18 + lit: root.hovered } } diff --git a/quickshell/bar/Tray.qml b/quickshell/bar/Tray.qml index 6ffd85d..06d3ef2 100644 --- a/quickshell/bar/Tray.qml +++ b/quickshell/bar/Tray.qml @@ -79,7 +79,7 @@ Column { scale: itemHover.hovered ? 1.18 : 1.0 Behavior on scale { - NumberAnimation { duration: Theme.durBase; easing.type: Easing.OutBack } + NumberAnimation { duration: Theme.durBase; easing.type: Easing.OutCubic } } HoverHandler { diff --git a/quickshell/bar/Workspaces.qml b/quickshell/bar/Workspaces.qml index 61b92dd..f653ab3 100644 --- a/quickshell/bar/Workspaces.qml +++ b/quickshell/bar/Workspaces.qml @@ -75,7 +75,7 @@ Item { Behavior on width { NumberAnimation { duration: Theme.durSlow - easing.type: Easing.OutBack + easing.type: Easing.OutCubic easing.overshoot: 1.6 } } @@ -122,7 +122,6 @@ Item { font.family: Theme.fontDisplay font.pixelSize: Theme.fsSmall font.weight: Theme.weightDisplay - font.italic: true renderType: Text.NativeRendering Behavior on opacity { diff --git a/quickshell/components/ChromeSurface.qml b/quickshell/components/ChromeSurface.qml index b4e6649..788ad83 100644 --- a/quickshell/components/ChromeSurface.qml +++ b/quickshell/components/ChromeSurface.qml @@ -3,7 +3,7 @@ import "root:/config" import "root:/components" // Calm, permanent-chrome preset. It is deliberately flat and opaque: one -// neutral keyline, no texture, no offset copy, and no accent unless active. +// neutral hairline, no texture, no ticks, and no accent unless active. P5Panel { property bool active: false property color tone: Theme.treatmentActiveMark @@ -12,16 +12,10 @@ P5Panel { fillOpacity: 1.0 border: Theme.treatmentRestMark borderWidth: 1 - // Keep the hard ink contour. Removing both texture and keyline made the - // permanent slabs read as generic broadcast HUD chrome. - keyline: true - drop: false halftone: false sheen: false slash: active slashColor: tone - slashWidth: 4 - lean: 0.06 - chop: Theme.cut + slashWidth: 2 padding: Theme.padS } diff --git a/quickshell/components/Geom.qml b/quickshell/components/Geom.qml index aacbd49..266f309 100644 --- a/quickshell/components/Geom.qml +++ b/quickshell/components/Geom.qml @@ -3,7 +3,10 @@ pragma Singleton import QtQuick import Quickshell -// Polygon maths for the Persona 5 panel language: everything leans, and corners +// Polygon maths for panel shapes. Under the YoRHa theme nothing leans and +// nothing is chopped (Theme.skew and Theme.cut are 0), so these collapse to +// plain rectangles; they are kept so a shape can be brought back on purpose. +// Originally the Persona 5 panel language: everything leans, and corners // get chopped rather than rounded. Singleton { id: root diff --git a/quickshell/components/Icon.qml b/quickshell/components/Icon.qml index 6782e24..8c9f6ef 100644 --- a/quickshell/components/Icon.qml +++ b/quickshell/components/Icon.qml @@ -39,7 +39,7 @@ Text { } NumberAnimation { target: root; property: "scale" - to: 1.0; duration: Theme.durSlow; easing.type: Easing.OutBack + to: 1.0; duration: Theme.durSlow; easing.type: Easing.OutCubic } } } diff --git a/quickshell/components/ListRow.qml b/quickshell/components/ListRow.qml index a6d0c5f..dd02216 100644 --- a/quickshell/components/ListRow.qml +++ b/quickshell/components/ListRow.qml @@ -7,8 +7,8 @@ import "root:/config" // came out as a faint milky film. This is the one row they share now. // // Rest is bare. Hover lifts the row onto the surface tone. The current item — -// connected, in use — carries an accent tick down its leading edge and an -// accent glyph, and its label goes to full weight. +// connected, in use — carries the NieR square marker at its leading edge and +// an accent glyph, and its label goes to full weight. Item { id: root @@ -40,12 +40,13 @@ Item { Rectangle { anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter - width: 3 - height: root.current ? root.height - 10 : 0 + anchors.leftMargin: 2 + width: root.current ? Theme.marker : 0 + height: width color: Theme.accent - Behavior on height { - NumberAnimation { duration: Theme.durBase; easing.type: Easing.OutBack } + Behavior on width { + NumberAnimation { duration: Theme.durBase; easing.type: Easing.OutCubic } } } @@ -76,8 +77,7 @@ Item { color: root.current || root.hovered ? Theme.text : Theme.subtext font.family: Theme.fontDisplay font.pixelSize: Theme.fsSmall - font.italic: true - font.weight: root.current ? Font.Black : Font.Medium + font.weight: root.current ? Font.DemiBold : Font.Medium renderType: Text.NativeRendering } diff --git a/quickshell/components/MeterBar.qml b/quickshell/components/MeterBar.qml index 658ea04..fb979aa 100644 --- a/quickshell/components/MeterBar.qml +++ b/quickshell/components/MeterBar.qml @@ -2,7 +2,7 @@ import QtQuick import "root:/config" import "root:/components" -// A segmented load meter — slanted ticks that light up left to right. Reads as +// A segmented load meter — upright ticks that light up left to right. Reads as // a gauge at a glance and keeps the panel language consistent. Item { id: root diff --git a/quickshell/components/NotifCard.qml b/quickshell/components/NotifCard.qml index b2b593d..dc26c48 100644 --- a/quickshell/components/NotifCard.qml +++ b/quickshell/components/NotifCard.qml @@ -21,8 +21,8 @@ Item { // The card's own geometry, published so anything drawn along its edges — // the toast countdown rule — can stay inside the chopped corners instead of // running out past them. - readonly property real lean: 0.05 - readonly property real chop: 12 + readonly property real lean: Theme.skew + readonly property real chop: Theme.cut implicitHeight: panel.height @@ -84,8 +84,7 @@ Item { wrapMode: Text.WordWrap font.family: Theme.fontDisplay font.pixelSize: Theme.fsBody - font.weight: Font.Black - font.italic: true + font.weight: Font.DemiBold renderType: Text.NativeRendering } @@ -141,7 +140,6 @@ Item { color: actionHover.hovered ? Theme.ink : Theme.text font.family: Theme.fontDisplay font.pixelSize: Theme.fsMicro - font.italic: true font.weight: Font.DemiBold renderType: Text.NativeRendering } diff --git a/quickshell/components/P5Backdrop.qml b/quickshell/components/P5Backdrop.qml index fea8a1f..83332c5 100644 --- a/quickshell/components/P5Backdrop.qml +++ b/quickshell/components/P5Backdrop.qml @@ -1,54 +1,46 @@ import QtQuick -import QtQuick.Shapes import "root:/config" import "root:/components" -// The shared ground for the two full-screen surfaces: an accent wedge leaning -// at the house angle, a tiled stripe field that sweeps in from the left, and a -// halftone dot wash over the top. +// The shared ground for the two full-screen surfaces, in the NieR menu +// pattern: a hairline grid that sweeps in from the left, a darker column down +// the left-hand side for the menu or the clock to stand in, and a dot wash +// over the top. // -// The lock screen and the power menu each used to draw their own version of -// this. They disagreed — the power menu had a wedge and a full stripe field, -// the lock had a 42px stripe band and no wedge, and the wedge leaned at 0.32 -// where every panel in the shell leans at Theme.skew. Building both on one -// component is what makes them read as the same object seen twice rather than -// as two guesses at the same brief. +// The lock screen and the power menu both stand on this one component, which +// is what makes them read as the same object seen twice rather than as two +// guesses at the same brief. Item { id: root - // 0 = withdrawn, 1 = fully present. Drives the stripe slide, the stripe - // opacity and the wedge together, so a caller animates one number instead + // 0 = withdrawn, 1 = fully present. Drives the grid slide, the grid + // opacity and the column together, so a caller animates one number instead // of keeping three in sync. The power menu runs it both ways on open and // close; the lock runs it once on entry. property real reveal: 1 property color tone: Theme.accent + // The column: a band of the void, edged by a hairline of the light. + // `wedge*` names are kept from the Persona layout so callers did not have + // to move; there is nothing wedge-shaped left. property bool wedge: true property real wedgeOpacity: 0.35 - // Bottom-left corner of the wedge and its span, as fractions of width. The - // wedge leans right going up, like every other edge in the shell, so its - // top edge sits `leanOffset` further right than its bottom. property real wedgeLeft: 0 property real wedgeSpan: 0.34 property bool stripes: true - // Tuned down from 0.10 for Mocha. Crust stripes on the blue-grey base read - // far heavier than they did on black, and buzzed against the text. - property real stripeOpacity: 0.07 + property real stripeOpacity: 0.05 property bool halftone: true property real halftoneOpacity: 0.05 property color halftoneColor: Theme.primary - // ONE angle, everywhere — the same rule the panels follow. - readonly property real leanOffset: root.height * Theme.skew - - // Diagonal stripe field, sliding in from off-screen left. + // Hairline grid, sliding in from off-screen left. Image { anchors.fill: parent visible: root.stripes && root.reveal > 0 - source: Theme.texStripes + source: Theme.texGrid fillMode: Image.Tile opacity: root.stripeOpacity * root.reveal smooth: false @@ -63,39 +55,33 @@ Item { } } - // The wedge. Drawn after the stripes so it reads as a slab laid over them. - Shape { - anchors.fill: parent + // The column. Drawn after the grid so it reads as a panel laid over it. + Item { + x: root.wedgeLeft * root.width + width: root.wedgeSpan * root.width + height: root.height visible: root.wedge && root.reveal > 0 opacity: root.reveal - preferredRendererType: Shape.CurveRenderer - ShapePath { - fillColor: Theme.alpha(Theme.accentDim, root.wedgeOpacity) - strokeColor: "transparent" - joinStyle: ShapePath.MiterJoin + Rectangle { + anchors.fill: parent + color: Theme.alpha(Theme.ink, root.wedgeOpacity) + } - PathPolyline { - path: { - const x = root.wedgeLeft * root.width; - const span = root.wedgeSpan * root.width; - const off = root.leanOffset; - return Geom.closed([ - Qt.point(x + off, 0), - Qt.point(x + off + span, 0), - Qt.point(x + span, root.height), - Qt.point(x, root.height) - ]); - } - } + // Its edge, drawn top-down as the column arrives. + Rectangle { + anchors.right: parent.right + width: 1 + height: parent.height * root.reveal + color: Theme.alpha(root.tone, 0.35) } } - // Screen-printed dot wash over the whole thing. + // Dot wash over the whole thing. Image { anchors.fill: parent visible: root.halftone - source: Theme.texHalftone + source: Theme.texDots fillMode: Image.Tile opacity: root.halftoneOpacity smooth: false diff --git a/quickshell/components/P5Button.qml b/quickshell/components/P5Button.qml index 7e4b353..ceb9bd6 100644 --- a/quickshell/components/P5Button.qml +++ b/quickshell/components/P5Button.qml @@ -1,7 +1,8 @@ import QtQuick import "root:/config" -// Chopped, leaning button with one activation path for pointer and keyboard. +// NieR menu button: a hairline box with a square marker that lights when the +// button is pointed at or chosen. One activation path for pointer and keyboard. FocusScope { id: root @@ -11,7 +12,7 @@ FocusScope { property bool destructive: false property bool selected: false property real lean: Theme.skew - property real lunge: 6 + property real lunge: 4 property bool wide: false signal clicked() @@ -24,7 +25,7 @@ FocusScope { // Keyboard focus and roving selection invert the slab to solid accent. // Pointer hover stays a keyline change, so the two never look alike and a // mouse user never sees the "selected" treatment by accident. Destructive - // buttons keep their own mauve inversion for both. + // buttons keep their own red inversion for both. readonly property bool inverted: root.enabled && !root.destructive && root.focusedOrSelected // Pointer activation must not turn a transient action into the black/white @@ -70,8 +71,6 @@ FocusScope { return Theme.alpha(root.accent, 0.55); } borderWidth: Theme.stroke - slash: !root.highlighted - slashColor: root.destructive ? Theme.alarm : root.accent Behavior on fillOpacity { NumberAnimation { duration: Theme.durFast } @@ -83,6 +82,20 @@ FocusScope { anchors.left: parent.left spacing: Theme.padM + // The marker. Dim at rest, full strength under the pointer or the + // cursor, in whatever colour the label is wearing. + Rectangle { + anchors.verticalCenter: parent.verticalCenter + width: Theme.marker + height: Theme.marker + color: label.color + opacity: root.highlighted ? 1.0 : 0.35 + + Behavior on opacity { + NumberAnimation { duration: Theme.durFast } + } + } + Icon { anchors.verticalCenter: parent.verticalCenter visible: root.icon !== "" @@ -100,6 +113,7 @@ FocusScope { } Text { + id: label anchors.verticalCenter: parent.verticalCenter text: root.text color: { @@ -114,8 +128,7 @@ FocusScope { font.family: Theme.fontDisplay font.pixelSize: Theme.fsBody font.weight: Theme.weightDisplay - font.italic: true - font.letterSpacing: 1.5 + font.letterSpacing: Theme.tracking font.capitalization: Font.AllUppercase renderType: Text.NativeRendering @@ -132,7 +145,7 @@ FocusScope { Behavior on x { NumberAnimation { duration: Theme.durBase - easing.type: Easing.OutBack + easing.type: Easing.OutCubic } } } diff --git a/quickshell/components/P5Panel.qml b/quickshell/components/P5Panel.qml index 624f378..6d355a8 100644 --- a/quickshell/components/P5Panel.qml +++ b/quickshell/components/P5Panel.qml @@ -4,8 +4,13 @@ import QtQuick.Effects import "root:/config" import "root:/components" -// The base surface for everything in this shell: a leaning, corner-chopped slab -// with an optional halftone wash and a accent slash along its leading edge. +// The base surface for everything in this shell. Under the YoRHa theme it is a +// plain rectangle with a hairline border, an optional dot wash, an optional +// accent bar down its leading edge, and optional corner ticks — the brackets +// NieR frames its panels with. +// +// The lean and chop knobs still exist and still work, so a caller can bring a +// shape back on purpose, but Theme.skew and Theme.cut are both zero. Item { id: root @@ -29,12 +34,12 @@ Item { property real chop: Theme.cut property var chopCorners: [1, 3] - // Tone slash down the leading edge — the Persona 5 tell. + // Accent bar down the leading edge. property bool slash: false property color slashColor: Theme.accent property real slashWidth: 4 - // Screen-printed dot wash. + // Dot-grid wash. property bool halftone: false property color halftoneColor: Theme.primary property real halftoneOpacity: 0.07 @@ -45,16 +50,20 @@ Item { // call sites that still set it don't have to be chased down. property bool sheen: false - // The screen-print stack. A pure-black copy of the silhouette sits behind - // the fill, offset down-and-right, and the fill carries a black keyline - // outside its coloured border. Together these are what stop the panel from - // reading as a flat clip-path. - property bool drop: true + // Optional print stack: an ink copy of the silhouette offset behind the + // fill, and an ink keyline outside the border. Both off by default — on a + // dark ground they only thicken the edge. + property bool drop: false property real dropOffset: Theme.dropOffset property color dropColor: Theme.ink - property bool keyline: true + property bool keyline: false property real keylineWidth: Theme.keylineWidth + // Corner ticks: a short L at each corner, just outside the border. + property bool ticks: false + property color tickColor: Theme.outline + property real tickLength: Theme.tick + readonly property real leanInset: (vertical ? width : height) * Math.abs(lean) @@ -165,7 +174,7 @@ Item { asynchronous: true sourceComponent: Image { anchors.fill: parent - source: Theme.texHalftone + source: Theme.texDots fillMode: Image.Tile opacity: root.halftoneOpacity smooth: false @@ -237,6 +246,44 @@ Item { } } + // Corner ticks. Two hairlines per corner, sitting 3px outside the panel so + // they read as a frame around it rather than as part of its border. + Loader { + anchors.fill: parent + anchors.margins: -3 + active: root.ticks + sourceComponent: Item { + Repeater { + model: 4 + + Item { + required property int index + readonly property bool atRight: index === 1 || index === 2 + readonly property bool atBottom: index >= 2 + + x: atRight ? parent.width - width : 0 + y: atBottom ? parent.height - height : 0 + width: root.tickLength + height: root.tickLength + + Rectangle { + y: parent.atBottom ? parent.height - 1 : 0 + width: parent.width + height: 1 + color: root.tickColor + } + + Rectangle { + x: parent.atRight ? parent.width - 1 : 0 + width: 1 + height: parent.height + color: root.tickColor + } + } + } + } + } + Item { id: contentHolder anchors.fill: parent diff --git a/quickshell/components/P5Slider.qml b/quickshell/components/P5Slider.qml index 0e20e5e..8aa69a2 100644 --- a/quickshell/components/P5Slider.qml +++ b/quickshell/components/P5Slider.qml @@ -2,7 +2,8 @@ import QtQuick import "root:/config" import "root:/components" -// Leaning slider with a chopped handle. Drag or click anywhere on the rail. +// Hairline slider with a square handle, the NieR settings-menu slider. Drag or +// click anywhere on the rail. Item { id: root @@ -30,7 +31,7 @@ Item { anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left anchors.right: parent.right - height: root.activeFocus ? 10 : 6 + height: root.activeFocus ? 4 : 2 // Focus widens the rail and rings it in the accent rather than filling // it: the level fill is often the accent itself, and a solid accent // rail swallowed it. @@ -50,7 +51,7 @@ Item { anchors.verticalCenter: parent.verticalCenter anchors.left: parent.left width: Math.max(0, Math.min(1, root.value)) * root.width - height: 6 + height: root.activeFocus ? 4 : 2 color: root.enabled ? root.accent : Theme.treatmentDisabledText Behavior on width { @@ -66,14 +67,14 @@ Item { // Handle Skew { id: handle - width: 6 - height: root.activeFocus || hover.hovered || drag.active ? 18 : 14 + width: height + height: root.activeFocus || hover.hovered || drag.active ? 12 : 10 color: root.enabled ? Theme.text : Theme.treatmentDisabledText anchors.verticalCenter: parent.verticalCenter x: Math.max(0, Math.min(1, root.value)) * root.width - width / 2 Behavior on height { - NumberAnimation { duration: Theme.durFast; easing.type: Easing.OutBack } + NumberAnimation { duration: Theme.durFast; easing.type: Easing.OutCubic } } Behavior on x { enabled: !drag.active diff --git a/quickshell/components/P5Tooltip.qml b/quickshell/components/P5Tooltip.qml index ea9a4c8..e3d112e 100644 --- a/quickshell/components/P5Tooltip.qml +++ b/quickshell/components/P5Tooltip.qml @@ -69,7 +69,6 @@ PopupWindow { ChromeSurface { anchors.fill: parent padding: root.pad - lean: 0.06 Column { id: textColumn @@ -84,7 +83,6 @@ PopupWindow { font.family: Theme.fontDisplay font.pixelSize: Theme.fsSmall font.weight: Theme.weightDisplay - font.italic: true renderType: Text.NativeRendering } diff --git a/quickshell/components/Popout.qml b/quickshell/components/Popout.qml index 321b8d0..0f11be2 100644 --- a/quickshell/components/Popout.qml +++ b/quickshell/components/Popout.qml @@ -226,12 +226,12 @@ PopupWindow { } NumberAnimation { target: contentHolder; property: "scale" - to: 1.0; duration: Theme.durSlow; easing.type: Easing.OutBack + to: 1.0; duration: Theme.durSlow; easing.type: Easing.OutCubic } NumberAnimation { target: contentHolder; property: root.slideProperty from: root.slideOrigin; to: root.bleed - duration: Theme.durSlow; easing.type: Easing.OutBack + duration: Theme.durSlow; easing.type: Easing.OutCubic } } diff --git a/quickshell/components/Porthole.qml b/quickshell/components/Porthole.qml new file mode 100644 index 0000000..0fa76f7 --- /dev/null +++ b/quickshell/components/Porthole.qml @@ -0,0 +1,43 @@ +import QtQuick +import "root:/config" + +// The house mark: a porthole with a planet low in it — the wallpaper's one +// composition, drawn in a hairline ring and a disc. The bar's sigil and the +// lock screen both draw it, so the two are the same mark at two sizes. +Item { + id: root + + property real size: 18 + property bool lit: false + + implicitWidth: root.size + implicitHeight: root.size + + Rectangle { + anchors.fill: parent + radius: width / 2 + color: "transparent" + border.width: Math.max(1, Math.round(root.size / 18)) + border.color: root.lit ? Theme.accent : Theme.primaryDim + + Behavior on border.color { + ColorAnimation { duration: Theme.durFast } + } + } + + // The planet's limb, sitting on the ring's lower edge. Always the planet + // white; `lit` only lets it rise a little. + Rectangle { + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: root.size / 6 + width: root.size * (root.lit ? 0.44 : 0.34) + height: width + radius: width / 2 + color: Theme.accent + + Behavior on width { + NumberAnimation { duration: Theme.durBase; easing.type: Easing.OutCubic } + } + } +} diff --git a/quickshell/components/SplitText.qml b/quickshell/components/SplitText.qml index 2699656..31528da 100644 --- a/quickshell/components/SplitText.qml +++ b/quickshell/components/SplitText.qml @@ -1,14 +1,13 @@ import QtQuick import "root:/config" -// Display text, screen-printed: the body sits on a hard crust copy knocked a -// pixel and a half down-right — the same offset `P5Panel` puts behind every -// slab. Drives most headings in the shell. +// Display text: upright, widely tracked, sitting on a soft ink copy a pixel +// down-right — the faint drop NieR puts under every line of its interface. +// Drives most headings in the shell. // -// This used to carry a permanent RGB split, a blue and a mauve ghost either -// side of the body. On crimson-and-black that read as misregistered print; on -// Mocha's pastels it read as blur, and it turned every heading in the shell -// soft. The two ghosts still exist, but only for the moment `glitch()` runs. +// The two ghosts either side of the body are the data-corruption flicker NieR +// uses when something changes under you. They are invisible at rest and only +// appear for the moment `glitch()` runs. Item { id: root @@ -16,16 +15,16 @@ Item { property int pixelSize: Theme.fsLarge property int weight: Theme.weightDisplay property string family: Theme.fontDisplay - property bool italic: true + property bool italic: false property color color: Theme.text property int elide: Text.ElideNone property int horizontalAlignment: Text.AlignLeft - property real letterSpacing: 0.5 + property real letterSpacing: Theme.tracking - // Print shadow. Scales gently with size so a 34px heading does not sit on + // Drop shadow. Scales gently with size so a 34px heading does not sit on // the same hairline offset as an 11px label. - property real shadowOffset: Math.max(1, Math.round(root.pixelSize / 10)) - property color shadowColor: Theme.ink + property real shadowOffset: Math.max(1, Math.round(root.pixelSize / 16)) + property color shadowColor: Theme.alpha(Theme.ink, 0.85) // Ghost offset and resting strength. Resting strength is zero, so the // ghosts are invisible until `glitch()` kicks them out. A caller that sets diff --git a/quickshell/config/Theme.qml b/quickshell/config/Theme.qml index e2b12b7..de92057 100644 --- a/quickshell/config/Theme.qml +++ b/quickshell/config/Theme.qml @@ -3,85 +3,93 @@ pragma Singleton import QtQuick import Quickshell -// Mocha palette: Catppuccin Mocha ground, blue as the accent, mauve as the -// alarm. Persona geometry, softer colour. +// YoRHa dark: the NieR:Automata interface language, lit the way +// ~/.wallpapers/space-1.jpg is lit. // -// The Takemi branch ran monochrome-plus-crimson, where one hue carried both -// "active" and "wrong". Mocha has room for two: blue is every resting accent — -// focus, selection, the thing you are pointing at — and mauve is reserved for -// the things that bite, so destructive and error still read at a glance -// without a third colour entering the shell. +// NieR's menus are sand paper and graphite — monochrome, hairline rules, +// letter-spaced capitals, a small square marking where you are, and selection +// shown by inverting the row rather than by colouring it. That language is +// kept whole. The colours are not NieR's: the game's beige is a lit room, and +// this rice is the dark outside the porthole. The ground is the wallpaper's +// grey-green void, the text is the same sage grey the suit catches, and the +// one bright thing on screen is the planet's white — so focus and selection +// are a slab of that light with the void punched out of it. // -// Mauve rather than Mocha's pink: pink is a pastel, and a slab of it over this -// ground goes chalky. Mauve is saturated enough to hold an edge against the -// near-black surfaces the Persona layout is built from. -// -// Everything else is Mocha's own neutral ramp. Fills stay flat and keylines -// stay hard; only the hues moved. +// There is still no third colour. The only warm thing in the wallpaper is the +// tiny red of the hull's indicator lights, and that is what `alarm` is. Singleton { id: root // ---------------------------------------------------------------- colors - // Crust, not pure black: it is the darkest thing in Mocha, so it keeps its - // job as the hard keyline and as text punched out of an accent fill. - readonly property color ink: "#11111b" + // Darker than the ground: text punched out of a light fill, and the + // shadow under display text. + readonly property color ink: "#090a08" - readonly property color base: "#1e1e2e" - readonly property color mantle: "#181825" - readonly property color surface: "#313244" - readonly property color surfaceAlt: "#45475a" - readonly property color overlay: "#585b70" - readonly property color outline: "#6c7086" + // The void. Green-black rather than neutral so the shell and the + // wallpaper read as one dark, not two. + readonly property color base: "#0f110e" + readonly property color mantle: "#0c0d0b" + readonly property color surface: "#161915" + readonly property color surfaceAlt: "#20241f" + readonly property color overlay: "#383e35" - readonly property color text: "#cdd6f4" - readonly property color subtext: "#a6adc8" - readonly property color muted: "#7f849c" + // The hull the desktop is framed by. Darker than anything inside the + // opening, so the frame reads as the inside of the ship and the windows as + // what you are looking out at. + readonly property color hull: root.mantle + readonly property color rim: "#2a2f28" + readonly property color outline: "#545c52" + + readonly property color text: "#ccd2cb" + readonly property color subtext: "#9fa7a2" + readonly property color muted: "#79847a" // ------------------------------------------------------------ THE KNOBS // Two colours, two meanings, and nothing else in the shell carries hue. // - // `accent` is blue: anything live, focused or selected. `alarm` is mauve: + // `accent` is the planet light: anything live, focused or selected. It is + // barely a colour at all, which is the point — NieR marks attention with + // brightness and inversion, not with hue. `alarm` is the hull's red: // anything destructive, failed or critical. Things that are merely off — - // muted, disabled, do-not-disturb — carry no hue at all; see the `Off` - // treatment below. Swap either line and everything derived - // from it recolours. + // muted, disabled, do-not-disturb — stay in the grey ramp; see the `Off` + // treatment below. // // Keep them in step with `c.accent` / `c.alarm` in // ~/.config/hypr/lua/palette.lua, which is what colours the Hyprland // window borders. Those are the only places the colours are written. - readonly property color accent: "#89b4fa" - readonly property color alarm: "#cba6f7" + readonly property color accent: "#eef1ea" + readonly property color alarm: "#c8684f" - readonly property color accentDim: "#5a7dc0" - readonly property color accentSoft: "#b4befe" + readonly property color accentDim: "#8e978d" + readonly property color accentSoft: "#bcc1bf" - // `primary` is the resting voice of the UI, which is now simply white. - // Kept under the old name so the existing call sites don't all have to move. + // `primary` is the resting voice of the UI — the sage text grey. Kept under + // the old name so the existing call sites don't all have to move. readonly property color primary: root.text - readonly property color primaryDim: "#9399b2" + readonly property color primaryDim: "#8e978d" readonly property color deep: root.surfaceAlt - // `glow` is the hover highlight. Pointing at a thing lights it up blue — - // the same signal as focus, because it is the same statement about where - // your attention is. + // `glow` is the hover highlight: pointing at a thing brightens it toward + // the planet light, the same signal as focus at a lower volume. readonly property color glow: root.accent // ------------------------------------------------ semantic treatments // These tokens describe interaction meaning, not new palette entries. Each - // state is composed only from crust, the neutral ramp, blue and mauve, so + // state is composed only from ink, the grey ramp, the light and the red, so // callers do not invent one-off state colours. readonly property color treatmentRestFill: root.surface - readonly property color treatmentRestMark: root.outline + readonly property color treatmentRestMark: root.overlay readonly property color treatmentRestText: root.text - readonly property color treatmentHoverFill: root.surface + // Hover lifts the surface a step and brings the marker up to full light. + // It never inverts: inversion is the cursor, and the pointer resting on + // something is not the same statement as the keyboard choosing it. + readonly property color treatmentHoverFill: root.surfaceAlt readonly property color treatmentHoverMark: root.accent - readonly property color treatmentHoverText: root.text + readonly property color treatmentHoverText: root.accent - // Focus and selection are an inverted slab: solid blue with crust punched - // out of it (9:1). This used to be a white fill, which was right against - // Takemi's black but glares as a lavender-white block on Mocha — and it - // made "selected" a third look that was neither hover nor accent. + // Focus and selection are the NieR cursor: the row inverted, a slab of the + // planet light with ink punched out of it. readonly property color treatmentFocusFill: root.accent readonly property color treatmentFocusMark: root.ink readonly property color treatmentFocusText: root.ink @@ -89,16 +97,16 @@ Singleton { readonly property color treatmentSelectedMark: root.treatmentFocusMark readonly property color treatmentSelectedText: root.treatmentFocusText - readonly property color treatmentActiveFill: root.surface + readonly property color treatmentActiveFill: root.surfaceAlt readonly property color treatmentActiveMark: root.accent - readonly property color treatmentActiveText: root.text + readonly property color treatmentActiveText: root.accent - // Mauve carries destructive/error meaning — never blue, so a dangerous + // Red carries destructive/error meaning — never the light, so a dangerous // button can never be mistaken for a merely focused one. // - // At rest it is a keyline and a label, not a fill. The solid mauve is held + // At rest it is a hairline and a label, not a fill. The solid red is held // back for the moment the pointer or the selection is actually on the - // thing — then it lands hard, with crust punched out of it at 9.1:1. + // thing, with ink punched out of it. readonly property color treatmentDestructiveFill: root.surface readonly property color treatmentDestructiveMark: root.alarm readonly property color treatmentDestructiveText: root.alarm @@ -115,12 +123,11 @@ Singleton { readonly property color treatmentUrgentText: root.text readonly property color treatmentDisabledFill: root.surface - readonly property color treatmentDisabledMark: root.outline + readonly property color treatmentDisabledMark: root.overlay readonly property color treatmentDisabledText: root.muted // Off is a state the user chose — muted, do-not-disturb, radio switched - // off. It is neither live nor wrong, so it gets no hue: painting a muted - // speaker blue said "active", and painting it mauve would say "broken". + // off. It is neither live nor wrong, so it sinks into the grey ramp. readonly property color treatmentOffFill: root.surface readonly property color treatmentOffMark: root.overlay readonly property color treatmentOffText: root.muted @@ -138,27 +145,30 @@ Singleton { a.a + (b.a - a.a) * k); } - // Load readouts sit at text until the number actually matters, then climb - // through the accent before they reach the alarm. Going straight from text - // to mauve passes through a washed-out mid-tone that reads as a faded red - // rather than as a rising number; routing through blue keeps every step of - // the ramp a colour the shell already uses. + // Load readouts sit at text until the number actually matters, brighten + // toward the light, and only then warm into the red. Every step of the ramp + // is a colour the shell already uses. function heat(pct: real): color { - if (pct <= 45) return root.text; - if (pct <= 75) return root.mix(root.text, root.accent, (pct - 45) / 30); - return root.mix(root.accent, root.alarm, (pct - 75) / 25); + if (pct <= 55) return root.text; + if (pct <= 80) return root.mix(root.text, root.accent, (pct - 55) / 25); + return root.mix(root.accent, root.alarm, (pct - 80) / 20); } // ----------------------------------------------------------------- fonts - readonly property string fontDisplay: "Archivo Black" + // NieR sets its UI in FOT-Rodin, a plain Japanese gothic, upright and + // widely tracked. Noto Sans is the closest free face that is already on + // the machine. Display text is never italic and never heavy; the wide + // tracking is what makes it read as a heading. + readonly property string fontDisplay: "Noto Sans" readonly property string fontMono: "JetBrainsMono Nerd Font" readonly property string fontIcon: "JetBrainsMono Nerd Font" - readonly property int weightDisplay: Font.Black - readonly property int weightBody: Font.Medium + readonly property int weightDisplay: Font.Medium + readonly property int weightBody: Font.Normal + + // Letter-spacing for uppercase labels and headings. + readonly property real tracking: 2.5 - // Nothing in the shell renders below this. 9px mono was legible on - // crimson-on-black; on Mocha's lower-contrast ramp it was not. readonly property int fsMicro: 10 readonly property int fsSmall: 11 readonly property int fsBody: 12 @@ -170,27 +180,32 @@ Singleton { readonly property int fsRailIcon: 17 // -------------------------------------------------------------- geometry + // The hull. The bar along the top, the rail down the right and a thin band + // down the left and along the bottom are one continuous surface, and the + // desktop is the rounded opening cut out of it — the porthole the + // wallpaper is looking through. `frame` is the band's thickness where + // there is no bar or rail, `frameRadius` the opening's corner. readonly property int barHeight: 40 - readonly property int barMargin: 8 - readonly property int barGap: 8 - - // The right-hand rail uses the same lean and chamfer as the bar — a - // vertical panel leans its horizontal edges by a fraction of its width, - // which works out to the same 14 degrees. readonly property int railWidth: 48 + readonly property int frame: 8 + readonly property int frameRadius: 18 - // ONE angle, everywhere. tan(14deg). Persona geometry is disciplined, not - // random: every edge in the shell leans by exactly this much in exactly the - // same direction, and every corner is chopped by exactly `cut`. Varying - // these per module reads as noise, not as style. - readonly property real skew: 0.249 - readonly property int cut: 10 - readonly property int stroke: 2 + // Nothing leans and nothing is chopped. NieR panels are plain rectangles; + // their character comes from hairlines, square markers and corner ticks. + // Both knobs are kept so the shape code still has one place to ask. + readonly property real skew: 0 + readonly property int cut: 0 + readonly property int stroke: 1 - // Crust keyline and offset copy behind panels. This is the one piece of - // layering the style needs; it is not a soft shadow and never blurs. - readonly property real dropOffset: 3 - readonly property real keylineWidth: 2 + // No printed drop and no ink contour: on a dark ground they only thicken + // the edge. The shadow under display text is the one offset left. + readonly property real dropOffset: 0 + readonly property real keylineWidth: 0 + + // The square bullet that marks the current row, and the length of the + // corner ticks that frame a panel. + readonly property int marker: 6 + readonly property int tick: 8 readonly property int padS: 6 readonly property int padM: 12 @@ -201,24 +216,27 @@ Singleton { readonly property int popoutGap: 10 // ------------------------------------------------------------ animation - // P5 motion is snappy and slightly overshooting — never soft. - readonly property int durFast: 110 - readonly property int durBase: 190 - readonly property int durSlow: 340 - readonly property int durLazy: 620 + // NieR motion is calm and mechanical: things glide in and settle, they + // never bounce. + readonly property int durFast: 120 + readonly property int durBase: 220 + readonly property int durSlow: 380 + readonly property int durLazy: 700 - readonly property var easeSnap: [0.16, 1.0, 0.3, 1.0, 1, 1] // outExpo-ish - readonly property var easeBack: [0.34, 1.56, 0.64, 1.0, 1, 1] // overshoot + readonly property var easeSnap: [0.22, 1.0, 0.36, 1.0, 1, 1] // outQuint + readonly property var easeGlide: [0.4, 0.0, 0.2, 1.0, 1, 1] // standard readonly property var easeIn: [0.55, 0.0, 0.9, 0.35, 1, 1] // -------------------------------------------------------------- textures - readonly property url texHalftone: "root:/assets/halftone.png" - readonly property url texStripes: "root:/assets/stripes.png" + // A 1px dot every 8px, and a 32px hairline grid — the two backgrounds the + // NieR menus are printed on. + readonly property url texDots: "root:/assets/dots.png" + readonly property url texGrid: "root:/assets/grid.png" readonly property url texScanline: "root:/assets/scanline.png" // Last resort only. The live wallpaper comes from the Wallpaper singleton, // which asks hyprpaper what is actually on screen — a path written down // here goes stale the moment the wallpaper is switched, which is exactly // what happened to the lock screen. - readonly property url fallbackWallpaper: "file:///home/narl/.wallpapers/arch.png" + readonly property url fallbackWallpaper: "file:///home/narl/.wallpapers/space-1.jpg" } diff --git a/quickshell/launcher/Launcher.qml b/quickshell/launcher/Launcher.qml index 2ef64c0..22ab63f 100644 --- a/quickshell/launcher/Launcher.qml +++ b/quickshell/launcher/Launcher.qml @@ -527,7 +527,7 @@ PanelWindow { } NumberAnimation { target: rise; property: "y" - from: 24; to: 0; duration: Theme.durSlow; easing.type: Easing.OutBack + from: 24; to: 0; duration: Theme.durSlow; easing.type: Easing.OutCubic } } diff --git a/quickshell/launcher/ResultRow.qml b/quickshell/launcher/ResultRow.qml index 9846553..0ad94c1 100644 --- a/quickshell/launcher/ResultRow.qml +++ b/quickshell/launcher/ResultRow.qml @@ -46,7 +46,7 @@ Item { color: Theme.accent Behavior on height { - NumberAnimation { duration: Theme.durFast; easing.type: Easing.OutBack } + NumberAnimation { duration: Theme.durFast; easing.type: Easing.OutCubic } } } diff --git a/quickshell/lock/LockFace.qml b/quickshell/lock/LockFace.qml index 177f721..5e46e7e 100644 --- a/quickshell/lock/LockFace.qml +++ b/quickshell/lock/LockFace.qml @@ -75,7 +75,7 @@ Item { reveal: 0 wedgeSpan: 0.30 wedgeOpacity: 0.30 - stripeOpacity: 0.07 + stripeOpacity: 0.04 } // ------------------------------------------------------------ clock @@ -84,17 +84,14 @@ Item { precision: SystemClock.Minutes } - // The house mark, same wordmark the bar carries far left. Small, above the - // clock — the lock's hero is the time, not the branding. - SplitText { + // The house mark, the same porthole the bar carries far left. Small, above + // the clock — the lock's hero is the time, not the branding. + Porthole { id: mark anchors.left: timeBlock.left anchors.bottom: timeBlock.top - anchors.bottomMargin: 6 - text: "P5" - pixelSize: Theme.fsTitle - split: 2 - letterSpacing: 0 + anchors.bottomMargin: 10 + size: 28 opacity: timeBlock.opacity } @@ -110,7 +107,6 @@ Item { text: Qt.formatDateTime(clock.date, "HH") pixelSize: Theme.fsMega * 1.7 split: 5 - splitOpacity: 0.85 } SplitText { @@ -118,7 +114,6 @@ Item { pixelSize: Theme.fsMega * 1.7 color: Theme.primary split: 5 - splitOpacity: 0.6 } Text { @@ -214,8 +209,6 @@ Item { anchors.topMargin: Theme.padL width: Math.min(380, authBlock.width - Theme.padL * 2) height: 56 - lean: 0.12 - chop: 16 fill: Theme.mantle fillOpacity: 0.94 border: surface.failed @@ -251,7 +244,7 @@ Item { property: "scale" from: 0.2; to: 1 duration: Theme.durBase - easing.type: Easing.OutBack + easing.type: Easing.OutCubic } } } @@ -399,7 +392,7 @@ Item { } NumberAnimation { target: shakeShift; property: "x" - to: 0; duration: 90; easing.type: Easing.OutBack + to: 0; duration: 90; easing.type: Easing.OutCubic } } @@ -424,7 +417,7 @@ Item { } NumberAnimation { target: shakeShift; property: "y" - from: 40; to: 0; duration: Theme.durLazy; easing.type: Easing.OutBack + from: 40; to: 0; duration: Theme.durLazy; easing.type: Easing.OutCubic } } } diff --git a/quickshell/lock/RailRow.qml b/quickshell/lock/RailRow.qml index 42e1deb..443cf99 100644 --- a/quickshell/lock/RailRow.qml +++ b/quickshell/lock/RailRow.qml @@ -45,7 +45,6 @@ Item { elide: Text.ElideRight font.family: Theme.fontDisplay font.pixelSize: Theme.fsSmall - font.italic: true font.weight: Font.DemiBold renderType: Text.NativeRendering } diff --git a/quickshell/overlays/Osd.qml b/quickshell/overlays/Osd.qml index e0fda81..ee5f8b1 100644 --- a/quickshell/overlays/Osd.qml +++ b/quickshell/overlays/Osd.qml @@ -111,8 +111,6 @@ PanelWindow { slash: true slashColor: root.tone slashWidth: 5 - lean: 0.09 - chop: 14 padding: Theme.padM opacity: root.shown ? 1 : 0 @@ -122,7 +120,7 @@ PanelWindow { NumberAnimation { id: fade; duration: Theme.durBase } } Behavior on scale { - NumberAnimation { duration: Theme.durSlow; easing.type: Easing.OutBack } + NumberAnimation { duration: Theme.durSlow; easing.type: Easing.OutCubic } } Icon { diff --git a/quickshell/overlays/PowerMenu.qml b/quickshell/overlays/PowerMenu.qml index 1c000cb..ac9e91a 100644 --- a/quickshell/overlays/PowerMenu.qml +++ b/quickshell/overlays/PowerMenu.qml @@ -75,14 +75,12 @@ PanelWindow { } } - // Stripes and wedge, shared with the lock screen. The wedge used to lean at - // 0.32 here, which was its own angle and nothing else's; P5Backdrop leans - // it at Theme.skew like every other edge in the shell. + // Grid and column, shared with the lock screen. P5Backdrop { id: ground anchors.fill: parent reveal: 0 - stripeOpacity: 0.10 + stripeOpacity: 0.05 wedgeOpacity: 0.35 wedgeSpan: 0.34 // The live desktop is still visible behind this, so a dot wash would be @@ -102,29 +100,26 @@ PanelWindow { opacity: 0 SplitText { - text: "TAKE" + text: "GLORY" pixelSize: Theme.fsMega split: 4 - splitOpacity: 0.9 } SplitText { - text: "YOUR" + text: "TO" pixelSize: Theme.fsMega color: Theme.accent split: 4 - splitOpacity: 0.5 } SplitText { - text: "TIME." + text: "MANKIND." pixelSize: Theme.fsMega split: 4 - splitOpacity: 0.9 } Text { - text: "— TAE TAKEMI" + text: "— YORHA" color: Theme.primary font.family: Theme.fontMono font.pixelSize: Theme.fsSmall @@ -212,7 +207,7 @@ PanelWindow { target: slide; property: "x" from: 90; to: 0 duration: Theme.durSlow - easing.type: Easing.OutBack + easing.type: Easing.OutCubic } // Slabs land out of true and snap square. Sliding alone // reads like a slide deck; the tilt is what makes it @@ -223,7 +218,7 @@ PanelWindow { target: tilt; property: "angle" from: -3; to: 0 duration: Theme.durSlow - easing.type: Easing.OutBack + easing.type: Easing.OutCubic easing.overshoot: 2.2 } } diff --git a/quickshell/overlays/Toasts.qml b/quickshell/overlays/Toasts.qml index 9a7c5b7..179cb0c 100644 --- a/quickshell/overlays/Toasts.qml +++ b/quickshell/overlays/Toasts.qml @@ -23,8 +23,8 @@ PanelWindow { anchors { top: true; right: true } margins { - top: Theme.barHeight + Theme.barMargin * 2 - right: Theme.barMargin + top: Theme.barHeight + Theme.frame + right: Theme.railWidth + Theme.frame } implicitWidth: 400 @@ -115,7 +115,7 @@ PanelWindow { onFinished: root.retire(toast.modelData) } - // Slide in from the right, Persona-style. + // Slide in from the right. opacity: 0 transform: Translate { id: shove; x: 60 } @@ -135,7 +135,7 @@ PanelWindow { target: shove; property: "x" from: 60; to: 0 duration: Theme.durSlow - easing.type: Easing.OutBack + easing.type: Easing.OutCubic } } diff --git a/quickshell/popouts/AudioInputBand.qml b/quickshell/popouts/AudioInputBand.qml index cbadc90..78de898 100644 --- a/quickshell/popouts/AudioInputBand.qml +++ b/quickshell/popouts/AudioInputBand.qml @@ -36,7 +36,6 @@ Item { font.family: Theme.fontDisplay font.pixelSize: Theme.fsSmall font.weight: Font.DemiBold - font.italic: true renderType: Text.NativeRendering } diff --git a/quickshell/popouts/AudioOutputHero.qml b/quickshell/popouts/AudioOutputHero.qml index d11c6e7..c8b7e1a 100644 --- a/quickshell/popouts/AudioOutputHero.qml +++ b/quickshell/popouts/AudioOutputHero.qml @@ -16,7 +16,6 @@ Item { font.family: Theme.fontDisplay font.pixelSize: Theme.fsHuge font.weight: Theme.weightDisplay - font.italic: true renderType: Text.NativeRendering } @@ -45,7 +44,6 @@ Item { font.family: Theme.fontDisplay font.pixelSize: Theme.fsSmall font.weight: Font.DemiBold - font.italic: true renderType: Text.NativeRendering } diff --git a/quickshell/popouts/AudioPopout.qml b/quickshell/popouts/AudioPopout.qml index 13906de..e3c8ade 100644 --- a/quickshell/popouts/AudioPopout.qml +++ b/quickshell/popouts/AudioPopout.qml @@ -163,7 +163,6 @@ Popout { font.family: Theme.fontDisplay font.pixelSize: Theme.fsSmall font.weight: Font.DemiBold - font.italic: true renderType: Text.NativeRendering } diff --git a/quickshell/popouts/CalendarPopout.qml b/quickshell/popouts/CalendarPopout.qml index 5190da5..441aa1a 100644 --- a/quickshell/popouts/CalendarPopout.qml +++ b/quickshell/popouts/CalendarPopout.qml @@ -145,8 +145,7 @@ Popout { } font.family: Theme.fontDisplay font.pixelSize: Theme.fsSmall - font.italic: true - font.weight: cell.modelData.today ? Font.Black : Font.Medium + font.weight: cell.modelData.today ? Font.DemiBold : Font.Medium renderType: Text.NativeRendering } } diff --git a/quickshell/popouts/MediaPopout.qml b/quickshell/popouts/MediaPopout.qml index 3316891..42ce57b 100644 --- a/quickshell/popouts/MediaPopout.qml +++ b/quickshell/popouts/MediaPopout.qml @@ -123,8 +123,7 @@ Popout { color: Theme.text pixelSize: Theme.fsLarge family: Theme.fontDisplay - weight: Font.Black - italic: true + weight: Font.DemiBold } Marquee { @@ -134,7 +133,6 @@ Popout { color: Theme.primary pixelSize: Theme.fsSmall family: Theme.fontDisplay - italic: true weight: Font.DemiBold } @@ -359,7 +357,7 @@ Popout { color: { if (!tb.enabled) return Theme.alpha(Theme.muted, 0.5); if (tb.activeFocus) return Theme.treatmentFocusText; - // Ink on the accent slab. White on light blue was barely 2:1. + // Ink on the accent slab, for contrast. if (tbHover.hovered && tb.primary) return Theme.ink; return Theme.text; } @@ -367,7 +365,7 @@ Popout { scale: tbHover.hovered && tb.enabled ? 1.12 : 1.0 Behavior on scale { - NumberAnimation { duration: Theme.durBase; easing.type: Easing.OutBack } + NumberAnimation { duration: Theme.durBase; easing.type: Easing.OutCubic } } HoverHandler { diff --git a/quickshell/popouts/NotifPopout.qml b/quickshell/popouts/NotifPopout.qml index ea880b0..bc2e59c 100644 --- a/quickshell/popouts/NotifPopout.qml +++ b/quickshell/popouts/NotifPopout.qml @@ -56,8 +56,7 @@ Popout { color: Theme.muted font.family: Theme.fontDisplay font.pixelSize: Theme.fsBody - font.italic: true - font.weight: Font.Black + font.weight: Font.DemiBold font.letterSpacing: 3 renderType: Text.NativeRendering } @@ -84,7 +83,7 @@ Popout { properties: "x" from: 40 duration: Theme.durSlow - easing.type: Easing.OutBack + easing.type: Easing.OutCubic } NumberAnimation { property: "opacity" diff --git a/quickshell/popouts/PopoutHeader.qml b/quickshell/popouts/PopoutHeader.qml index a529573..fcb90ee 100644 --- a/quickshell/popouts/PopoutHeader.qml +++ b/quickshell/popouts/PopoutHeader.qml @@ -2,8 +2,8 @@ import QtQuick import "root:/config" import "root:/components" -// Title bar for a popout: glyph, print-shadowed heading, right-aligned status -// text, and a rule with a chopped accent tail. +// Title bar for a popout, in the NieR header pattern: glyph, tracked heading, +// right-aligned status text, and a hairline rule that ends in a square. Item { id: root @@ -31,7 +31,6 @@ Item { anchors.verticalCenter: parent.verticalCenter text: root.title.toUpperCase() pixelSize: Theme.fsLarge - letterSpacing: 1.5 } } @@ -50,19 +49,19 @@ Item { Rectangle { anchors.bottom: parent.bottom + anchors.bottomMargin: (Theme.marker - 1) / 2 anchors.left: parent.left - anchors.right: parent.right - anchors.rightMargin: 22 - height: 2 - color: Theme.alpha(root.accent, 0.8) + anchors.right: endMark.left + height: 1 + color: Theme.alpha(root.accent, 0.6) } - Skew { + Rectangle { + id: endMark anchors.bottom: parent.bottom anchors.right: parent.right - width: 16 - height: 2 + width: Theme.marker + height: Theme.marker color: Theme.accent - lean: 1.4 } } diff --git a/quickshell/popouts/PopoutSurface.qml b/quickshell/popouts/PopoutSurface.qml index 25da113..f4edf0c 100644 --- a/quickshell/popouts/PopoutSurface.qml +++ b/quickshell/popouts/PopoutSurface.qml @@ -10,20 +10,14 @@ P5Panel { fill: Theme.mantle fillOpacity: 0.97 - // A neutral keyline. `tone` used to colour the whole border at 75%, and - // since most panels pass the resting text colour that put a pale 2px frame - // around every popout — the loudest thing on screen for no reason. The - // tone lives in the slash now; the frame is structure. + // The frame is structure: a neutral hairline. The tone goes into the + // corner ticks, which is where NieR puts the one bright mark on a panel. border: Theme.surfaceAlt borderWidth: Theme.stroke halftone: textured halftoneColor: tone halftoneOpacity: 0.06 - sheen: true - slash: true - slashColor: tone - slashWidth: 5 - lean: 0.06 - chop: 16 + ticks: true + tickColor: tone padding: Theme.padM } diff --git a/quickshell/popouts/TrayMenu.qml b/quickshell/popouts/TrayMenu.qml index 49005af..d3cfdb7 100644 --- a/quickshell/popouts/TrayMenu.qml +++ b/quickshell/popouts/TrayMenu.qml @@ -29,7 +29,7 @@ PopupWindow { // The slab's own lean and padding, which the entries sit inside. Sizing the // window to the entry widths alone left every label short by that inset and // elided perfectly ordinary items. - readonly property real slabLean: 0.06 + readonly property real slabLean: Theme.skew readonly property real slabPad: Theme.padS readonly property real contentHeight: list.implicitHeight + slabPad * 2 @@ -114,7 +114,6 @@ PopupWindow { anchors.fill: parent tone: Theme.accent padding: root.slabPad - chop: 12 lean: root.slabLean TrayMenuList { @@ -139,12 +138,12 @@ PopupWindow { } NumberAnimation { target: holder; property: "scale" - to: 1.0; duration: Theme.durSlow; easing.type: Easing.OutBack + to: 1.0; duration: Theme.durSlow; easing.type: Easing.OutCubic } NumberAnimation { target: holder; property: "x" from: root.bleed + 14; to: root.bleed - duration: Theme.durSlow; easing.type: Easing.OutBack + duration: Theme.durSlow; easing.type: Easing.OutCubic } } diff --git a/quickshell/popouts/TrayMenuList.qml b/quickshell/popouts/TrayMenuList.qml index a6a955f..2f3cbc7 100644 --- a/quickshell/popouts/TrayMenuList.qml +++ b/quickshell/popouts/TrayMenuList.qml @@ -84,19 +84,12 @@ Column { width: root.width // ------------------------------------------------------ separator - // - // A horizontal rule slants by a fraction of its own width, so at - // menu width the house lean turns a hairline into a 30px diagonal - // gash straight across the entries above and below it. The rise is - // pinned in pixels instead, matching the rail's dividers. - Skew { + Rectangle { anchors.verticalCenter: parent.verticalCenter visible: row.entry.isSeparator width: parent.width - Theme.padM * 2 x: Theme.padM height: 1 - vertical: true - lean: width > 0 ? 5 / width : 0 color: Theme.alpha(Theme.outline, 0.9) } @@ -226,20 +219,12 @@ Column { NumberAnimation { duration: Theme.durFast; easing.type: Easing.OutExpo } } - // The guide rule down the side of an expanded submenu. - // - // Same trap the separators hit, from the other direction: the - // house lean is a fraction of *height*, and this rule is as tall - // as the submenu. A Wi-Fi list of thirty networks made it 600px - // tall, which sheared a 1px hairline into a 150px crimson wedge - // lying across every entry in the list. The rise is pinned in - // pixels, and it is declared before the entries so it can never - // paint over them again. - Skew { + // The guide rule down the side of an expanded submenu, + // declared before the entries so it can never paint over them. + Rectangle { x: Theme.padS width: 1 height: parent.height - lean: height > 0 ? 5 / height : 0 visible: row.expanded color: Theme.alpha(Theme.accent, 0.8) } diff --git a/quickshell/shell.qml b/quickshell/shell.qml index 0837c65..284d5eb 100644 --- a/quickshell/shell.qml +++ b/quickshell/shell.qml @@ -8,9 +8,10 @@ import "root:/ask" import "root:/overlays" import "root:/lock" -// Takemi — a Persona 5 flavoured Quickshell desktop. +// Takemi — a YoRHa-dark Quickshell desktop: NieR:Automata's interface +// language, lit like the wallpaper. // -// bar/ the top bar and its modules +// bar/ the hull, the top bar, the rail and their modules // popouts/ hover panels hanging off bar modules // launcher/ the application launcher // ask/ the question panel, dropped from the top edge @@ -35,6 +36,12 @@ ShellRoot { void Apps.index; } + Variants { + model: Quickshell.screens + + Frame {} + } + Variants { model: Quickshell.screens