add docs, protocol, plugins, README, CHANGELOG
This commit is contained in:
parent
1d2209bfac
commit
f262da222b
44 changed files with 9269 additions and 0 deletions
19
docs/04-clients/README.md
Normal file
19
docs/04-clients/README.md
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Clients
|
||||
|
||||
VNOX is a native-only platform. There is no web client and none is planned.
|
||||
|
||||
## Why no web client
|
||||
|
||||
- WebRTC adds latency overhead incompatible with VNOX's voice latency targets
|
||||
- WASM + wgpu in browser is not a viable egui deployment target today
|
||||
- Electron is explicitly rejected (it's what we're building against)
|
||||
- A browser tab is not the right environment for a persistent voice client
|
||||
|
||||
The desktop client is a real native binary. It starts fast, uses minimal memory,
|
||||
and has direct access to audio hardware without browser sandboxing.
|
||||
|
||||
## Clients
|
||||
|
||||
- [desktop.md](desktop.md) — primary client, Windows / macOS / Linux
|
||||
- [mobile.md](mobile.md) — Phase 3, stack TBD
|
||||
- [overlay.md](overlay.md) — in-game HUD, Phase 2
|
||||
400
docs/04-clients/design-system.md
Normal file
400
docs/04-clients/design-system.md
Normal file
|
|
@ -0,0 +1,400 @@
|
|||
# VNOX Client — Design System
|
||||
|
||||
> Based on Hi-Fi Minimalism v2.0
|
||||
> Adapted for: native desktop voice/chat client (Rust + egui + wgpu)
|
||||
|
||||
---
|
||||
|
||||
## Philosophy
|
||||
|
||||
VNOX UI должен ощущаться как инструмент, а не социальная сеть.
|
||||
|
||||
```
|
||||
calm · focused · fast · warm · precise
|
||||
```
|
||||
|
||||
Не:
|
||||
```
|
||||
gamer RGB · Discord clone · neon cyberpunk · glassmorphism · corporate SaaS
|
||||
```
|
||||
|
||||
> The client is infrastructure. The UI is just the control surface.
|
||||
|
||||
---
|
||||
|
||||
## Color Tokens
|
||||
|
||||
```css
|
||||
/* Backgrounds — layered, never pure black */
|
||||
--bg-base: #0d0d0d; /* root, titlebar */
|
||||
--bg-surface: #151515; /* panels, sidebars (was #111111 — lifted for panel contrast) */
|
||||
--bg-elevated: #1d1d1d; /* inputs, cards (was #141414 — lifted for depth) */
|
||||
--bg-interactive: #2a2a2a; /* hover targets, dropdowns */
|
||||
|
||||
/* Borders — lifted significantly for visual hierarchy */
|
||||
--border-subtle: #1c1c1c; /* was #171717 */
|
||||
--border-default: #262626; /* was #1e1e1e — now actually visible */
|
||||
--border-strong: #2e2e2e;
|
||||
--border-accent: rgba(255, 107, 53, 0.20);
|
||||
|
||||
/* Accent — warm orange */
|
||||
--accent: #ff6b35;
|
||||
--accent-hover: #ff844f;
|
||||
--accent-active: #e85d04;
|
||||
--accent-10: rgba(255, 107, 53, 0.08);
|
||||
--accent-20: rgba(255, 107, 53, 0.15);
|
||||
|
||||
/* Text — warm, never pure white */
|
||||
--text-primary: #f4c89a; /* main content (added) */
|
||||
--text-secondary: #c88b5a; /* names, labels */
|
||||
--text-muted: #8a6a52; /* secondary info */
|
||||
--text-dim: #6a4a2a; /* hints, timestamps */
|
||||
--text-ghost: #5a422c; /* section labels, separators (was #3d2e20 — lifted) */
|
||||
--text-invisible: #443222; /* near-invisible, decorative (was #2d1e12 — lifted) */
|
||||
|
||||
/* Semantic */
|
||||
--success: #7cb87a; /* online, connected, low latency */
|
||||
--success-muted: rgba(124, 184, 122, 0.10);
|
||||
--warning: #e6a230; /* ping indicator, unread */
|
||||
--warning-muted: rgba(230, 162, 48, 0.10);
|
||||
--error: #d9604a; /* muted mic (when needed), errors */
|
||||
--error-muted: rgba(217, 96, 74, 0.10);
|
||||
--info: #6a9ecf; /* second user accent color */
|
||||
--info-muted: rgba(106, 158, 207, 0.10);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Typography
|
||||
|
||||
Клиент использует **только monospace**. Это намеренно — усиливает ощущение инструмента.
|
||||
|
||||
```
|
||||
Primary font: IBM Plex Mono
|
||||
Fallback: Fira Code, Geist Mono, monospace
|
||||
```
|
||||
|
||||
### Scale (клиент-специфичный, компактный)
|
||||
|
||||
| Role | Size | Weight | Color |
|
||||
|------|------|--------|-------|
|
||||
| Section label | 10px | 400 | `--text-ghost` |
|
||||
| Timestamp, ID | 9px | 400 | `--text-invisible` |
|
||||
| Status, badge | 9px | 500 | semantic |
|
||||
| Channel name | 12px | 400 | `--text-ghost` → `--text-secondary` |
|
||||
| Message text | 11px | 400 | `--text-muted` |
|
||||
| Username | 11px | 600 | varies per user |
|
||||
| Node name | 13px | 600 | `--text-secondary` |
|
||||
| Settings title | 13px | 600 | `--text-secondary` |
|
||||
| Wordmark VNOX | 11px | 600 | letter-spacing: 0.2em |
|
||||
| Panel title | 11px | 400 | `--text-secondary` |
|
||||
| Dashboard heading | 14px | 600 | `--text-secondary` |
|
||||
|
||||
Letter spacing для section labels: `0.10–0.12em`, text-transform: uppercase.
|
||||
|
||||
---
|
||||
|
||||
## Layout
|
||||
|
||||
### Title bar (34px)
|
||||
|
||||
- Background: `--bg-strip` (`theme::BG_STRIP`); **без отдельной painter-linии** под всю ширину — переход «titlebar ↔ контент» только за счёт контраста `--bg-strip` vs `--bg-base`. Раньше 1px `hline` воспринимался как случайная полоска «под логотипом» из-за состыковки с левым rail.
|
||||
- Сетка из **трёх равных колонок**:
|
||||
- **левая** — **`[ prefs ]`** + **`VNOX`** (wordmark `--text-primary`, слева направо после prefs);
|
||||
- **центр** — статус ноды: **`●`** + **`NODE: …`** (`OFFLINE` / `CONNECTING` / имя ноды), **по центру средней колонки** (= визуальный центр окна);
|
||||
- **правая** — **transport‑подсказка** справа: `transport: idle` · `transport: connecting…` · `transport: quic/v1`.
|
||||
- Вход в настройки: **`[ prefs ]`** — явная консольная кнопка (без нестабильных Unicode‑иконок); при открытых настройках тот же текст, цвет **accent**. Дубль: кнопка **open prefs** в нижней левой колонке, **только пока offline**.
|
||||
- Нативный заголовок ОС (**taskbar / список окон**) — короткий **`Vnox`**, чтобы не дублировать тот же wordmark **`VNOX`** внутри клиента.
|
||||
|
||||
### Структура окна
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ [prefs] VNOX │ ● NODE: OFFLINE │ transport: idle │
|
||||
│ (нет линии 1px на всю ширину под панелью) │
|
||||
├──────────────────────────────────────────────────────┤
|
||||
│ rail │ channels (208px) │ main content │
|
||||
│ (52px) │ │ │
|
||||
│ SERVERS │ node / status │ connect or chat │
|
||||
│ [AB] │ channel sections │ │
|
||||
│ [+] │ ─────────────── │ │
|
||||
│ │ identity + voice UI │ │
|
||||
└─────────┴─────────────────────┴─────────────────────┘
|
||||
```
|
||||
|
||||
### Node rail (bookmark strip, 52px)
|
||||
|
||||
Узкая колонка **закладок серверов** (не «Discord‑кругляши»):
|
||||
|
||||
- Ширина **52px**, фон `--bg-strip`, как верхний titlebar для визуальной связности.
|
||||
- Заголовок колонки: **SERVERS** (8px, `--text-ghost`, центрируется по ширине rail).
|
||||
- Плитки **30×30px**, скругление 5px, **строго центрируются** по горизонтали (без случайной короткой линии‑разделителя посередине — она давала эффект «криво» в узком rail).
|
||||
- **Idle** (нет активной закладки): рамка 1px `--border-faint`, подпись `···` во внутреннем поле, tooltip объясняет «подключайся через Connect».
|
||||
- **Активная нода**: 2 символа аббревиатуры, `--accent` левый акцент 2px внутри плитки, `--accent-10` фон.
|
||||
- **«+»**: только одна вторичная плита внизу; tooltip — «bookmark позже».
|
||||
|
||||
### Node switcher (legacy note)
|
||||
|
||||
Исторически описывался как 40px rail с линией перед `+`; в текущем клиенте заменено на блок **Node rail** выше.
|
||||
|
||||
### Channel list (208px)
|
||||
|
||||
- Node info (верх): имя ноды 12px semibold + `lnex://nc.<short_id>` 9px `--text-ghost` при коннекте; офлайн — одна строка **not connected**
|
||||
- Section labels: 9px uppercase, `--text-ghost`, letter-spacing 0.12em
|
||||
- Channel item: 4px 12px padding, gap 6px (icon + name)
|
||||
- Default: `--text-ghost`
|
||||
- Hover: `--text-dim` (без background)
|
||||
- Active: `--text-secondary` + левая полоска 2px `--accent` + `--accent-10` bg
|
||||
- Voice users под каналом: indent 26px, 10px, `--success` для говорящих, `--text-ghost` для muted
|
||||
|
||||
### Bottom-left identity bar
|
||||
|
||||
```
|
||||
[ open prefs ] (только пока offline)
|
||||
|
||||
— voice ~ channel 00:42
|
||||
[x] microphone [x] hear others
|
||||
|
||||
[YU] you
|
||||
a1b2…9f0e (pubkey hex, middle-truncated)
|
||||
```
|
||||
|
||||
- **Не показывать** фиктивный RTT (например «12ms»), если нет реального измерения.
|
||||
- **Не дублировать** протокольную строку вида `LNEx v1 · udp` под ником — перегружает и налезает на аватар/текст; протокол раскрывается в Connect / docs.
|
||||
- Настройки **не** прячем в ряд мелких иконок у ника: основной вход — **`[ prefs ]`** в title bar; офлайн — компактная кнопка **open prefs**.
|
||||
- В голосе: чекбоксы **microphone** / **hear others** (без эмодзи/символов, которые на части шрифтов дают «квадратики»).
|
||||
- Avatar: 32×32px, radius 6px, disabled button (только визуал), self — `--accent-10` + border.
|
||||
|
||||
### Main area
|
||||
|
||||
- Channel header: 36px, border-bottom `--border-subtle`
|
||||
- Messages: padding 12px 14px, gap между группами 8px
|
||||
- Input: `#general ›` prefix + cursor blink + hint text
|
||||
|
||||
---
|
||||
|
||||
## Components
|
||||
|
||||
### Toggle
|
||||
|
||||
```
|
||||
Off: width 30px, height 16px, bg --bg-elevated, border --border-default
|
||||
thumb: 10px circle, bg #2d2d2d, left 2px
|
||||
|
||||
On: bg --accent-10, border --border-accent
|
||||
thumb: bg --accent, left 16px, glow rgba(255,107,53,0.4)
|
||||
|
||||
Transition: 150ms ease
|
||||
```
|
||||
|
||||
### Badge
|
||||
|
||||
```css
|
||||
/* Protocol / transport */
|
||||
.badge-lnex { color: #ff844f; border: 1px solid rgba(255,107,53,0.2); bg: rgba(255,107,53,0.08) }
|
||||
.badge-udp { color: #6a9ecf; border: 1px solid rgba(106,158,207,0.2); bg: rgba(106,158,207,0.10) }
|
||||
.badge-tcp { color: #e6a230; border: 1px solid rgba(230,162,48,0.2); bg: rgba(230,162,48,0.10) }
|
||||
.badge-enc { color: #7cb87a; border: 1px solid rgba(124,184,122,0.2); bg: rgba(124,184,122,0.10) }
|
||||
|
||||
/* Размер: 9px, padding 1px 6px, border-radius 3px */
|
||||
```
|
||||
|
||||
### Select / Input
|
||||
|
||||
```
|
||||
bg: --bg-elevated (#111)
|
||||
border: 1px solid --border-default
|
||||
border-radius: 5px
|
||||
font: 10px IBM Plex Mono
|
||||
color: --text-muted
|
||||
|
||||
focus:
|
||||
border-color: --border-accent
|
||||
```
|
||||
|
||||
### Slider
|
||||
|
||||
```
|
||||
track: 2px height, --border-default
|
||||
thumb: 10px circle, --accent, subtle glow
|
||||
|
||||
::-webkit-slider-thumb {
|
||||
background: var(--accent);
|
||||
box-shadow: 0 0 6px rgba(255, 107, 53, 0.3);
|
||||
}
|
||||
```
|
||||
|
||||
### User avatar
|
||||
|
||||
```
|
||||
Size variants:
|
||||
sm — 24×24px, border-radius 5px (identity bar)
|
||||
md — 26×26px, border-radius 6px (member list)
|
||||
lg — 36×36px, border-radius 8px (identity card in settings)
|
||||
|
||||
Default: bg --bg-elevated, border --border-default, color --text-muted
|
||||
Self: bg --accent-10, border --border-accent, color --accent
|
||||
Other: custom per-user, based on their seed color (--info, --text-secondary, etc.)
|
||||
```
|
||||
|
||||
### System message / separator
|
||||
|
||||
```
|
||||
font-size: 9–10px
|
||||
color: --text-ghost
|
||||
display: flex + ::before/::after lines in --border-subtle
|
||||
|
||||
Examples:
|
||||
● connected · nightcore.lnex · LNEx v1
|
||||
— today —
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Active / Indicator Language
|
||||
|
||||
Везде используется одна и та же визуальная метафора для "активно":
|
||||
|
||||
```
|
||||
Левая вертикальная полоска 2px --accent
|
||||
+ subtle --accent-10 background
|
||||
```
|
||||
|
||||
Это применяется к:
|
||||
- активной ноде в switcher
|
||||
- активному каналу в списке
|
||||
- активному разделу в настройках
|
||||
|
||||
Не используется background без полоски, и не используется полоска без подсветки.
|
||||
|
||||
---
|
||||
|
||||
## Voice Indicators
|
||||
|
||||
```
|
||||
Говорит: dot 5px #7cb87a, box-shadow 0 0 6px rgba(124,184,122,0.45)
|
||||
Muted: icon ti-microphone-off, color --text-ghost
|
||||
В канале: dot или icon перед именем, indent 26px от иконки канала
|
||||
```
|
||||
|
||||
В voice badge (активный call):
|
||||
```
|
||||
dot 5px --accent, box-shadow 0 0 6px rgba(255,107,53,0.5)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Settings Layout
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ titlebar — [prefs]* │ VNOX │ … │
|
||||
│ открыть настройки: клик [prefs]; обратный маршрут │
|
||||
│ тот же, пока приложение показывает settings screen │
|
||||
├──────────────────────────────────────────────────────┤
|
||||
│ nav (160px) │ content │
|
||||
│ │ │
|
||||
│ account │ [page title] │
|
||||
│ identity │ [subtitle] │
|
||||
│ │ │
|
||||
│ audio │ [group label] ────────────────── │
|
||||
│ voice ◄ │ row: label + control │
|
||||
│ output │ row: label + control │
|
||||
│ │ │
|
||||
│ network │ [group label] ────────────────── │
|
||||
│ network │ ... │
|
||||
│ overlay │ │
|
||||
│ │ │
|
||||
│ app │ │
|
||||
│ appearance │ │
|
||||
│ keybinds │ │
|
||||
│ plugins │ │
|
||||
│ │ │
|
||||
│ debug │ │
|
||||
│ advanced │ │
|
||||
└─────────────────┴────────────────────────────────────┘
|
||||
```
|
||||
|
||||
- Nav width: 160px, bg `--bg-base`
|
||||
- Section labels в nav: 9px uppercase, `--text-ghost`
|
||||
- Nav item: 11px, default `--text-ghost`, hover `--text-dim`, active `--text-secondary` + левая полоска
|
||||
- Content padding: 16px 20px
|
||||
- Group label: 9px uppercase, `--text-ghost`, border-bottom `--border-subtle`, margin-bottom 8px
|
||||
- Row: `display:flex; justify-content:space-between; align-items:center; padding:6px 0`
|
||||
- Row separator: `border-top: 1px solid #0f0f0f` (почти невидимый, только ритм)
|
||||
|
||||
---
|
||||
|
||||
## Motion
|
||||
|
||||
```
|
||||
duration-instant: 80ms — toggle, dot
|
||||
duration-fast: 120ms — hover color change
|
||||
duration-base: 150ms — toggle thumb, panel transitions
|
||||
duration-slow: 250ms — page switch in settings
|
||||
|
||||
ease: cubic-bezier(0.0, 0.0, 0.2, 1) — ease-out для всего
|
||||
```
|
||||
|
||||
Никаких scale transforms на hover. Только:
|
||||
- `color` transition
|
||||
- `background` transition
|
||||
- `border-color` transition
|
||||
- `box-shadow` для glow (subtle)
|
||||
- `left` для toggle thumb
|
||||
|
||||
---
|
||||
|
||||
## Anti-patterns (клиент-специфично)
|
||||
|
||||
| ❌ Не делать | ✅ Делать |
|
||||
|-------------|---------|
|
||||
| Отдельная 1px линия на всю ширину только под titlebar (стек с rail = «случайная полоска») | Отделение только контрастом `--bg-strip` / `--bg-base`; линии локально там, где группируешь контент |
|
||||
| Круглые аватары | Квадратные с border-radius 5–8px |
|
||||
| Sidebar с серверами как у Discord (72px, круглые) | Узкий rail **52px**, квадратные плитки **30×30**, аббревиатура, заголовок **SERVERS** |
|
||||
| Панель участников справа как у Discord | Нет отдельной панели, участники — в боковом списке |
|
||||
| Neon glow на элементах | Subtle glow max 0.18 opacity |
|
||||
| Pure black backgrounds | Минимум #0a0a0a |
|
||||
| Pure white text | Максимум #f4c89a |
|
||||
| RGB accent | Один тёплый accent #ff6b35 |
|
||||
| Rounded pill buttons everywhere | border-radius 4–6px, pill только для badge |
|
||||
| Жирные разделители | 1px --border-subtle, почти невидимые |
|
||||
|
||||
---
|
||||
|
||||
## Noise Texture
|
||||
|
||||
Лёгкий шум поверх всего интерфейса — добавляет аналоговое ощущение.
|
||||
|
||||
```css
|
||||
.root::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
background-image: url("data:image/svg+xml,..."); /* SVG feTurbulence */
|
||||
opacity: 0.025; /* максимум 0.03, иначе грязно */
|
||||
pointer-events: none;
|
||||
z-index: 999;
|
||||
}
|
||||
```
|
||||
|
||||
В egui/wgpu: реализуется как overlay texture на финальном render pass.
|
||||
|
||||
---
|
||||
|
||||
## Seed Colors для пользователей
|
||||
|
||||
У каждого пользователя свой цвет ника, детерминированный от pubkey.
|
||||
|
||||
Палитра допустимых цветов (тёплая, совместимая с системой):
|
||||
|
||||
```
|
||||
#c88b5a — warm amber (default / self)
|
||||
#6a9ecf — steel blue
|
||||
#7cb87a — warm green
|
||||
#c49a6c — sand
|
||||
#b07cc6 — muted purple
|
||||
#d4876a — terracotta
|
||||
```
|
||||
|
||||
Не используются: яркие/neon цвета, холодные синие, чистый белый/красный.
|
||||
195
docs/04-clients/desktop.md
Normal file
195
docs/04-clients/desktop.md
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
# Desktop Client
|
||||
|
||||
The primary VNOX client. Native, fast, lightweight.
|
||||
|
||||
## Stack
|
||||
|
||||
| Layer | Technology |
|
||||
|-------|-----------|
|
||||
| Language | Rust |
|
||||
| UI framework | egui |
|
||||
| Renderer | wgpu |
|
||||
| Audio capture/playback | cpal |
|
||||
| Audio processing | rodio |
|
||||
| Voice codec | opus (libopus bindings) |
|
||||
| Networking | quinn (QUIC/UDP), tokio |
|
||||
| Serialization | prost (Protobuf) |
|
||||
|
||||
### Why egui
|
||||
|
||||
- immediate mode UI: simple to reason about, no complex state trees
|
||||
- runs on wgpu: same renderer as the rest of the GPU pipeline
|
||||
- truly cross-platform: one codebase, same behavior on Windows/macOS/Linux
|
||||
- no runtime dependencies: ships as a single binary
|
||||
|
||||
### Why wgpu
|
||||
|
||||
- modern GPU API (Vulkan / Metal / DX12 / WebGPU backend)
|
||||
- future-proof for overlay rendering and spatial audio visualizations
|
||||
- native on all tier-1 platforms
|
||||
|
||||
---
|
||||
|
||||
## Platforms
|
||||
|
||||
| Platform | Status |
|
||||
|----------|--------|
|
||||
| Linux x86_64 | Phase 1 |
|
||||
| Windows x86_64 | Phase 1 |
|
||||
| macOS (Apple Silicon) | Phase 1 |
|
||||
| macOS (Intel) | Phase 1 |
|
||||
| Linux ARM64 | Phase 2 |
|
||||
|
||||
---
|
||||
|
||||
## Audio pipeline
|
||||
|
||||
```
|
||||
cpal (capture)
|
||||
│ PCM f32 48000Hz
|
||||
▼
|
||||
RNNoise (noise suppression)
|
||||
▼
|
||||
AEC (echo cancellation)
|
||||
▼
|
||||
VAD (voice activity detection)
|
||||
▼
|
||||
opus encode
|
||||
▼
|
||||
LNEx UDP packet → voice-node
|
||||
```
|
||||
|
||||
Playback:
|
||||
|
||||
```
|
||||
LNEx UDP packet ← voice-node
|
||||
▼
|
||||
jitter buffer
|
||||
▼
|
||||
opus decode
|
||||
▼
|
||||
rodio (playback)
|
||||
▼
|
||||
cpal (output device)
|
||||
```
|
||||
|
||||
Audio device selection is configurable in Settings → Voice and Settings → Audio Output.
|
||||
|
||||
---
|
||||
|
||||
## Design system
|
||||
|
||||
The client follows the VNOX Hi-Fi Minimalism design system.
|
||||
Full specification: `docs/04-clients/design-system.md`
|
||||
|
||||
Key decisions:
|
||||
- monospace font throughout (IBM Plex Mono)
|
||||
- warm dark palette (`#0d0d0d` base, `#ff6b35` accent)
|
||||
- no round server icons — square with abbreviation, 40px sidebar
|
||||
- latency indicator bottom-left, next to identity
|
||||
- no separate member list panel — voice users shown inline in channel list
|
||||
|
||||
---
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────┐
|
||||
│ titlebar: dots · VNOX wordmark · connected node │
|
||||
├────────┬──────────────────┬───────────────────────── │
|
||||
│ nodes │ channels │ main (chat / voice) │
|
||||
│ 40px │ 190px │ flex │
|
||||
│ │ │ │
|
||||
│ NC ◄ │ nightcore.lnex │ #general │
|
||||
│ DV · │ ───────────── │ ───────────────────── │
|
||||
│ GG │ # general ◄ │ messages │
|
||||
│ VD │ # dev-talk │ │
|
||||
│ + │ # plugins │ │
|
||||
│ │ │ │
|
||||
│ │ ~ lobby │ │
|
||||
│ │ · raven │ ───────────────────── │
|
||||
│ │ · 0xmist │ #general › [input] │
|
||||
│ │ 🔇 lurker_7 │ │
|
||||
│ │ ~ gaming │ │
|
||||
│ │ ───────────── │ │
|
||||
│ │ ● 12ms lnex v1 │ │
|
||||
│ │ [YU] you 🎤 🎧 ⚙ │ │
|
||||
└────────┴──────────────────┴──────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Settings
|
||||
|
||||
Settings are stored locally. No settings are synced to the server.
|
||||
|
||||
### Voice
|
||||
- input device
|
||||
- input volume
|
||||
- noise suppression (RNNoise on/off)
|
||||
- echo cancellation (on/off)
|
||||
- activation mode: push-to-talk / voice activity / always on
|
||||
- VAD threshold
|
||||
- Opus bitrate (8–128k)
|
||||
- Opus frame interval (10 / 20 / 40ms)
|
||||
|
||||
### Audio output
|
||||
- output device
|
||||
- output volume
|
||||
- jitter buffer size
|
||||
- adaptive jitter buffer (on/off)
|
||||
|
||||
### Network
|
||||
- relay address
|
||||
- auto relay selection
|
||||
- UDP port
|
||||
- force relay only (disable direct)
|
||||
|
||||
### Identity
|
||||
- view pubkey
|
||||
- export keypair
|
||||
- seed phrase backup
|
||||
- rotate keypair
|
||||
|
||||
### Appearance
|
||||
- color scheme
|
||||
- UI scale
|
||||
- font
|
||||
|
||||
### Keybinds
|
||||
- push-to-talk key
|
||||
- mute toggle
|
||||
- deafen toggle
|
||||
- overlay toggle
|
||||
|
||||
### Plugins
|
||||
- installed plugin list
|
||||
- enable / disable per plugin
|
||||
|
||||
### Advanced (debug)
|
||||
- log level
|
||||
- log voice packets
|
||||
- show packet stats
|
||||
- disable encryption (dev only)
|
||||
|
||||
---
|
||||
|
||||
## Building from source
|
||||
|
||||
```bash
|
||||
# Prerequisites: Rust stable, system audio libs
|
||||
|
||||
# Linux (Ubuntu/Debian)
|
||||
apt install libasound2-dev libopus-dev
|
||||
|
||||
# macOS
|
||||
brew install opus
|
||||
|
||||
# Build
|
||||
git clone https://github.com/vnox/vnox
|
||||
cd vnox/client
|
||||
cargo build --release
|
||||
|
||||
# Binary
|
||||
./target/release/vnox-client
|
||||
```
|
||||
71
docs/04-clients/mobile.md
Normal file
71
docs/04-clients/mobile.md
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
# Mobile Client
|
||||
|
||||
> Status: Phase 3 — not yet started.
|
||||
> This document tracks intentions and open questions.
|
||||
|
||||
---
|
||||
|
||||
## Goal
|
||||
|
||||
A native mobile client for iOS and Android.
|
||||
Not a PWA. Not a wrapper around the desktop client.
|
||||
|
||||
## Open questions
|
||||
|
||||
### UI framework
|
||||
|
||||
egui on mobile is not practical today — touch input support is limited,
|
||||
and the immediate mode model doesn't map well to mobile interaction patterns.
|
||||
|
||||
Candidates under consideration:
|
||||
|
||||
| Option | Notes |
|
||||
|--------|-------|
|
||||
| Rust + custom egui mobile backend | Most consistent with desktop codebase, significant work |
|
||||
| Rust + Makepad | Rust-native UI designed for mobile, less mature |
|
||||
| Rust core + Flutter UI | Dart for UI, Rust for audio/networking via FFI |
|
||||
| Rust core + Swift/Kotlin UI | Platform-native UI, Rust for the important parts |
|
||||
|
||||
Decision: deferred to Phase 3.
|
||||
|
||||
### Audio
|
||||
|
||||
Mobile audio APIs are significantly more constrained than desktop:
|
||||
|
||||
- iOS: AVAudioSession, strict background audio rules
|
||||
- Android: AAudio / OpenSL ES, varying latency by device
|
||||
|
||||
opus encoding is the same. cpal has partial mobile support.
|
||||
The audio pipeline will need platform-specific tuning.
|
||||
|
||||
### Background operation
|
||||
|
||||
Voice calls in the background require OS-level permission and
|
||||
platform-specific handling (CallKit on iOS, ConnectionService on Android).
|
||||
This is non-trivial and will be a significant portion of mobile dev effort.
|
||||
|
||||
---
|
||||
|
||||
## What mobile must support (MVP)
|
||||
|
||||
- connect to a VNOX node
|
||||
- join voice channels
|
||||
- push-to-talk
|
||||
- text chat
|
||||
- identity (same keypair as desktop, importable via QR or keyfile)
|
||||
|
||||
## What mobile explicitly will not do
|
||||
|
||||
- host a node (gateway or voice-node)
|
||||
- run plugins
|
||||
- game overlay
|
||||
|
||||
---
|
||||
|
||||
## Timeline
|
||||
|
||||
Mobile client is Phase 3, after:
|
||||
- Phase 1: desktop client + server MVP
|
||||
- Phase 2: overlay, permissions, friend system
|
||||
|
||||
Estimated start: after Phase 2 is stable.
|
||||
106
docs/04-clients/overlay.md
Normal file
106
docs/04-clients/overlay.md
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
# Overlay
|
||||
|
||||
> Status: Phase 2 — design draft.
|
||||
|
||||
The VNOX overlay renders a HUD on top of running games and applications,
|
||||
showing voice channel state without alt-tabbing.
|
||||
|
||||
---
|
||||
|
||||
## What it shows
|
||||
|
||||
- who is currently speaking (avatar / nickname + audio indicator)
|
||||
- your own mic state (active / muted / push-to-talk held)
|
||||
- current channel name
|
||||
- latency (RTT to node)
|
||||
- hotkey state hints
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
The overlay is a separate process that communicates with the main VNOX client
|
||||
via a local IPC socket (Unix socket / named pipe).
|
||||
|
||||
The client pushes state updates to the overlay:
|
||||
- user speaking events (`VOICE_STATE`)
|
||||
- channel changes
|
||||
- mute state changes
|
||||
|
||||
The overlay renders on top of other applications.
|
||||
|
||||
### Rendering approach
|
||||
|
||||
| Platform | Method |
|
||||
|----------|--------|
|
||||
| Windows | DirectX overlay injection or transparent top-level window |
|
||||
| Linux (X11) | Shaped transparent window, always-on-top |
|
||||
| Linux (Wayland) | Layer shell protocol (wlr-layer-shell) |
|
||||
| macOS | CGWindow overlay |
|
||||
|
||||
Implementation complexity varies significantly by platform.
|
||||
Windows DX injection is the most reliable for full-screen games.
|
||||
|
||||
---
|
||||
|
||||
## Game integrations
|
||||
|
||||
For games that support it, the overlay can receive additional data:
|
||||
|
||||
### Positional voice (Phase 4)
|
||||
|
||||
Games that expose player position data can send it to VNOX,
|
||||
enabling positional audio — players hear each other based on
|
||||
in-game distance and direction.
|
||||
|
||||
Integration methods:
|
||||
|
||||
| Game / Engine | Method |
|
||||
|---------------|--------|
|
||||
| Minecraft | Fabric/Forge mod that sends position via local socket |
|
||||
| Source Engine | Client plugin / VScript |
|
||||
| Unreal Engine | Plugin exposing position to named pipe |
|
||||
| Unity | SDK that writes position to shared memory |
|
||||
|
||||
Protocol for positional data is TBD (Phase 4 design).
|
||||
|
||||
### Speaking indicators in-game
|
||||
|
||||
Some games support custom HUD elements. Where possible, the overlay
|
||||
will render directly within the game's UI rather than as an external window.
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
```toml
|
||||
[overlay]
|
||||
enabled = true
|
||||
|
||||
# Overlay position on screen
|
||||
position = "top-right" # top-left | top-right | bottom-left | bottom-right
|
||||
|
||||
# Opacity (0.0–1.0)
|
||||
opacity = 0.85
|
||||
|
||||
# Show latency
|
||||
show_latency = false
|
||||
|
||||
# Hotkey to toggle overlay visibility
|
||||
toggle_hotkey = "ctrl+shift+o"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Hotkeys
|
||||
|
||||
All hotkeys are global (work even when VNOX window is not focused).
|
||||
|
||||
| Action | Default |
|
||||
|--------|---------|
|
||||
| Push-to-talk | `mouse4` |
|
||||
| Mute toggle | `ctrl+m` |
|
||||
| Deafen toggle | `ctrl+d` |
|
||||
| Toggle overlay | `ctrl+shift+o` |
|
||||
|
||||
Configurable in Settings → Keybinds.
|
||||
Loading…
Add table
Add a link
Reference in a new issue