Тайловый оконный менеджер для Linux-консоли в эстетике SuperHot: Mind Control Delete
Полная замена
agettyс DRM/KMS direct access, login screen (PAM/shadow), multi-monitor, window rules, autostart, launcher (.desktop), X11 встраивание с GPU-ускорением (DRI3/DMA-BUF + hardware cursor + overlay planes), MCD-style glitch-анимации перехода между workspaces, live-reload конфигурации через inotify, IPC-сокет (i3-msg-совместимый протокол), полная xterm совместимость через libvterm, PipeWire звуком и xdg-desktop-portal для screen share.
- Что нового в v0.5
- Ключевые возможности
- Архитектура
- Быстрый старт
- Установка
- Конфигурация (полный справочник)
- Пути и приоритет
- [general] — общие настройки
- [theme] — цвета интерфейса
- [login] — экран входа
- [[workspaces]] — рабочие пространства
- [[monitors]] — мульти-монитор
- [[window_rules]] — правила размещения окон
- [[autostart]] — автозапуск
- [launcher] — лаунчер приложений
- [popups] — попапы
- [[keybindings]] — горячие клавиши
- [live_reload] — live-reload конфигурации
- [animations] — glitch-анимации MCD-style
- [ipc] — IPC сокет (i3-msg совместимый)
- [x11] — X11 встраивание и GPU-ускорение
- [audio] — звук (PipeWire)
- [portal] — xdg-desktop-portal
- [gamepad] — геймпады
- Сводная таблица всех полей
- Горячие клавиши (по умолчанию)
- Login screen
- Multi-monitor
- Window rules
- Autostart
- Launcher
- Popups из скриптов
- Live reload конфигурации
- Glitch-анимации MCD-style
- IPC сокет (i3-msg совместимый)
- Полная xterm совместимость (libvterm)
- X11 встраивание (Xephyr + DRI3 + overlay planes)
- Звук и screen share
- Геймпады
- Сборка пакетов
- Структура проекта
- История версий
- FAQ
- Устранение неполадок
- Лицензия
- Inotify-наблюдатель на
config.tomlв отдельном потоке (черезlibc::inotify_add_watch) - Debounce (
live_reload.debounce_ms, по умолчанию 250 мс) для защиты от множественных событий - Автоматическое применение изменений на лету (без перезапуска WM):
theme.*— пересборкаThemeи немедленное использование при рендереkeybindings— новые биндинги активны сразуwindow_rules— применяются к новым окнамanimations.*— параметры анимацийipc.*(кромеsocket_path)live_reload.*,popups.*,general.glitch_intensity/framerate/gap/border
- Поля, требующие перезапуска, логируются как warning:
general.font,general.font_size,general.workspace_countmonitors,x11.display,x11.screen_size,x11.dri3,x11.overlay_planes
ConfigDiff— детектор изменений для отладки (логирует что именно поменялось)
Три типа анимаций, все с corner-to-corner reveal (TL → BR диагональ):
1. Workspace transition — при переключении между workspaces:
- Transition (
ws_transition_ms, по умолчанию 250 мс) — все символы экрана (терминальные ячейки, разделители, X11-окна как квадраты █▓) перебираются случайными символами - Manifest (
ws_manifest_ms, по умолчанию 200 мс) — поверх перебора проявляется целевой ws: добавляются недостающие символы, исчезают лишние. Перебор всё ещё идёт для остальных ячеек - Reveal (
ws_reveal_ms, по умолчанию 250 мс) — от левого верхнего угла к правому нижнему символы фиксируются в финальном состоянии
2. New window — при создании нового окна/терминала:
- Fill (
new_window_fill_ms, по умолчанию 600 мс) — квадрат нового окна заливается перебором - Reveal (
new_window_reveal_ms, по умолчанию 250 мс) — corner-to-corner внутри rect окна
3. Random glitch — спонтанный быстрый глитч:
- Длительность
random_glitch_ms(по умолчанию 120 мс — короче, чем ws transition) - Частота =
general.glitch_intensity/random_glitch_every_frames - Скорость перебора
random_chars_per_sec(по умолчанию 220 chars/sec — значительно быстрее)
Набор символов для перебора полностью настраивается:
- Заглавные A-Z (
glitch_use_alpha) - Квадраты с разной заливкой: ░ ▒ ▓ █ ■ □ ▢ ▣ ▤ ▥ ▦ ▧ ▨ ▩ ▀ ▄ ▌ ▐ (
glitch_use_blocks) - Цифры 0-9 (
glitch_use_digits)
- UNIX-доменный сокет (по умолчанию
$XDG_RUNTIME_DIR/superhot-tty.sockили/tmp/superhot-tty-$UID.sock) - JSON-протокол: команды и запросы
- Поддерживаемые команды (i3-msg синтаксис):
workspace N|next|prev— переключение wsmove to workspace N— переместить окноexec CMD [ARGS],exec --no-startup-id CMD— запуск программkill,reload,restart,quit,split h|v,focus dir,fullscreen toggle,layout toggle,launcher,glitch
- Запросы:
get_workspaces,get_config,get_focused,get_version - Standalone CLI утилита
shtty-msg(второй binary в crate)
- Runtime FFI к
libvterm.so.0черезlibloading(без жёсткой зависимости) - Если libvterm доступна — используется полная xterm state machine (CSI/OSC/DCS, 256/truecolor, cursor styles, mouse tracking, DEC modes, OSC 4/8/52, ...)
- Если нет — fallback на расширенный built-in ANSI-парсер:
- CSI: A-Z (cursor), J/K (erase), m (SGR), r (scroll region), L/M/P/@/S/T, s/u (save/restore), E/F/G/d, n (DSR)
- Private modes: 1049/47/1047 (alt screen), 25 (cursor vis), 7 (autowrap), 1 (cursor keys), 12 (cursor blink)
- ESC: D (IND), E (NEL), M (RI), c (RIS), 7/8 (DECSC/DECRC), =/> (keypad)
- OSC: 0/2 (title), 4 (palette), 8 (hyperlink), 52 (clipboard)
- SGR: bold/italic/underline/reverse, 16-color, 256-color, truecolor → 16-color палитра
- Версия bumped до
0.5.0 - Добавлены секции конфига:
[live_reload],[animations],[ipc] - Добавлен второй binary
shtty-msg(CLI для IPC) - Обновлён README с полной документацией
- Тайловый layout в стиле BSP/i3: бинарное дерево тайлов, split h/v, ratio resize
- 10 workspaces (1..9 + 0=10) с независимыми layout-деревьями
- Multi-monitor: per-monitor workspace binding (как Hyprland)
- Перемещение окон по тайловой сетке и между workspaces
- Fullscreen toggle, resize mode, cycle focus
- Live-reload конфигурации (theme/keybindings/window_rules/animations/ipc) — без перезапуска
- PAM аутентификация (service "login") при сборке с
--features pam - Fallback на
/etc/shadow+crypt(3)без PAM (по умолчанию) - MCD-themed: большой заголовок по центру, glitch border, corner brackets
- Настраиваемый текст: "MORE" / "БОЛЬШЕ" / свой
- Clock, hint, error display
- Rofi-подобный launcher
Mod4+D— читает.desktopфайлы - Terminal=true приложения открываются в нативном терминале
- Window rules для авто-placement по WM_CLASS/WM_NAME
- Autostart для запуска при старте WM
- Xephyr на
:1+ Composite redirect + XDamage - DRI3 + DMA-BUF для GPU-ускорения (FFI к
libxcb-dri3) - Hardware DRM cursor plane — 0% CPU, без перерисовки framebuffer
- Hardware DRM overlay planes — 0% CPU для X11 rendering
- Auto-place: новые X11 окна автоматически размещаются по правилам или на active ws
- Workspace transition — glitch-перебор символов при переключении ws
- New window — заливка нового окна перебором + corner-to-corner reveal
- Random glitch — спонтанный быстрый глитч (настраиваемая вероятность)
- Все параметры (длительность фаз, набор символов, скорость перебора, цвет) настраиваются
- UNIX-domain сокет, JSON-протокол
- CLI утилита
shtty-msg - Скриптование WM извне (workspace, exec, kill, reload, get_workspaces, ...)
- PTY через
libc::openpty+fork/execvp - Полная xterm совместимость через libvterm (если доступна)
- Fallback ANSI-парсер на ~95% случаев (если libvterm нет)
- 256-color + truecolor поддержка (truecolor аппроксимируется в 16-color палитру)
- OSC title — синхронизация заголовка tile с
WM_NAMEприложения
- Клавиатура через evdev (эксклюзивный grab)
- Мышь через evdev + MCD-styled курсор (софтверный или hardware DRM cursor plane)
- Геймпады: evdev passthrough (Steam Input) + опционально SDL2
- PipeWire + pipewire-pulse + wireplumber (автозапуск)
- xdg-desktop-portal backend для screen sharing в OBS/Discord
+------------------------------------------------------------------------+
| superhot-tty v0.5 |
| |
| 1. LOGIN SCREEN (PAM) |
| ┌─────────────────────────┐ |
| │ БОЛЬШЕ / MORE │ |
| │ (themed MCD login) │ |
| │ login → password │ |
| └───────────┬─────────────┘ |
| │ PAM auth success |
| ▼ |
| 2. WM (after switch_to_user) |
| +----------+ +-----------+ +------------+ +--------------------+ |
| | Keyboard | | Mouse | | Gamepad | | Config (TOML) | |
| | (evdev) | | (evdev) | | (SDL2/ | | ~/.config/ | |
| | | | +cursor | | passthru) | | SH-tty/ | |
| +---+------+ +---+-------+ +--+---------+ +-----+--------------+ |
| \ | / | |
| +-----v-----------v----------v-+ +----------v----------+ |
| | Window Rules Engine | | Autostart | |
| | (match WM_CLASS → placement) | | (run on WM start) | |
| +-------------+----------------+ +---------+-----------+ |
| | | |
| +-------------v---------------------------------v----------+ |
| | IPC Server ← shtty-msg Animation Manager | |
| | (i3-msg JSON protocol) (MCD glitch animations) | |
| +-------------+-------------------------------------+------+ |
| | | |
| +-------------v-------------------------------------v------+ |
| | Launcher + Layout + Workspaces | |
| | (.desktop scanner, BSP tree, 10 ws) | |
| +-------------------------+--------------------------------+ |
| | |
| +---------v---------+ |
| | Canvas + Font | ← live-reload |
| | + VTerm (libvterm)| theme/animations |
| +---------+---------+ |
| | |
| +---------v---------+ |
| | Multi-Monitor | ← per-monitor CRTC |
| | DRM/KMS | ← per-monitor ws |
| | + DRI3 + Planes | ← GPU Aceleration for X11 |
| +-------------------+ |
| |
| Watchers: |
| • ConfigWatcher (inotify) → ConfigDiff → hot-apply |
| • IPC listener thread → IpcRequest → execute |
| |
| Sidecar: Xephyr :1, PipeWire, xdg-desktop-portal |
+------------------------------------------------------------------------+
# 1. Установить зависимости (Arch Linux)
sudo pacman -S rust cargo gcc pkgconf systemd kbd zsh pam \
xorg-server-xvfb xorg-server-xephyr \
freetype2 fontconfig ttf-dejavu \
pipewire pipewire-pulse wireplumber \
xdg-desktop-portal libvterm
# 2. Клонировать и собрать
git clone https://github.com/TumRedSun/SH-tty.git
cd SH-tty
cargo build --release
# Если freetype2 system library недоступна (ошибка "Package freetype2 not found"),
# можно собрать без TTF поддержки (fallback на PSF bitmap шрифты):
# cargo build --release --no-default-features
# 3. Установить
sudo install -Dm755 target/release/superhot-tty /usr/local/bin/
sudo install -Dm755 target/release/shtty-msg /usr/local/bin/
sudo install -Dm644 systemd/superhot-tty@.service /etc/systemd/system/
sudo install -Dm644 config/default.toml /etc/SH-tty/config.toml
# 4. Активировать (заменяет getty на tty1)
sudo systemctl disable getty@tty1
sudo systemctl enable superhot-tty@tty1
sudo reboot
# 5. После перезагрузки — themed login screen на tty1
# Login → Password → shellДля других дистрибутивов см. Установка.
Соберите пакеты (см. Сборка пакетов) или скачайте pre-built:
Arch Linux:
sudo pacman -U superhot-tty-0.5.0-1-x86_64.pkg.tar.zstDebian/Ubuntu:
sudo dpkg -i superhot-tty_0.5.0_amd64.deb
sudo apt-get install -f # разрешить зависимостиFedora/RHEL:
sudo dnf install superhot-tty-0.5.0-1.x86_64.rpmПосле установки:
sudo systemctl disable getty@tty1
sudo systemctl enable superhot-tty@tty1
sudo rebootgit clone https://github.com/TumRedSun/SH-tty.git
cd SH-tty
cargo build --release
sudo install -Dm755 target/release/superhot-tty /usr/local/bin/
sudo install -Dm755 target/release/shtty-msg /usr/local/bin/
sudo install -Dm644 systemd/superhot-tty@.service /etc/systemd/system/
sudo install -Dm644 config/default.toml /etc/SH-tty/config.toml
sudo systemctl disable getty@tty1
sudo systemctl enable superhot-tty@tty1
sudo rebootОбязательные:
rust cargo gcc pkgconf systemd kbd zsh pam
xorg-server-xephyr
pipewire pipewire-pulse wireplumber
xdg-desktop-portal
Опциональные (но рекомендуются):
libvterm # полная xterm совместимость (fallback built-in парсер без неё)
libxcb-dri3 # DRI3 GPU-ускорение
sdl2 # для --features gamepad-sdl2
libpam0g-dev # для --features pam (иначе fallback на /etc/shadow)
xdg-desktop-portal-gtk # GTK file chooser
# По умолчанию — без PAM, без SDL2
cargo build --release
# С PAM (реальная PAM аутентификация вместо /etc/shadow)
cargo build --release --features pam
# С SDL2 геймпадом (для не-Steam сценария)
cargo build --release --features gamepad-sdl2
# Всё сразу
cargo build --release --features pam,gamepad-sdl2superhot-tty ищет конфиг в следующем порядке (первый найденный используется):
$XDG_CONFIG_HOME/SH-tty/config.toml(обычно~/.config/SH-tty/config.toml)~/.config/SH-tty/config.toml/etc/SH-tty/config.toml(system-wide)
Пример конфига со всеми секциями и комментариями — config/default.toml в репозитории.
Все секции имеют значения по умолчанию — пропущенные поля берутся из defaults. Можно иметь минимальный конфиг только с теми полями, которые нужно переопределить:
[general]
shell = "bash"
[login]
language = "ru"[general]
shell = "zsh" # shell для нативных терминалов
font = "Lat2-Terminus16" # PSF-шрифт (PSF1/PSF2, ищется в /usr/share/kbd/consolefonts/)
font_size = 16 # размер шрифта (для информации, реальный размер — из PSF)
gap = 4 # зазор между тайлами в пикселях
border = 1 # толщина бордюра неактивного тайла
outer_padding = 4 # внешний padding от краёв экрана
status_bar_height = 24 # высота статус-бара внизу
framerate = 60 # целевой FPS (60 = 16.67 мс на кадр)
glitch_intensity = 0.15 # 0.0..1.0 — вероятность random glitch
workspace_count = 10 # 1..9 + 0=10 (как в i3)Поля, требующие перезапуска при изменении:
font,font_size— нужна новая загрузка PSFworkspace_count— пересоздание структур Workspaces
Hot-reload: gap, border, outer_padding, status_bar_height, framerate, glitch_intensity, shell.
Все цвета в hex-формате #RRGGBB.
[theme]
bg = "#0A0716" # фон экрана (тёмно-фиолетовый)
tile_bg_inactive = "#120E24" # фон неактивного тайла
tile_bg_active = "#0F0A1E" # фон активного тайла
border_inactive = "#3A2D5C" # бордюр неактивного тайла
border_active = "#FF2E97" # бордюр активного тайла (магента)
border_x11 = "#00F0FF" # бордюр X11 тайла (циан)
fg_default = "#E6E1F0" # основной текст
fg_dim = "#7A6F96" # приглушённый текст
accent_magenta = "#FF2E97" # акцент магента
accent_cyan = "#00F0FF" # акцент циан (используется для glitch_color)
popup_bg = "#140B2E" # фон попапа
popup_border = "#FF2E97" # бордюр попапа
error = "#FF4D4D" # текст ошибокHot-reload: да, все поля — Theme пересобирается сразу.
[login]
title = "" # пусто → использовать language default
subtitle = "" # пусто → использовать language default
language = "en" # "en" → "MORE" / "SUPERHOT TTY", "ru" → "БОЛЬШЕ" / "СУПЕРХОТ TTY"
show_clock = true # показывать часы
show_hint = true # показывать "Press Enter to login"
pam_service = "login" # PAM service (если собрано с --features pam)
auto_start_session = true # автоматически запускать WM после login
# title_color = "#FF2E97" # optional override (default = theme.accent_magenta)
# title_font = "" # optional override (default = general.font)Hot-reload: да.
Список workspace'ов с именами (для отображения в статус-баре). Каждый — отдельный массив.
[[workspaces]]
n = 1
name = "MAIN"
[[workspaces]]
n = 2
name = "WEB"
[[workspaces]]
n = 3
name = "DEV"
[[workspaces]]
n = 4
name = "CHAT"
[[workspaces]]
n = 5
name = "MEDIA"
[[workspaces]]
n = 6
name = "6"
[[workspaces]]
n = 7
name = "7"
[[workspaces]]
n = 8
name = "8"
[[workspaces]]
n = 9
name = "9"
[[workspaces]]
n = 10
name = "MISC"Число workspace'ов — general.workspace_count (по умолчанию 10). [[workspaces]] — метаданные (имена), не количество.
Hot-reload: да (имена обновляются в статус-баре).
Привязка workspaces к конкретным мониторам (как в Hyprland).
[[monitors]]
connector = "eDP-1" # имя коннектора DRM
workspaces = [1, 3, 5, 7, 9] # нечётные ws на этом мониторе
enabled = true # false = отключить
position = "primary" # "primary" / "left-of X" / "right-of X" / "above X" / "below X"
# resolution = [2560, 1440] # опц.: пусто = preferred из EDID
# refresh_rate = 144 # опц.: пусто = default
[[monitors]]
connector = "HDMI-A-1"
workspaces = [2, 4, 6, 8, 10] # чётные ws
enabled = true
position = "right-of eDP-1"Если конфиг пустой — все workspaces на primary monitor.
Имена коннекторов (распространённые):
eDP-1— встроенный экран ноутбукаHDMI-A-1,HDMI-B-1— HDMI выходыDP-1,DP-2— DisplayPortDVI-D-1— DVIVGA-1— VGA
Посмотреть доступные: cat /sys/class/drm/*/status или в логе superhot-tty при старте.
Hot-reload: нет (требует перезапуска — reinit DRM/KMS).
Автоматическое размещение X11 окон по критериям (при CreateNotify).
Все непустые поля match_* должны совпасть (AND). Поле regex = true включает wildcard match (* и ?).
[[window_rules]]
match_class = "firefox" # WM_CLASS (instance)
# match_title = "Mozilla Firefox" # WM_NAME (опц., AND)
# match_app_id = "org.mozilla.firefox" # app_id (опц., AND)
regex = false # true → wildcard match
workspace = 2 # поместить на workspace N
# monitor = "HDMI-A-1" # или на конкретный монитор
size = [80, 80] # 80% ширины, 80% высоты (опц.)
position = [10, 10] # 10% x, 10% y (опц.)
focus = true # сделать сфокусированным
fullscreen = false # открыть в fullscreen
skip_auto_place = false # не размещать автоматическиПримеры:
# Steam → MEDIA (ws 5)
[[window_rules]]
match_class = "Steam"
workspace = 5
focus = true
# Discord → CHAT (ws 4)
[[window_rules]]
match_class = "discord"
workspace = 4
focus = true
# Firefox → WEB (ws 2)
[[window_rules]]
match_class = "firefox"
workspace = 2
# GIMP — большой размер
[[window_rules]]
match_class = "Gimp"
workspace = 5
size = [80, 80]
position = [10, 10]Hot-reload: да (применяется к новым окнам).
Список команд, запускаемых при старте WM (после login), в отдельных потоках.
[[autostart]]
type = "command" # фоновый процесс без UI
cmd = "pipewire"
delay_ms = 0 # задержка перед запуском
[[autostart]]
type = "command"
cmd = "pipewire-pulse"
delay_ms = 500
[[autostart]]
type = "command"
cmd = "wireplumber"
delay_ms = 1000
[[autostart]]
type = "x11" # графическое приложение (DISPLAY=:1)
cmd = "firefox"
args = []
delay_ms = 2000
workspace = 2 # открыть на workspace 2
[[autostart]]
type = "x11"
cmd = "discord"
delay_ms = 3000
workspace = 4
[[autostart]]
type = "terminal" # в нативном терминале (TERM=xterm-256color)
cmd = "htop"
delay_ms = 0
workspace = 1Типы:
command— фоновый процесс (pipewire, wireplumber, и т.д.)x11— графическое приложение (firefox, discord, steam)terminal— запустить команду в нашем нативном терминале (htop, vim, btop)
Hot-reload: нет (применяется только при старте WM).
[launcher]
max_rows = 12 # макс. число строк в списке
x11_display = ":1" # DISPLAY для запуска X11 приложений
terminal_shell = "zsh" # shell для терминальных приложений (Terminal=true)
desktop_paths = [
"/usr/share/applications",
"/usr/local/share/applications",
"~/.local/share/applications",
]
[launcher.custom_entries]
"terminal: bash" = "bash"
"reload config" = "superhot-tty-reload"
"system status" = "neofetch"Custom entries — дополнительные пункты в лаунчере (ключ — отображаемое имя, значение — команда).
Hot-reload: нет (применяется при старте WM).
[popups]
duration_frames = 240 # длительность показа (240 кадров при 60fps = 4 сек)
max_width_pct = 67 # макс. ширина в % от экрана
glitch_border = true # RGB-сдвиг бордюра
# font = "Lat2-Terminus16" # опц. override (default = general.font)Hot-reload: да.
Все биндинги в конфиге. Никаких захардкоженных.
[[keybindings]]
key = "d" # клавиша (a-z, 0-9, Return, Space, Tab, Left/Right/Up/Down, F1-F12, ...)
mods = ["Super"] # модификаторы: Super, Ctrl, Alt, Shift
action = { type = "launcher" }Mods: Super, Ctrl, Alt, Shift — комбинируются как массив. Все модификаторы должны быть нажаты (AND).
Типы actions:
launcher— открыть лаунчерterminal— новый терминалsplit_horizontal,split_vertical— сплит текущего тайлаfocus { dir = "left|right|up|down" }— фокус в направленииmove { dir = "left|right|up|down" }— переместить окноswap { dir = "left|right|up|down" }— swap с соседомresize { dir = "left|right|up|down", delta = 0.05 }— resize сплитаresize_mode— войти/выйти из resize mode (HJKL)workspace { n = 1 }— переключиться на ws Nmove_to_workspace { n = 1 }— переместить окно на ws Nclose— закрыть тайлfullscreen— toggle fullscreencycle_focus— цикл по всем тайламtoggle_layout— toggle layout (заглушка)reload— reload конфига (через ConfigWatcher)quit— выйти из WMspawn { cmd = "...", args = [...] }— запустить фоновый процессspawn_x11 { cmd = "...", args = [...] }— запустить X11 приложение (DISPLAY=:1)spawn_terminal { cmd = "...", args = [...] }— запустить в нативном терминалеpopup_script { cmd = "...", args = [...] }— запустить скрипт, показать stdout в popuppopup { text = "..." }— показать статичный popuptab_next,tab_prev— переключение табов (заглушки)
Примеры:
[[keybindings]]
key = "Return"
mods = ["Super"]
action = { type = "terminal" }
[[keybindings]]
key = "h"
mods = ["Super", "Shift"]
action = { type = "move", dir = "left" }
[[keybindings]]
key = "2"
mods = ["Super"]
action = { type = "workspace", n = 2 }
[[keybindings]]
key = "e"
mods = ["Super"]
action = { type = "spawn_x11", cmd = "xterm", args = [] }
[[keybindings]]
key = "p"
mods = ["Super"]
action = { type = "popup_script", cmd = "echo", args = ["Hello from SuperHot TTY!"] }Hot-reload: да (новые биндинги активны сразу).
[live_reload]
enabled = true # включить inotify watcher
debounce_ms = 250 # задержка перед перечитыванием (защита от множественных событий)При изменении config.toml (через inotify IN_MODIFY/IN_CLOSE_WRITE/IN_MOVED_TO/IN_CREATE) — после debounce WM перечитывает файл и применяет изменения.
Логируется через log::info! что именно изменилось (theme / keybindings / window_rules / animations / ipc / live_reload / general / x11 / monitors).
Поля, требующие перезапуска, логируются как warning.
Hot-reload: да (можно включать/выключать watcher на лету).
Полная настройка glitch-эффектов.
[animations]
# Включение/выключение анимаций
workspace_transition = true # переход между ws
new_window = true # появление нового окна
random_glitch = true # случайные глитчи
# WS transition — три фазы:
ws_transition_ms = 250 # фаза 1: сплошной перебор всего экрана
ws_manifest_ms = 200 # фаза 2: целевой ws проявляется поверх перебора
ws_reveal_ms = 250 # фаза 3: corner-to-corner фиксация
# New window — две фазы:
new_window_fill_ms = 600 # фаза 1: квадрат окна заливается перебором
new_window_reveal_ms = 250 # фаза 2: corner-to-corner фиксация
# Random glitch:
random_glitch_ms = 120 # длительность (короче, чем ws transition)
random_glitch_every_frames = 360 # в среднем раз в N кадров (× glitch_intensity)
# Скорость перебора символов (chars/sec):
chars_per_sec = 60 # для ws transition и new window
random_chars_per_sec = 220 # для random glitch (значительно быстрее)
# Набор символов для перебора:
glitch_use_alpha = true # A-Z (заглавные английские)
glitch_use_blocks = true # ░ ▒ ▓ █ ■ □ ▢ ▣ ▤ ▥ ▦ ▧ ▨ ▩ ▀ ▄ ▌ ▐
glitch_use_digits = false # 0-9
# Цвет символов глитча (hex):
# glitch_color = "#00F0FF" # по умолчанию = theme.accent_cyanПодробнее о фазах workspace transition:
-
Transition (
ws_transition_ms) — все символы экрана (терминальные ячейки, разделители, X11-окна как квадраты █▓) перебираются случайными символами из набора (glitch_use_alpha+glitch_use_blocks+glitch_use_digits). Скорость перебора —chars_per_sec. -
Manifest (
ws_manifest_ms) — поверх перебора постепенно проявляется целевой ws. Ячейки целевого ws, в которых есть символ, заменяют glitch-символ. Ячейки, которых в целевом ws нет (но были в старом) — остаются в glitch (эффект "исчезновения"). Перебор для остальных ячеек продолжается. -
Reveal (
ws_reveal_ms) — diagonal corner-to-corner: от левого верхнего угла к правому нижнему символы фиксируются в финальном состоянии (terminal cells из целевого ws). Ячейка фиксируется если её нормализованное диагональное расстояние(col/(cols-1) + row/(rows-1)) / 2≤ прогрессу reveal.
Hot-reload: да.
[ipc]
enabled = true # включить IPC сервер
# socket_path = "/run/user/1000/superhot-tty.sock" # опц. (пусто = авто)
socket_mode = 0o600 # права на файл сокета (octal)По умолчанию сокет:
$XDG_RUNTIME_DIR/superhot-tty.sock(обычно/run/user/$UID/)/tmp/superhot-tty-$UID.sock(fallback)
Hot-reload: частично (enabled — да, socket_path — требует перезапуска).
См. подробности в IPC сокет.
[x11]
dri3 = true # DRI3 + DMA-BUF (FFI к libxcb-dri3)
display = ":1" # display для Xephyr
screen_size = [1920, 1080] # размер Xephyr screen
xtest_input = true # XTest extension для ввода в X11 окна
hardware_cursor = true # DRM cursor plane (0% CPU)
auto_place_windows = true # авто-place X11 окон по правилам
overlay_planes = true # DRM overlay planes (0% CPU для X11 rendering)Hot-reload: нет (требует перезапуска — reinit Xephyr/DRM).
[audio]
start_pipewire_pulse = true # запускать pipewire + pipewire-pulse при старте
start_wireplumber = true # запускать wireplumber (session manager)
default_volume = 70 # начальная громкость (0-100)Hot-reload: нет (применяется при старте WM).
[portal]
start_portal = true # запускать портал-бэкенд
service_name = "org.freedesktop.impl.portal.desktop.SuperHot" # DBus имя
object_path = "/org/freedesktop/portal/desktop" # DBus путьHot-reload: нет (применяется при старте WM).
[gamepad]
enabled = true # обрабатывать геймпад
steam_passthrough = true # evdev passthrough для Steam Input
stick_sensitivity = 50 # чувствительность стика (1-100)
[gamepad.keymap]
"a" = "Return"
"b" = "Escape"
"x" = "space"
"y" = "Tab"
"dpad_up" = "k"
"dpad_down" = "j"
"dpad_left" = "h"
"dpad_right" = "l"
"start" = "Super"
"back" = "Super"
"left_shoulder" = "bracketleft"
"right_shoulder" = "bracketright"Hot-reload: частично.
| Секция | Поле | Тип | По умолчанию | Hot-reload | Описание |
|---|---|---|---|---|---|
general |
shell |
string | "zsh" |
✅ | shell для терминалов |
general |
font |
string | "Lat2-Terminus16" |
❌ | PSF-шрифт |
general |
font_size |
u32 | 16 |
❌ | размер шрифта |
general |
gap |
i32 | 4 |
✅ | зазор между тайлами |
general |
border |
i32 | 1 |
✅ | толщина бордюра |
general |
outer_padding |
i32 | 4 |
✅ | внешний padding |
general |
status_bar_height |
u32 | 24 |
✅ | высота статус-бара |
general |
framerate |
u32 | 60 |
✅ | целевой FPS |
general |
glitch_intensity |
f32 | 0.15 |
✅ | вероятность random glitch (0..1) |
general |
workspace_count |
u8 | 10 |
❌ | число workspaces |
theme |
(12 colors) | string hex | MCD-палитра | ✅ | цвета интерфейса |
login |
title |
string | "" (auto) |
✅ | заголовок login screen |
login |
subtitle |
string | "" (auto) |
✅ | подзаголовок |
login |
language |
string | "en" |
✅ | "en" / "ru" |
login |
show_clock |
bool | true |
✅ | показывать часы |
login |
show_hint |
bool | true |
✅ | подсказка "Press Enter" |
login |
pam_service |
string | "login" |
✅ | PAM service |
login |
auto_start_session |
bool | true |
✅ | авто-запуск WM |
workspaces |
n |
u8 | — | ✅ | номер ws |
workspaces |
name |
string | — | ✅ | имя ws |
monitors |
connector |
string | — | ❌ | имя коннектора DRM |
monitors |
workspaces |
u8[] | — | ❌ | список ws на мониторе |
monitors |
enabled |
bool | true |
❌ | вкл/выкл |
monitors |
resolution |
(u32,u32) | None |
❌ | разрешение |
monitors |
refresh_rate |
u32 | None |
❌ | частота |
monitors |
position |
string | None |
❌ | позиционирование |
window_rules |
match_class |
string | — | ✅ | WM_CLASS match |
window_rules |
match_title |
string | — | ✅ | WM_NAME match |
window_rules |
match_app_id |
string | — | ✅ | app_id match |
window_rules |
regex |
bool | false |
✅ | wildcard/regex |
window_rules |
workspace |
u8 | None |
✅ | target ws |
window_rules |
monitor |
string | None |
✅ | target monitor |
window_rules |
size |
(u32,u32) | None |
✅ | размер в % |
window_rules |
position |
(u32,u32) | None |
✅ | позиция в % |
window_rules |
focus |
bool | true |
✅ | сделать сфокусированным |
window_rules |
fullscreen |
bool | false |
✅ | открыть в fullscreen |
window_rules |
skip_auto_place |
bool | false |
✅ | не размещать авто |
autostart |
type |
string | — | ❌ | command/x11/terminal |
autostart |
cmd |
string | — | ❌ | команда |
autostart |
args |
string[] | [] |
❌ | аргументы |
autostart |
delay_ms |
u64 | 0 |
❌ | задержка |
autostart |
workspace |
u8 | None |
❌ | target ws |
autostart |
monitor |
string | None |
❌ | target monitor |
launcher |
max_rows |
u32 | 12 |
❌ | макс. строк |
launcher |
x11_display |
string | ":1" |
❌ | DISPLAY |
launcher |
terminal_shell |
string | "zsh" |
❌ | shell для Terminal=true |
launcher |
desktop_paths |
string[] | стандартные | ❌ | пути .desktop |
launcher.custom_entries |
(key,value) | string→string | {} |
❌ | доп. пункты |
popups |
duration_frames |
u32 | 240 |
✅ | длительность показа |
popups |
max_width_pct |
u32 | 67 |
✅ | макс. ширина % |
popups |
glitch_border |
bool | true |
✅ | RGB-сдвиг бордюра |
popups |
font |
string? | None |
✅ | override шрифта |
live_reload |
enabled |
bool | true |
✅ | вкл inotify watcher |
live_reload |
debounce_ms |
u64 | 250 |
✅ | debounce |
animations |
workspace_transition |
bool | true |
✅ | анимация перехода ws |
animations |
new_window |
bool | true |
✅ | анимация нового окна |
animations |
random_glitch |
bool | true |
✅ | случайные глитчи |
animations |
ws_transition_ms |
u32 | 250 |
✅ | фаза 1 ws transition |
animations |
ws_manifest_ms |
u32 | 200 |
✅ | фаза 2 ws transition |
animations |
ws_reveal_ms |
u32 | 250 |
✅ | фаза 3 ws transition |
animations |
new_window_fill_ms |
u32 | 600 |
✅ | фаза 1 new window |
animations |
new_window_reveal_ms |
u32 | 250 |
✅ | фаза 2 new window |
animations |
random_glitch_ms |
u32 | 120 |
✅ | длительность random |
animations |
random_glitch_every_frames |
u32 | 360 |
✅ | частота random |
animations |
chars_per_sec |
u32 | 60 |
✅ | скорость перебора |
animations |
random_chars_per_sec |
u32 | 220 |
✅ | скорость random |
animations |
glitch_use_alpha |
bool | true |
✅ | A-Z в переборе |
animations |
glitch_use_blocks |
bool | true |
✅ | блоки в переборе |
animations |
glitch_use_digits |
bool | false |
✅ | цифры в переборе |
animations |
glitch_color |
string? | None |
✅ | цвет глитча (default accent_cyan) |
ipc |
enabled |
bool | true |
✅ | вкл IPC сервер |
ipc |
socket_path |
string? | None |
❌ | путь сокета |
ipc |
socket_mode |
u32 | 0o600 |
✅ | права сокета |
x11 |
dri3 |
bool | true |
❌ | DRI3 + DMA-BUF |
x11 |
display |
string | ":1" |
❌ | display Xephyr |
x11 |
screen_size |
(u16,u16) | (1920,1080) |
❌ | размер Xephyr |
x11 |
xtest_input |
bool | true |
❌ | XTest extension |
x11 |
hardware_cursor |
bool | true |
❌ | DRM cursor plane |
x11 |
auto_place_windows |
bool | true |
❌ | авто-place X11 |
x11 |
overlay_planes |
bool | true |
❌ | DRM overlay planes |
audio |
start_pipewire_pulse |
bool | true |
❌ | запуск PipeWire |
audio |
start_wireplumber |
bool | true |
❌ | запуск wireplumber |
audio |
default_volume |
u32 | 70 |
❌ | начальная громкость |
portal |
start_portal |
bool | true |
❌ | запуск портала |
portal |
service_name |
string | "...SuperHot" |
❌ | DBus имя |
portal |
object_path |
string | "/org/..." |
❌ | DBus путь |
gamepad |
enabled |
bool | true |
✅ | обработка геймпада |
gamepad |
steam_passthrough |
bool | true |
✅ | evdev passthrough |
gamepad |
stick_sensitivity |
u32 | 50 |
✅ | чувствительность стика |
gamepad.keymap |
(key,value) | string→string | defaults | ✅ | маппинг кнопок |
Все биндинги в конфиге ([[keybindings]]). По умолчанию (см. config/default.toml):
Mod4 = Super/Windows key.
| Hotkey | Действие |
|---|---|
Mod4+D |
Launcher |
Mod4+Enter |
Новый терминал (zsh) |
Mod4+V |
Split vertical |
Mod4+H/J/K/L |
Фокус left/down/up/right |
Mod4+Shift+H/J/K/L |
Переместить окно |
Mod4+Ctrl+H/J/K/L |
Swap с соседом |
Mod4+R |
Resize mode (HJKL) |
Mod4+Alt+H/J/K/L |
Resize split в направлении |
Mod4+1..9 |
Workspace 1..9 |
Mod4+0 |
Workspace 10 |
Mod4+Shift+1..0 |
Переместить окно на workspace 1..10 |
Mod4+Q |
Закрыть тайл |
Mod4+F |
Fullscreen toggle |
Mod4+Space |
Cycle focus |
Mod4+E |
Открыть X11-плитку (xterm) |
Mod4+P |
Popup script (echo Hello) |
Mod4+Ctrl+R |
Reload config |
Mod4+Shift+E |
Quit |
Все биндинги можно переназначить или добавить свои — см. [[keybindings]].
При запуске на tty1, superhot-tty показывает themed login screen:
╔════════════════════╗
║ ║
║ MORE ║ ← configurable title
║ SUPERHOT TTY ║ ← configurable subtitle
║ ║
║ 12:34:56 ║ ← clock (optional)
║ ║
║ Press Enter to login║ ← hint (optional)
║ ║
╚════════════════════╝
После Enter:
- Login: — ввод логина
- Password: — ввод пароля (скрытые символы •)
- PAM аутентификация через service
login(если собрано с--features pam) - Fallback: проверка через
/etc/shadow+crypt(3) - При успехе: переключение на UID/GID пользователя, загрузка user config, запуск WM
- При ошибке: показ сообщения, возврат к Welcome
[login]
title = "MORE" # свой текст (пусто = language default)
subtitle = "SUPERHOT TTY"
language = "en" # или "ru" для "БОЛЬШЕ" / "СУПЕРХОТ TTY"
show_clock = true
show_hint = true
pam_service = "login"
title_color = "#FF2E97" # optional override
# title_font = "Lat2-Terminus16" # optional overrideВ конфиге [[monitors]] — список мониторов с привязкой workspaces:
[[monitors]]
connector = "eDP-1" # встроенный экран ноутбука
workspaces = [1, 3, 5, 7, 9] # нечётные ws на этом мониторе
enabled = true
position = "primary"
[[monitors]]
connector = "HDMI-A-1"
workspaces = [2, 4, 6, 8, 10] # чётные ws на этом мониторе
enabled = true
position = "right-of eDP-1"
resolution = [2560, 1440] # optional
refresh_rate = 144 # optional
[[monitors]]
connector = "DP-1"
workspaces = [1, 2, 3]
resolution = [1920, 1080]
position = "left-of eDP-1"- При
Mod4+1(ws 1) — фокус переходит на eDP-1 (т.к. ws 1 привязан к нему) - При
Mod4+2(ws 2) — фокус переходит на HDMI-A-1 - Layout каждого workspace сохраняется независимо
- Каждый монитор имеет свой CRTC + dumb buffer + page-flip
Имена определяются DRM. Распространённые:
eDP-1— встроенный экран ноутбукаHDMI-A-1,HDMI-B-1— HDMI выходыDP-1,DP-2— DisplayPortDVI-D-1— DVIVGA-1— VGA
Посмотреть доступные: cat /sys/class/drm/*/status или в логе superhot-tty при старте.
[[window_rules]]
match_class = "firefox" # WM_CLASS (instance)
# match_title = "Mozilla Firefox" # WM_NAME (optional, AND)
# match_app_id = "org.mozilla.firefox" # app_id (optional, AND)
regex = false # true → wildcard match (* and ?)
workspace = 2 # поместить на workspace 2
# monitor = "HDMI-A-1" # или на конкретный монитор
size = [80, 80] # 80% ширины, 80% высоты (optional)
position = [10, 10] # 10% x, 10% y (optional)
focus = true # сделать сфокусированным
fullscreen = false # открыть в fullscreen
skip_auto_place = false # не размещать автоматическиSteam games → workspace 5 (MEDIA):
[[window_rules]]
match_class = "Steam"
workspace = 5
focus = trueDiscord → workspace 4 (CHAT):
[[window_rules]]
match_class = "discord"
workspace = 4Firefox → workspace 2 (WEB):
[[window_rules]]
match_class = "firefox"
workspace = 2GIMP — большой размер:
[[window_rules]]
match_class = "Gimp"
workspace = 5
size = [80, 80]
position = [10, 10]- При
CreateNotifyв X11 сервере (например, Steam запустил игру) - Мы получаем
WM_CLASSчерезXGetWindowProperty - Проходим по всем
[[window_rules]]в конфиге - Первое совпавшее правило применяется:
- Переключаемся на указанный workspace (если есть)
- Создаём X11 tile на активном workspace
- Привязываем окно к tile
- Если ни одно правило не совпало — открываем на текущем active ws
Список команд, запускаемых при старте WM (после login):
[[autostart]]
type = "command" # фоновый процесс без UI
cmd = "pipewire"
delay_ms = 0
[[autostart]]
type = "command"
cmd = "pipewire-pulse"
delay_ms = 500
[[autostart]]
type = "x11" # графическое приложение
cmd = "firefox"
args = []
delay_ms = 2000
workspace = 2 # открыть на workspace 2
[[autostart]]
type = "terminal" # в нативном терминале
cmd = "htop"
delay_ms = 0
workspace = 1
[[autostart]]
type = "x11"
cmd = "discord"
delay_ms = 3000
workspace = 4command— фоновый процесс (pipewire, wireplumber, и т.д.)x11— графическое приложение (firefox, discord, steam)terminal— запустить команду в нашем нативном терминале (htop, vim, btop)
Каждая команда запускается в отдельном потоке с указанной задержкой.
Mod4+D открывает launcher в центре экрана:
╔═══════════════════════════════════════╗
║ RUN // superhot launcher ║
╠═══════════════════════════════════════╣
║ > firef ║
╠═══════════════════════════════════════╣
║ ▸ Firefox Web ║
║ Firefox Developer Edition Web ║
║ Firejail Sys ║
╠═══════════════════════════════════════╣
║ ↑↓ navigate Enter run Esc close [3/124] ║
╚═══════════════════════════════════════╝
- Читает
.desktopфайлы из:/usr/share/applications/usr/local/share/applications~/.local/share/applications
- Если
.desktopимеетTerminal=true→ запускаемExecв нашем нативном терминале - Если
Terminal=false→ запускаем как X11 приложение на нашем display:1 - Авто-создаётся X11 tile для графического приложения
[launcher.custom_entries]
"terminal: bash" = "bash"
"reload config" = "superhot-tty-reload"
"system status" = "neofetch"PopupScript action — запускает скрипт и показывает его stdout в MCD-styled popup:
[[keybindings]]
key = "p"
mods = ["Super"]
action = { type = "popup_script", cmd = "echo", args = ["Hello from SuperHot TTY!"] }
[[keybindings]]
key = "s"
mods = ["Super"]
action = { type = "popup_script", cmd = "systemctl", args = ["status", "pipewire"] }
[[keybindings]]
key = "b"
mods = ["Super"]
action = { type = "popup_script", cmd = "neofetch", args = ["--stdout"] }Также можно показывать статичный текст:
[[keybindings]]
key = "h"
mods = ["Super"]
action = { type = "popup", text = "Mod4+D launcher\nMod4+1..0 workspaces\nMod4+Enter terminal" }Popup умеет:
- Multiline ASCII текст
- Glitch border (RGB-сдвиг)
- Corner brackets (MCD style)
- Авто-размер по контенту
- Авто-закрытие через
duration_frames(default 240 = 4 сек)
Inotify-наблюдатель на config.toml (через libc::inotify_add_watch в отдельном потоке).
При изменении файла — debounce (live_reload.debounce_ms, по умолчанию 250 мс), затем перечитывание.
theme.*— пересобираетсяThemeи сразу используется при рендереkeybindings— новые биндинги активны сразуwindow_rules— применяются к новым окнамanimations.*— параметры анимацийipc.*(кромеsocket_path— требует перезапуска)live_reload.*general.glitch_intensity,general.framerate,general.gap/border/outer_padding/status_bar_heightpopups.*
general.font,general.font_size— нужны новая загрузка PSFgeneral.workspace_count— пересоздание структур Workspacesmonitors— reinit DRM/KMSx11.display,x11.screen_size— reinit Xephyrx11.dri3,x11.overlay_planes— reinit DRM planes
В логе (например, journalctl -u superhot-tty@tty1) видно:
INFO config change detected, reloading...
INFO config diff: {"theme": true, "keybindings": false, "window_rules": false, ...}
INFO → theme reloaded
src/config/watcher.rs — ConfigWatcher + ConfigDiff (детектор изменений).
Три типа анимаций, все с corner-to-corner reveal (TL → BR диагональ).
При переключении workspaces (через Mod4+N, IPC workspace N, или window rule):
Фаза 1: Transition (ws_transition_ms, по умолчанию 250 мс)
- Все символы экрана (терминальные ячейки, разделители, X11-окна как квадраты █▓) начинают перебираться случайными символами:
- Заглавные A-Z (если
glitch_use_alpha = true) - Квадраты с разной заливкой: ░ ▒ ▓ █ ■ □ ▢ ▣ ▤ ▥ ▦ ▧ ▨ ▩ ▀ ▄ ▌ ▐ (если
glitch_use_blocks = true) - Опционально цифры 0-9 (
glitch_use_digits)
- Заглавные A-Z (если
- Скорость перебора:
chars_per_sec(по умолчанию 60 chars/sec) - Каждая ячейка имеет свой псевдо-случайный сдвиг фазы, чтобы ячейки менялись не одновременно
Фаза 2: Manifest (ws_manifest_ms, по умолчанию 200 мс)
- Поверх перебора проявляется целевой ws:
- Ячейки целевого ws, в которых есть символ, заменяют glitch-символ (появление)
- Ячейки, которых в целевом ws нет (но были в старом) — остаются в glitch (исчезновение)
- Перебор для остальных ячеек продолжается
- Прогресс — от 0% до 100% за
ws_manifest_ms
Фаза 3: Reveal (ws_reveal_ms, по умолчанию 250 мс)
- Diagonal corner-to-corner: от левого верхнего угла к правому нижнему символы фиксируются в финальном состоянии (terminal cells из целевого ws)
- Ячейка фиксируется если её нормализованное диагональное расстояние
(col/(cols-1) + row/(rows-1)) / 2≤ прогрессу reveal - Создаёт эффект "волны" от TL к BR
При создании нового X11-окна или нативного терминального tile:
Фаза 1: Fill (new_window_fill_ms, по умолчанию 600 мс)
- Квадрат нового окна заливается перебором (фон глитча — тёмный, символы glitch_color)
- Реальное содержимое окна скрыто
Фаза 2: Reveal (new_window_reveal_ms, по умолчанию 250 мс)
- Corner-to-corner внутри rect окна: символы фиксируются, видно реальный терминал/окно
- Тот же diagonal-алгоритм, что и у ws transition
Спонтанный быстрый глитч по случайному под-прямоугольнику экрана:
- Длительность:
random_glitch_ms(по умолчанию 120 мс — короче, чем ws transition) - Частота: в среднем раз в
random_glitch_every_framesкадров (по умолчанию 360), умножается наgeneral.glitch_intensity(0.0..1.0, по умолчанию 0.15)- Формула:
P(glitch this frame) = glitch_intensity / random_glitch_every_frames - При defaults: 0.15 / 360 ≈ 0.00042 на кадр, ~раз в 40 секунд при 60 FPS
- Формула:
- Скорость перебора:
random_chars_per_sec(по умолчанию 220 chars/sec — значительно быстрее, чем у ws/new_window) - Corner-to-corner reveal как и у остальных, но быстрый
- Цвета: чередующиеся glitch_color и accent_magenta (для мигающего эффекта)
[animations]
# glitch_color = "#00F0FF" # default = theme.accent_cyanshtty-msg "glitch"Запускает random glitch немедленно (вероятность 100%).
src/render/glitch.rs:
AnimationManager— менеджер всех активных анимацийActiveAnimation— состояние одной анимации (kind, started, total_duration, snapshots)CharSnapshot— снимок экрана как сетка символов (для ws transition: old + new)snapshot_workspace()— делает снимок текущего workspace (терминалы + X11 как квадраты)random_glitch_char()— случайный символ из набора (A-Z + блоки + опц. цифры)
UNIX-доменный сокет (по умолчанию $XDG_RUNTIME_DIR/superhot-tty.sock или /tmp/superhot-tty-$UID.sock). Протокол: JSON-запросы и JSON-ответы.
{ "type": "command", "cmd": "workspace 2" }
{ "type": "command", "cmd": "workspace next" }
{ "type": "command", "cmd": "workspace prev" }
{ "type": "command", "cmd": "move to workspace 3" }
{ "type": "command", "cmd": "exec firefox" }
{ "type": "command", "cmd": "exec --no-startup-id alacritty" }
{ "type": "command", "cmd": "exec discord -- --gpu-rasterization" }
{ "type": "command", "cmd": "kill" }
{ "type": "command", "cmd": "reload" }
{ "type": "command", "cmd": "restart" }
{ "type": "command", "cmd": "quit" }
{ "type": "command", "cmd": "split horizontal" }
{ "type": "command", "cmd": "split vertical" }
{ "type": "command", "cmd": "focus left" }
{ "type": "command", "cmd": "focus right" }
{ "type": "command", "cmd": "focus up" }
{ "type": "command", "cmd": "focus down" }
{ "type": "command", "cmd": "fullscreen toggle" }
{ "type": "command", "cmd": "layout toggle" }
{ "type": "command", "cmd": "launcher" }
{ "type": "command", "cmd": "glitch" }
{ "type": "get_workspaces" }
{ "type": "get_config" }
{ "type": "get_focused" }
{ "type": "get_version" }{ "status": "ok", "result": "switched to workspace 2" }
{ "status": "ok", "result": "[{\"num\":1,\"name\":\"MAIN\",\"current\":true,\"tiles\":2}, ...]" }
{ "status": "ok", "result": "{\"name\":\"superhot-tty\",\"version\":\"0.5.0\",\"libvterm\":true}" }
{ "status": "error", "error": "unknown command: foo" }
{ "status": "error", "error": "workspace requires argument" }Standalone binary (не зависит от основного crate):
# Команды
shtty-msg "workspace 2"
shtty-msg "workspace next"
shtty-msg "move to workspace 3"
shtty-msg "exec firefox"
shtty-msg "exec --no-startup-id alacritty"
shtty-msg "kill"
shtty-msg "reload"
shtty-msg "split vertical"
shtty-msg "focus left"
shtty-msg "fullscreen toggle"
shtty-msg "launcher"
shtty-msg "glitch"
# Запросы
shtty-msg --get-workspaces
shtty-msg --get-config
shtty-msg --get-focused
shtty-msg --get-version
# Помощь
shtty-msg
shtty-msg --help#!/bin/bash
shtty-msg "workspace next"
sleep 0.3
shtty-msg "exec alacritty"#!/bin/bash
# Получить список workspaces и текущий
WS=$(shtty-msg --get-workspaces | jq -r '.result' | jq '.[] | select(.current==true) | .name')
echo "Workspace: $WS"ipc.socket_mode (по умолчанию 0o600, только владелец). Для разделения между пользователями — создайте группу и поменяйте права.
src/ipc/mod.rs—IpcServer,IpcRequest,IpcResponse,parse_i3_command(),shell_split()src/bin/shtty_msg.rs— standalone CLI binary (без зависимости от основного crate)- IPC сервер запускается в отдельном потоке, главный цикл WM опрашивает
try_recv()каждый кадр
Runtime FFI к libvterm.so.0 через libloading. Если библиотека доступна — VTerm проксирует туда все байты от PTY и синхронизирует grid. Если нет — fallback на расширенный built-in ANSI-парсер.
shtty-msg --get-version
# {"status":"ok","result":"{\"name\":\"superhot-tty\",\"version\":\"0.5.0\",\"libvterm\":true}"}"libvterm":true — используется libvterm, "libvterm":false — fallback built-in парсер.
Или в логе при старте WM:
INFO libvterm backend active (full xterm compatibility)
# или
INFO libvterm not available — using built-in minimal ANSI parser
Arch Linux:
sudo pacman -S libvtermDebian/Ubuntu:
sudo apt install libvterm-devFedora:
sudo dnf install libvterm-develЕсли libvterm недоступна, используется расширенный built-in парсер. Покрывает:
CSI sequences:
H/f— cursor position (CSI n;m H)A/B/C/D— cursor up/down/fwd/backE/F— CNL/CPL (cursor next/prev line)G/d— column/row setJ— erase display (0=cursor-to-end, 1=start-to-cursor, 2=all, 3=scrollback)K— erase line (0/1/2)m— SGR (colors, bold, italic, underline, reverse, ...)r— DECSTBM (scroll region)n— device status report (CSI 6n → cursor position)L/M— insert/delete linesP— delete chars@— insert blanksS/T— scroll up/downs/u— save/restore cursor (ANSI.SYS)h/l— ANSI modes (7=autowrap, 4=insert)
Private modes (CSI ?):
1049— alt screen (xterm)47/1047— alt screen (older variants)25— cursor visibility7— autowrap1— application cursor keys12— cursor blink
ESC sequences:
D— IND (index, down + scroll if needed)E— NEL (next line)M— RI (reverse index)c— RIS (full reset)7/8— DECSC/DECRC (save/restore cursor + attrs)=/>— application/normal keypadP— DCS (Device Control String, игнорируется до ST)\\— ST (String Terminator)
OSC sequences:
0;title/2;title— window title (синхронизируется с заголовком tile)4;N;COLOR— palette set (игнорируется, у нас 16-color палитра)8;params;uri— hyperlink (игнорируется)52;clipboard— clipboard (игнорируется)
SGR (Select Graphic Rendition):
0— reset all attrs1/22— bold on/off3/23— italic on/off4/24— underline on/off7/27— reverse on/off30-37/40-47— 16-color fg/bg38;5;N/48;5;N— 256-color38;2;R;G;B/48;2;R;G;B— truecolor (аппроксимируется в ближайший 16-color)90-97/100-107— bright fg/bg
src/term/libvterm.rs—LibVTermHandle, FFI bindings черезlibloadingsrc/term/vterm.rs—VTermс опциональным libvterm backend- При
VTerm::new(cols, rows)— пытается загрузить libvterm; если успешно, использует её - При
feed()— если libvterm активна, проксирует байты туда и синхронизирует grid - При недоступности — встроенный state machine (Ground/Esc/Csi/CsiPrivate/CsiGt/Osc/Dcs)
Mod4+D→ начните вводить имя программы↑↓навигация,Enterзапуск- Графическое приложение откроется в новой X11 плитке на текущем ws
- Терминальное приложение откроется в нативном терминале
# Из любого терминала внутри superhot-tty:
DISPLAY=:1 firefox
DISPLAY=:1 steam
DISPLAY=:1 discordКогда X11 приложение создаёт окно (CreateNotify):
- Получаем
WM_CLASSиWM_NAME - Ищем matching
[[window_rules]]в конфиге - Применяем правило (workspace, size, position, focus, fullscreen)
- Если правило не найдено — открываем на текущем active ws
Полная реализация через FFI к libxcb-dri3 (динамическая загрузка через libloading):
DRI3QueryVersion— проверка поддержки DRI3 на X-сервереDRI3Open— получение authenticated DRM fd от X-сервераDRI3BuffersFromPixmap(DRI3 1.2+) — получение dma-buf fd с modifiersDRI3BufferFromPixmap(DRI3 1.0) — fallback без modifiers- Автоматический выбор API по версии DRI3
src/x11/dri3.rs — полностью реализован, использует libloading для runtime загрузки libxcb-dri3.so.0.
DRM dedicated cursor plane через DRM_IOCTL_MODE_CURSOR2:
- Узнёт размер курсора через
DRM_CAP_CURSOR_WIDTH/HEIGHT(типично 64×64) - Создаёт dumb buffer ARGB для курсора
- MCD-styled crosshair курсор (неоновый крестик с магента-центром и glow)
move_to(x, y)— только обновляет позицию, 0% CPU, без перерисовки framebuffershow()/hide()— управление видимостьюupdate_image()— смена изображения (для анимации)
src/drm/cursor.rs — HardwareCursor struct.
Overlay planes для X11 окон — 0% CPU rendering:
- При
CreateNotifyX11 окна:CompositeNameWindowPixmap→ pixmapDRI3BuffersFromPixmap→ dma-buf fd
- Импорт dma-buf в DRM:
DRM_IOCTL_PRIME_FD_TO_HANDLE→ GEM handleDRM_IOCTL_MODE_ADDFB2с modifiers → DRM framebuffer
DRM_IOCTL_MODE_SETPLANE— присвоение framebuffer к overlay plane- GPU composites overlay поверх primary scanout на лету
src/drm/planes.rs — OverlayManager с отслеживанием занятых planes, auto-finding free overlay plane per CRTC.
[x11]
dri3 = true # DRI3 + DMA-BUF
hardware_cursor = true # DRM cursor plane
overlay_planes = true # 0% CPU X11 renderingЕсли overlay_planes = false — X11 окна blit'ятся в canvas (CPU). Fallback на случай если GPU не поддерживает достаточно overlay planes.
superhot-tty запускает (если [audio] включён):
pipewire— основной daemonpipewire-pulse— PulseAudio совместимостьwireplumber— session manager
pactl set-sink-volume @DEFAULT_SINK@ 80%
pactl set-sink-mute @DEFAULT_SINK@ toggle
pactl list sinks shortРегистрируется DBus service org.freedesktop.impl.portal.desktop.SuperHot с интерфейсом ScreenCast.
Discord/Slack: Share Screen → выберите "SuperHot" monitor.
OBS: Add Source → ScreenCast (Portal) → выберите "SuperHot".
Steam Input работает через evdev — superhot-tty не вмешивается:
DISPLAY=:1 steamСоберите с --features gamepad-sdl2:
[gamepad.keymap]
"a" = "Return"
"b" = "Escape"
"dpad_up" = "k"
"dpad_down" = "j"
"left_shoulder" = "bracketleft"build-packages.sh генерирует 3 пакета:
./build-packages.sh # все 3 пакета
./build-packages.sh pacman # только Arch
./build-packages.sh deb # только Debian
./build-packages.sh rpm # только FedoraРезультат в target/packages/:
superhot-tty-0.5.0-1-x86_64.pkg.tar.zst(Arch)superhot-tty_0.5.0_amd64.deb(Debian)superhot-tty-0.5.0-1.x86_64.rpm(Fedora)superhot-tty-packages-0.5.0.tar.gz(все 3 в одном архиве)
cargo,rust— для бинарникаmakepkg(Arch) илиcargo-deb(Debian) илиcargo-rpm(Fedora)- Или
fpmкак универсальный fallback
superhot-tty/
├── Cargo.toml # manifest (2 binary: superhot-tty, shtty-msg)
├── build-packages.sh # генерация 3 пакетов
├── README.md
├── LICENSE
├── config/
│ └── default.toml # полный пример конфига со всеми секциями
├── skel/
│ └── zshrc.example # пример .zshrc с MCD-стилем
├── systemd/
│ └── superhot-tty@.service
├── packaging/
│ ├── arch/
│ │ ├── PKGBUILD
│ │ └── superhot-tty.install
│ ├── debian/ # (используется cargo-deb)
│ └── rpm/
│ └── superhot-tty.spec
├── debian/
│ ├── control
│ ├── postinst
│ └── prerm
└── src/
├── main.rs # entry: login → WM flow, IPC handler
├── login/mod.rs # PAM login screen
├── config/
│ ├── mod.rs # TOML config (все секции v0.5)
│ ├── window_rules.rs # window rules engine
│ └── watcher.rs # live-reload inotify watcher (NEW v0.5)
├── launcher/mod.rs # rofi-like launcher (.desktop scanner)
├── drm/
│ ├── kms.rs # DRM/KMS ioctls
│ ├── multi_monitor.rs # multi-monitor backend
│ ├── cursor.rs # hardware DRM cursor plane
│ ├── planes.rs # hardware DRM overlay planes (0% CPU X11)
│ └── fbdev.rs # legacy fallback
├── render/
│ ├── canvas.rs # direct framebuffer canvas
│ ├── font.rs # PSF1/PSF2 font loader
│ ├── text.rs # text renderer
│ └── glitch.rs # MCD-style glitch animations (NEW v0.5)
├── term/
│ ├── pty.rs # PTY (openpty + fork/execvp)
│ ├── vterm.rs # built-in ANSI parser (extended v0.5)
│ └── libvterm.rs # libvterm FFI bindings (NEW v0.5)
├── layout/
│ ├── mod.rs # BSP/i3 tile tree
│ └── workspaces.rs # 10 workspaces
├── input/
│ ├── keyboard.rs # evdev keyboard
│ ├── mouse.rs # evdev mouse + software cursor
│ └── gamepad.rs # evdev/SDL2 gamepad
├── x11/
│ ├── compositor.rs # Xephyr + Composite + Damage
│ ├── dri3.rs # DRI3/DMA-BUF FFI (libloading libxcb-dri3)
│ └── dmabuf.rs # DMA-BUF helpers
├── ipc/
│ └── mod.rs # i3-msg-compatible IPC socket (NEW v0.5)
├── bin/
│ └── shtty_msg.rs # standalone IPC CLI binary (NEW v0.5)
├── audio/mod.rs # PipeWire launcher
├── portal/mod.rs # xdg-desktop-portal backend
└── ui/
├── theme.rs # MCD color palette (16 ANSI colors)
├── popup.rs # MCD-styled popups
└── mod.rs
- ✅ Live reload конфигурации — inotify watcher на
config.toml, debounce, hot-apply theme/keybindings/window_rules/animations/ipc, warn для перезапускаемых полей —src/config/watcher.rs - ✅ Анимации перехода между workspaces (glitch MCD-style) — три фазы: transition (перебор) → manifest (проявление нового ws) → reveal (corner-to-corner фиксация). Плюс new-window анимация и random glitch —
src/render/glitch.rs - ✅ IPC сокет (i3-msg-совместимый протокол) — UNIX-domain сокет, JSON-команды, CLI
shtty-msg—src/ipc/mod.rs,src/bin/shtty_msg.rs - ✅ Полная xterm совместимость (libvterm) — runtime FFI к
libvterm.so.0черезlibloading, fallback на расширенный built-in парсер (CSI/OSC/DCS, SGR truecolor, DEC modes, save/restore cursor, DECSC/DECRC) —src/term/libvterm.rs,src/term/vterm.rs
- ✅ Полная DRI3/DMA-BUF реализация (FFI к xcb-dri3) —
src/x11/dri3.rs - ✅ Hardware DRM cursor plane —
src/drm/cursor.rs - ✅ Hardware DRM overlay planes (0% CPU для X11) —
src/drm/planes.rs
- ✅ Login screen (PAM)
- ✅ Multi-monitor с per-monitor workspace binding
- ✅ 10 workspaces (Mod4+1..0)
- ✅ Window rules engine
- ✅ Autostart
- ✅ Launcher: Terminal=true → нативный терминал
- ✅ Popups из скриптов
- ✅ 3 пакета (pacman/.deb/.rpm)
- ✅ Config в XDG-пути
- ✅ Initial superhot-tty: tile tree, DRM/KMS direct, MCD theme
A: Ctrl+Alt+F2 — стандартный getty. Ctrl+Alt+F1 — обратно в superhot-tty.
A: Проверьте:
/etc/pam.d/loginсуществует- В логе:
journalctl -u superhot-tty@tty1 | grep -i pam - Для отладки можно временно отключить PAM в конфиге (не рекомендуется)
A: Проверьте:
- Конфиг
[[monitors]]— правильные имена коннекторов cat /sys/class/drm/*/status— какие коннекторы connected- В логе superhot-tty при старте: "found N connectors, M connected"
A:
- Проверьте
WM_CLASSчерезxprop WM_CLASS(в Xephyr) match_class— case-insensitive contains- Если нужно точное совпадение —
regex = trueи используйте wildcard
A: Steam Input требует evdev. Проверьте что пользователь в группе input:
groups $USER
sudo usermod -aG input $USERA: Проверьте:
[live_reload] enabled = trueв конфиге- Файл, который вы редактируете, — тот, что загрузился (см. лог:
loaded config from ...) live_reload.debounce_msне слишком большой- В логе:
config change detected, reloading...
A:
[ipc] enabled = true- Проверьте путь сокета:
shtty-msg(без аргументов показывает путь) - В логе:
IPC socket listening at ... - Проверьте права:
ls -la $XDG_RUNTIME_DIR/superhot-tty.sock
A: Уменьшите:
animations.chars_per_sec(по умолчанию 60 — попробуйте 30)animations.ws_transition_ms/ws_manifest_ms/ws_reveal_ms- Выключите random glitch:
animations.random_glitch = false - Уменьшите
general.glitch_intensity(0.0 = выключено)
A: Проверьте:
ldconfig -p | grep vterm— установлена ли библиотекаshtty-msg --get-version—"libvterm":true/false- В логе:
libvterm backend activeилиlibvterm not available - Установите:
sudo pacman -S libvterm/sudo apt install libvterm-dev/sudo dnf install libvterm-devel
sudo systemctl disable superhot-tty@tty1
sudo systemctl enable getty@tty1
sudo systemctl daemon-reload
sudo rebootA:
[animations]
glitch_color = "#FF00FF" # любой hexA:
[animations]
workspace_transition = false
new_window = false
random_glitch = falseA: Нет. superhot-tty — это замена agetty, работает напрямую с DRM/KMS (без X server на основном экране). X11 используется только через Xephyr для совместимости с X-приложениями.
# Systemd логи superhot-tty
journalctl -u superhot-tty@tty1 -f
# Логи текущей сессии
journalctl -u superhot-tty@tty1 --since "1 hour ago"
# Фильтр по уровню
journalctl -u superhot-tty@tty1 -p err# Проверить DRM устройства
ls -la /dev/dri/
cat /sys/class/drm/*/status
# Проверить коннекторы
cat /sys/class/drm/card0-*/status
# Проверить Xephyr
DISPLAY=:1 xdpyinfo | head
# Проверить IPC сокет
ls -la $XDG_RUNTIME_DIR/superhot-tty.sock
shtty-msg --get-version
# Проверить libvterm
ldconfig -p | grep vterm| Симптом | Причина | Решение |
|---|---|---|
| Чёрный экран после reboot | DRM не получил master | Проверить лог: journalctl -u superhot-tty@tty1 |
| Login не работает | PAM не настроен | Установить libpam0g-dev, собрать с --features pam |
| Окна X11 не появляются | Xvfb не запущен | Проверить: pgrep Xvfb |
| Нет звука | PipeWire не стартовал | systemctl --user status pipewire |
| Скриншот не работает | Portal не зарегистрирован | Проверить: dbus-send --session --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames |
| Glitch-анимации не работают | Выключены в конфиге | Проверить [animations] секцию |
| IPC не отвечает | Сокет не создан | Проверить [ipc] enabled = true и логи |
| Live reload не работает | Watcher выключен | Проверить [live_reload] enabled = true |
| Терминал глючит с цветами | libvterm недоступна | Установить libvterm |
Package freetype2 not found при сборке |
Отсутствует freetype2 system library | Arch: sudo pacman -S freetype2 Debian: sudo apt install libfreetype6-dev Fedora: sudo dnf install freetype-devel |
| Русский/Unicode текст рендерится как '?' | Шрифт не найден или нет Unicode coverage | Установить TTF шрифт: sudo pacman -S ttf-dejavu (Arch). Проверить лог: ищется TTF через fc-match |
| X11 окна не получают клавиатурный ввод | XTest extension недоступен | Проверить лог на "XTest extension NOT available". Xvfb должен поддерживать XTest (стандартная сборка xorg-server-xvfb поддерживает) |
| X11 окна не закрываются (Super+Q) | Приложение не обрабатывает WM_DELETE_WINDOW | WM отправляет WM_DELETE_WINDOW, ждёт 200мс, затем force destroy. Если окно всё ещё не закрывается — проверить лог на ошибки close_window |
MIT License. См. LICENSE.