unit-3-hyprland-nier-rice
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseUnit-3 Hyprland NieR:Automata Rice
Unit-3 尼尔机械纪元主题Hyprland桌面配置(Rice)
Skill by ara.so — Daily 2026 Skills collection.
Unit-3 is a fully themed Arch Linux desktop rice combining Hyprland (Wayland compositor), Quickshell (QML-based widget system), and Waybar into a cohesive NieR:Automata aesthetic. It includes custom QML widgets for an app menu, lockscreen, wallpaper picker, notifications, and media player.
由ara.so开发的技能——2026每日技能合集。
Unit-3是一套完整主题化的Arch Linux桌面配置,将Hyprland(Wayland合成器)、Quickshell(基于QML的组件系统)和Waybar整合为统一的尼尔机械纪元视觉风格。它包含自定义QML组件,应用菜单、锁屏、壁纸选择器、通知栏和媒体播放器一应俱全。
Installation
安装
Quick Install (Recommended)
快速安装(推荐)
bash
bash <(curl -fsSL https://raw.githubusercontent.com/samyns/Unit-3/main/install.sh)bash
bash <(curl -fsSL https://raw.githubusercontent.com/samyns/Unit-3/main/install.sh)Manual Clone
手动克隆
bash
git clone https://github.com/samyns/Unit-3.git
cd Unit-3
bash install.shThe installer sets up:
- Hyprland config in
~/.config/hypr/ - Quickshell widgets in
~/.config/quickshell/ - Waybar config in
~/.config/waybar/ - Kitty terminal config
bash
git clone https://github.com/samyns/Unit-3.git
cd Unit-3
bash install.sh安装程序会完成以下配置:
- Hyprland配置文件存放于
~/.config/hypr/ - Quickshell组件存放于
~/.config/quickshell/ - Waybar配置文件存放于
~/.config/waybar/ - Kitty终端配置
Directory Structure
目录结构
Unit-3/
├── install.sh
├── .config/
│ ├── hypr/
│ │ ├── hyprland.conf # Main Hyprland config
│ │ └── user.conf # User overrides (never overwritten)
│ ├── quickshell/
│ │ └── *.qml # Quickshell QML widget files
│ └── waybar/
│ ├── config # Waybar modules config
│ └── style.css # Waybar NieR-themed stylesUnit-3/
├── install.sh
├── .config/
│ ├── hypr/
│ │ ├── hyprland.conf # Hyprland主配置文件
│ │ └── user.conf # 用户自定义配置(永不覆盖)
│ ├── quickshell/
│ │ └── *.qml # Quickshell QML组件文件
│ └── waybar/
│ ├── config # Waybar模块配置
│ └── style.css # 尼尔主题Waybar样式User Configuration (Never Overwritten)
用户自定义配置(永不覆盖)
All personal overrides go in . This file is safe from updates.
~/.config/hypr/user.confconf
undefined所有个人自定义配置需写入,该文件不会被更新覆盖。
~/.config/hypr/user.confconf
undefined~/.config/hypr/user.conf
~/.config/hypr/user.conf
Monitor setup
显示器设置
monitor = DP-1, 2560x1440@144, 0x0, 1
monitor = HDMI-A-1, 1920x1080@60, 2560x0, 1
monitor = DP-1, 2560x1440@144, 0x0, 1
monitor = HDMI-A-1, 1920x1080@60, 2560x0, 1
Input layout
输入布局
input {
kb_layout = us
kb_variant =
follow_mouse = 1
sensitivity = 0
}
input {
kb_layout = us
kb_variant =
follow_mouse = 1
sensitivity = 0
}
Custom keybinds
自定义快捷键
bind = SUPER, B, exec, firefox
bind = SUPER, E, exec, nautilus
bind = SUPER, M, exec, spotify
bind = SUPER, B, exec, firefox
bind = SUPER, E, exec, nautilus
bind = SUPER, M, exec, spotify
Environment variables
环境变量
env = XCURSOR_SIZE, 24
env = GTK_THEME, NieR
---env = XCURSOR_SIZE, 24
env = GTK_THEME, NieR
---Keybinds Reference
快捷键参考
| Key | Action |
|---|---|
| Open app menu |
| Lockscreen |
| Terminal (kitty) |
| Toggle Quickshell player |
| Wallpaper picker |
| Close window |
| Fullscreen toggle |
| Cycle windows |
| Switch workspace |
| Screenshot |
| Region screenshot |
| 按键 | 操作 |
|---|---|
| 打开应用菜单 |
| 锁屏 |
| 打开终端(kitty) |
| 切换Quickshell媒体播放器显示状态 |
| 打开壁纸选择器 |
| 关闭窗口 |
| 切换全屏状态 |
| 循环切换窗口 |
| 切换工作区 |
| 截图 |
| 区域截图 |
QML Widget Development
QML组件开发
Quickshell widgets are written in QML. Unit-3 widgets follow a NieR aesthetic with dark backgrounds and angular UI elements.
Quickshell组件基于QML编写。Unit-3的组件遵循尼尔机械纪元风格,采用深色背景和棱角分明的UI元素。
Basic Quickshell Widget Structure
基础Quickshell组件结构
qml
// ~/.config/quickshell/MyWidget.qml
import Quickshell
import Quickshell.Io
import QtQuick
import QtQuick.Controls
ShellRoot {
// Panels are screen-anchored overlays
PanelWindow {
id: myPanel
anchors {
top: true
left: true
right: true
}
height: 40
color: "transparent"
Rectangle {
anchors.fill: parent
color: "#1a1a1a"
border.color: "#c8a951" // NieR gold accent
border.width: 1
Text {
anchors.centerIn: parent
text: "Unit-3"
color: "#e8d5a3"
font.family: "monospace"
font.pixelSize: 14
}
}
}
}qml
// ~/.config/quickshell/MyWidget.qml
import Quickshell
import Quickshell.Io
import QtQuick
import QtQuick.Controls
ShellRoot {
// Panel是锚定屏幕的覆盖层
PanelWindow {
id: myPanel
anchors {
top: true
left: true
right: true
}
height: 40
color: "transparent"
Rectangle {
anchors.fill: parent
color: "#1a1a1a"
border.color: "#c8a951" // 尼尔金色强调色
border.width: 1
Text {
anchors.centerIn: parent
text: "Unit-3"
color: "#e8d5a3"
font.family: "monospace"
font.pixelSize: 14
}
}
}
}Notification Widget Pattern
通知组件示例
qml
// Notification popup following NieR style
import Quickshell
import Quickshell.Services.Notifications
import QtQuick
ShellRoot {
NotificationServer {
id: notifServer
}
Variants {
model: notifServer.trackedNotifications
PanelWindow {
required property var modelData
property var notification: modelData
anchors {
top: true
right: true
}
margins.top: 10
margins.right: 10
width: 320
height: 80
color: "transparent"
Rectangle {
anchors.fill: parent
color: "#101418"
border.color: "#c8a951"
border.width: 1
radius: 2
Column {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
leftMargin: 16
}
spacing: 4
Text {
text: notification.summary
color: "#c8a951"
font.pixelSize: 13
font.bold: true
}
Text {
text: notification.body
color: "#9a9a8a"
font.pixelSize: 11
}
}
MouseArea {
anchors.fill: parent
onClicked: notification.dismiss()
}
}
// Auto-dismiss timer
Timer {
interval: 5000
running: true
onTriggered: notification.dismiss()
}
}
}
}qml
// 尼尔风格通知弹窗
import Quickshell
import Quickshell.Services.Notifications
import QtQuick
ShellRoot {
NotificationServer {
id: notifServer
}
Variants {
model: notifServer.trackedNotifications
PanelWindow {
required property var modelData
property var notification: modelData
anchors {
top: true
right: true
}
margins.top: 10
margins.right: 10
width: 320
height: 80
color: "transparent"
Rectangle {
anchors.fill: parent
color: "#101418"
border.color: "#c8a951"
border.width: 1
radius: 2
Column {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
leftMargin: 16
}
spacing: 4
Text {
text: notification.summary
color: "#c8a951"
font.pixelSize: 13
font.bold: true
}
Text {
text: notification.body
color: "#9a9a8a"
font.pixelSize: 11
}
}
MouseArea {
anchors.fill: parent
onClicked: notification.dismiss()
}
}
// 自动关闭计时器
Timer {
interval: 5000
running: true
onTriggered: notification.dismiss()
}
}
}
}Media Player Widget Pattern
媒体播放器组件示例
qml
// ~/.config/quickshell/Player.qml
import Quickshell
import Quickshell.Services.Mpris
import QtQuick
import QtQuick.Controls
ShellRoot {
FloatingWindow {
id: playerWindow
visible: false // toggled by SUPER + Return
width: 340
height: 100
color: "transparent"
Rectangle {
anchors.fill: parent
color: "#0d1117"
border.color: "#c8a951"
border.width: 1
Row {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
leftMargin: 12
}
spacing: 12
// Album art
Rectangle {
width: 64
height: 64
color: "#1a1a1a"
border.color: "#c8a951"
border.width: 1
Image {
anchors.fill: parent
source: MprisController.currentPlayer?.trackArtUrl ?? ""
fillMode: Image.PreserveAspectCrop
}
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 4
Text {
text: MprisController.currentPlayer?.trackTitle ?? "No media"
color: "#e8d5a3"
font.pixelSize: 13
font.bold: true
elide: Text.ElideRight
width: 220
}
Text {
text: MprisController.currentPlayer?.trackArtist ?? ""
color: "#9a9a8a"
font.pixelSize: 11
}
// Playback controls
Row {
spacing: 8
Repeater {
model: ["⏮", "⏯", "⏭"]
Text {
text: modelData
color: "#c8a951"
font.pixelSize: 16
MouseArea {
anchors.fill: parent
onClicked: {
if (index === 0) MprisController.currentPlayer?.previous()
else if (index === 1) MprisController.currentPlayer?.playPause()
else MprisController.currentPlayer?.next()
}
}
}
}
}
}
}
}
}
}qml
// ~/.config/quickshell/Player.qml
import Quickshell
import Quickshell.Services.Mpris
import QtQuick
import QtQuick.Controls
ShellRoot {
FloatingWindow {
id: playerWindow
visible: false // 通过SUPER + Return切换显示
width: 340
height: 100
color: "transparent"
Rectangle {
anchors.fill: parent
color: "#0d1117"
border.color: "#c8a951"
border.width: 1
Row {
anchors {
left: parent.left
verticalCenter: parent.verticalCenter
leftMargin: 12
}
spacing: 12
// 专辑封面
Rectangle {
width: 64
height: 64
color: "#1a1a1a"
border.color: "#c8a951"
border.width: 1
Image {
anchors.fill: parent
source: MprisController.currentPlayer?.trackArtUrl ?? ""
fillMode: Image.PreserveAspectCrop
}
}
Column {
anchors.verticalCenter: parent.verticalCenter
spacing: 4
Text {
text: MprisController.currentPlayer?.trackTitle ?? "无媒体播放"
color: "#e8d5a3"
font.pixelSize: 13
font.bold: true
elide: Text.ElideRight
width: 220
}
Text {
text: MprisController.currentPlayer?.trackArtist ?? ""
color: "#9a9a8a"
font.pixelSize: 11
}
// 播放控制
Row {
spacing: 8
Repeater {
model: ["⏮", "⏯", "⏭"]
Text {
text: modelData
color: "#c8a951"
font.pixelSize: 16
MouseArea {
anchors.fill: parent
onClicked: {
if (index === 0) MprisController.currentPlayer?.previous()
else if (index === 1) MprisController.currentPlayer?.playPause()
else MprisController.currentPlayer?.next()
}
}
}
}
}
}
}
}
}
}Wallpaper Picker Widget
壁纸选择器组件
qml
// ~/.config/quickshell/WallpaperPicker.qml
import Quickshell
import Quickshell.Io
import QtQuick
import QtQuick.Layouts
ShellRoot {
property string wallpaperDir: "/home/" + Qt.application.name + "/Pictures/Wallpapers"
FloatingWindow {
id: pickerWindow
width: 800
height: 500
Rectangle {
anchors.fill: parent
color: "#0d1117"
border.color: "#c8a951"
border.width: 1
GridView {
anchors {
fill: parent
margins: 16
}
cellWidth: 180
cellHeight: 120
model: FileView {
path: wallpaperDir
nameFilters: ["*.jpg", "*.png", "*.webp"]
}
delegate: Rectangle {
width: 172
height: 112
color: "#1a1a1a"
border.color: mouseArea.containsMouse ? "#c8a951" : "transparent"
border.width: 2
Image {
anchors.fill: parent
anchors.margins: 2
source: "file://" + model.filePath
fillMode: Image.PreserveAspectCrop
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
// Set wallpaper via swww
Process.exec(["swww", "img", model.filePath,
"--transition-type", "wipe",
"--transition-angle", "30"])
pickerWindow.visible = false
}
}
}
}
}
}
}qml
// ~/.config/quickshell/WallpaperPicker.qml
import Quickshell
import Quickshell.Io
import QtQuick
import QtQuick.Layouts
ShellRoot {
property string wallpaperDir: "/home/" + Qt.application.name + "/Pictures/Wallpapers"
FloatingWindow {
id: pickerWindow
width: 800
height: 500
Rectangle {
anchors.fill: parent
color: "#0d1117"
border.color: "#c8a951"
border.width: 1
GridView {
anchors {
fill: parent
margins: 16
}
cellWidth: 180
cellHeight: 120
model: FileView {
path: wallpaperDir
nameFilters: ["*.jpg", "*.png", "*.webp"]
}
delegate: Rectangle {
width: 172
height: 112
color: "#1a1a1a"
border.color: mouseArea.containsMouse ? "#c8a951" : "transparent"
border.width: 2
Image {
anchors.fill: parent
anchors.margins: 2
source: "file://" + model.filePath
fillMode: Image.PreserveAspectCrop
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: {
// 通过swww设置壁纸
Process.exec(["swww", "img", model.filePath,
"--transition-type", "wipe",
"--transition-angle", "30"])
pickerWindow.visible = false
}
}
}
}
}
}
}Waybar Configuration Pattern
Waybar配置示例
jsonc
// ~/.config/waybar/config (NieR modules example)
{
"layer": "top",
"position": "top",
"height": 32,
"modules-left": ["hyprland/workspaces", "hyprland/window"],
"modules-center": ["clock"],
"modules-right": ["pulseaudio", "network", "battery", "tray"],
"hyprland/workspaces": {
"format": "{id}",
"on-click": "activate"
},
"clock": {
"format": "{:%H:%M}",
"format-alt": "{:%Y-%m-%d %H:%M:%S}",
"tooltip-format": "<big>{:%Y %B}</big>\n<tt>{calendar}</tt>"
},
"network": {
"format-wifi": " {essid}",
"format-ethernet": " {ipaddr}",
"format-disconnected": " disconnected",
"tooltip-format": "{ifname}: {ipaddr}"
},
"pulseaudio": {
"format": " {volume}%",
"format-muted": " muted",
"on-click": "pavucontrol"
}
}css
/* ~/.config/waybar/style.css — NieR color palette */
* {
font-family: "monospace";
font-size: 13px;
}
window#waybar {
background: rgba(13, 17, 23, 0.92);
border-bottom: 1px solid #c8a951;
color: #e8d5a3;
}
#workspaces button {
color: #9a9a8a;
border-radius: 0;
padding: 0 8px;
border-bottom: 2px solid transparent;
}
#workspaces button.active {
color: #c8a951;
border-bottom: 2px solid #c8a951;
}
#clock {
color: #c8a951;
font-weight: bold;
letter-spacing: 2px;
}
#network, #pulseaudio, #battery {
color: #e8d5a3;
padding: 0 12px;
}jsonc
// ~/.config/waybar/config(尼尔主题模块示例)
{
"layer": "top",
"position": "top",
"height": 32,
"modules-left": ["hyprland/workspaces", "hyprland/window"],
"modules-center": ["clock"],
"modules-right": ["pulseaudio", "network", "battery", "tray"],
"hyprland/workspaces": {
"format": "{id}",
"on-click": "activate"
},
"clock": {
"format": "{:%H:%M}",
"format-alt": "{:%Y-%m-%d %H:%M:%S}",
"tooltip-format": "<big>{:%Y %B}</big>\n<tt>{calendar}</tt>"
},
"network": {
"format-wifi": " {essid}",
"format-ethernet": " {ipaddr}",
"format-disconnected": " 已断开",
"tooltip-format": "{ifname}: {ipaddr}"
},
"pulseaudio": {
"format": " {volume}%",
"format-muted": " 已静音",
"on-click": "pavucontrol"
}
}css
/* ~/.config/waybar/style.css — 尼尔配色方案 */
* {
font-family: "monospace";
font-size: 13px;
}
window#waybar {
background: rgba(13, 17, 23, 0.92);
border-bottom: 1px solid #c8a951;
color: #e8d5a3;
}
#workspaces button {
color: #9a9a8a;
border-radius: 0;
padding: 0 8px;
border-bottom: 2px solid transparent;
}
#workspaces button.active {
color: #c8a951;
border-bottom: 2px solid #c8a951;
}
#clock {
color: #c8a951;
font-weight: bold;
letter-spacing: 2px;
}
#network, #pulseaudio, #battery {
color: #e8d5a3;
padding: 0 12px;
}Hyprland Config Patterns
Hyprland配置示例
conf
undefinedconf
undefined~/.config/hypr/hyprland.conf (snippet)
~/.config/hypr/hyprland.conf(代码片段)
NieR-style animations
尼尔风格动画
animations {
enabled = true
bezier = nier, 0.05, 0.9, 0.1, 1.0
animation = windows, 1, 4, nier, slide
animation = fade, 1, 4, nier
animation = workspaces, 1, 5, nier, slidevert
}
animations {
enabled = true
bezier = nier, 0.05, 0.9, 0.1, 1.0
animation = windows, 1, 4, nier, slide
animation = fade, 1, 4, nier
animation = workspaces, 1, 5, nier, slidevert
}
Minimal decorations for NieR aesthetic
尼尔风格极简窗口装饰
decoration {
rounding = 0
blur {
enabled = true
size = 4
passes = 2
noise = 0.02
contrast = 1.0
brightness = 0.9
}
drop_shadow = true
shadow_color = rgba(200, 169, 81, 0.4)
shadow_range = 8
}
decoration {
rounding = 0
blur {
enabled = true
size = 4
passes = 2
noise = 0.02
contrast = 1.0
brightness = 0.9
}
drop_shadow = true
shadow_color = rgba(200, 169, 81, 0.4)
shadow_range = 8
}
Window gaps
窗口间距
general {
gaps_in = 4
gaps_out = 8
border_size = 1
col.active_border = rgba(c8a951ff)
col.inactive_border = rgba(2a2a2aff)
}
---general {
gaps_in = 4
gaps_out = 8
border_size = 1
col.active_border = rgba(c8a951ff)
col.inactive_border = rgba(2a2a2aff)
}
---Troubleshooting
故障排查
Quickshell widgets not appearing
Quickshell组件不显示
bash
undefinedbash
undefinedCheck if quickshell is running
检查Quickshell是否在运行
pgrep -a quickshell
pgrep -a quickshell
Restart quickshell
重启Quickshell
pkill quickshell && quickshell &
pkill quickshell && quickshell &
Check logs for QML errors
检查QML错误日志
quickshell 2>&1 | grep -i error
undefinedquickshell 2>&1 | grep -i error
undefinedWaybar not loading
Waybar无法加载
bash
undefinedbash
undefinedValidate config syntax
验证配置语法
waybar --log-level debug
waybar --log-level debug
Reload waybar
重启Waybar
pkill waybar && waybar &
pkill waybar && waybar &
Check config location
检查配置文件位置
ls ~/.config/waybar/
undefinedls ~/.config/waybar/
undefinedHyprland keybinds not working
Hyprland快捷键不生效
bash
undefinedbash
undefinedCheck active config
检查当前生效配置
hyprctl activewindow
hyprctl getoption general:border_size
hyprctl activewindow
hyprctl getoption general:border_size
Reload config live
实时重载配置
hyprctl reload
hyprctl reload
Verify user.conf is sourced
确认user.conf已被加载
grep "user.conf" ~/.config/hypr/hyprland.conf
undefinedgrep "user.conf" ~/.config/hypr/hyprland.conf
undefinedWallpaper not setting (swww)
壁纸无法设置(swww)
bash
undefinedbash
undefinedInitialize swww daemon first
先初始化sww守护进程
swww-daemon &
swww-daemon &
Then set wallpaper
再设置壁纸
swww img ~/Pictures/wall.jpg --transition-type wipe
undefinedswww img ~/Pictures/wall.jpg --transition-type wipe
undefinedWrong monitor layout
显示器布局错误
conf
undefinedconf
undefined~/.config/hypr/user.conf
~/.config/hypr/user.conf
List available monitors first:
先列出可用显示器:
hyprctl monitors
hyprctl monitors
monitor = DP-1, 2560x1440@144, 0x0, 1
monitor = HDMI-A-1, 1920x1080@60, 2560x0, 1
---monitor = DP-1, 2560x1440@144, 0x0, 1
monitor = HDMI-A-1, 1920x1080@60, 2560x0, 1
---NieR Color Palette Reference
尼尔机械纪元配色参考
| Name | Hex | Usage |
|---|---|---|
| Gold accent | | Borders, active elements |
| Light text | | Primary text |
| Dim text | | Secondary text |
| Background | | Main background |
| Surface | | Widget backgrounds |
| Dark surface | | Inset elements |
| 名称 | 十六进制码 | 用途 |
|---|---|---|
| 金色强调色 | | 边框、活跃元素 |
| 浅色文本 | | 主要文本 |
| 暗色文本 | | 次要文本 |
| 主背景色 | | 整体背景 |
| 组件背景色 | | 组件背景 |
| 深色组件色 | | 内嵌元素 |
Updating the Rice
更新桌面配置
bash
cd ~/Unit-3 # or wherever you cloned it
git pull
bash install.sh # re-runs installer; user.conf is preservedbash
cd ~/Unit-3 # 或你克隆到的目录
git pull
bash install.sh # 重新运行安装程序;user.conf会被保留