5.6 KiB
Fox Desktop — Design Spec
Datum: 2026-05-11
Status: Genehmigt
Überblick
Fox Desktop ist eine native Mac-App (Electron), die als dünne Hülle um die bestehende Laravel-HUD-App (fox.pxo.at/hud) fungiert. Electron fügt native Mac-Fähigkeiten hinzu, ohne das HUD neu zu schreiben.
Architektur
Mac OS
├── Tray Icon (Menu Bar)
├── BrowserWindow (Overlay, fullscreen, always-on-top)
│ └── lädt https://fox.pxo.at/hud
│ └── preload.js injiziert window.foxBridge
├── Global Shortcut: Cmd+Shift+F
└── Python Subprocess: openwakeword ("hey_jarvis")
└── stdout "WAKE" → IPC → showHud()
Der Electron-Main-Process hat keine eigene WebSocket-Verbindung zu Reverb. Der WebSocket-Kanal gehört der HUD-Seite selbst. Electron ist reiner Plattform-Layer.
Prinzipien
- Pure Shell: Electron kapselt, erweitert nicht die App-Logik
- Bridge ist optional:
window.foxBridgewird nur in Electron injiziert; das HUD funktioniert im normalen Browser unverändert weiter - Kein Vite Build: Es gibt kein eigenes Frontend — nur Electron-Module und Python-Script
- Kein electron-builder vorerst — erst nach stabilem Dev-Setup
Dateien
| Datei | Aufgabe |
|---|---|
package.json |
Electron-App-Konfiguration, npm-Scripts |
electron/main.js |
App-Lifecycle, IPC-Handler, globaler Shortcut |
electron/hud.js |
BrowserWindow erstellen, show/hide mit Transition |
electron/tray.js |
Menu Bar Icon (Template Image) + Kontextmenü |
electron/wakeword.js |
Python-Subprocess starten, Auto-Restart bei Absturz |
electron/mac-agent.js |
AppleScript-Ausführung via osascript |
electron/preload.js |
window.foxBridge in HUD-Seite injizieren |
python/wakeword.py |
OpenWakeWord Loop, schreibt "WAKE" auf stdout |
assets/fox-tray.png |
16×16 Menu Bar Icon (Template Image) |
Datenflüsse
HUD öffnen (Wakeword)
"hey jarvis" gesprochen
→ python/wakeword.py erkennt Wakeword
→ stdout: "WAKE\n"
→ electron/wakeword.js liest stdout
→ IPC intern → showHud()
→ BrowserWindow.show() + focus()
→ webContents.send('hud-show')
→ HUD CSS-Transition startet
HUD öffnen (Tastaturkürzel / Tray)
Cmd+Shift+F gedrückt ODER Tray-Icon geklickt
→ main.js globalShortcut / tray.on('click')
→ showHud()
Mac-Befehl aus HUD
HUD JavaScript: await window.foxBridge.macCommand('spotify_play')
→ preload.js: ipcRenderer.invoke('mac-command', 'spotify_play')
→ main.js IPC Handler
→ electron/mac-agent.js: executeMacCommand('spotify_play')
→ osascript: tell application "Spotify" to play
→ Rückgabewert { success: true, output: '' } → HUD
HUD schließen
ESC im HUD ODER foxBridge.hideHud() ODER Tray-Menü "Verstecken"
→ ipcRenderer.send('hide-hud')
→ main.js → hideHud()
→ webContents.send('hud-hide') ← CSS-Transition startet
→ setTimeout 600ms → BrowserWindow.hide()
BrowserWindow Konfiguration
{
width: screenWidth,
height: screenHeight,
x: 0, y: 0,
frame: false,
transparent: true,
alwaysOnTop: true,
show: false,
skipTaskbar: true,
hasShadow: false,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false,
webSecurity: false, // Remote URL + preload injection
allowRunningInsecureContent: true,
}
}
setAlwaysOnTop(true, 'screen-saver') und setVisibleOnAllWorkspaces(true) nach dem Erstellen.
window.foxBridge API
window.foxBridge = {
sendMessage(text), // Text an Fox Laravel via IPC
hideHud(), // HUD verstecken
macCommand(cmd), // AppleScript-Befehl ausführen (async, gibt Result zurück)
onFoxAction(callback), // Fox-Aktionen empfangen
onHudShow(callback), // HUD-Show-Event
onHudHide(callback), // HUD-Hide-Event
onStartListening(callback), // Mikrofon-Start-Signal
onPlayAudio(callback), // Audio-URL zum Abspielen
}
Mac-Agent Befehle
Vordefinierte Shortcuts (z.B. spotify_play, mail_open, volume_up) sowie generische Formen:
script:<applescript>— direktes AppleScriptopen:<url>— URL im Standardbrowser öffnenapp:<name>— Mac-App öffnensave:<json>— Datei auf Desktop schreiben
Wakeword (OpenWakeWord)
- Python 3,
openwakeword,pyaudio,numpy,tflite-runtime - Eingebautes Modell:
hey_jarvis(kein API-Key, kein Training nötig) - Electron spawnt
python3 python/wakeword.pyals Child-Process - Auto-Restart nach Absturz (2s Delay)
- Später: eigenes "hey fox" Modell trainierbar
Laravel HUD — Anpassungsstellen
Diese 3 optionalen Punkte müssen in fox-hud.blade.php / HUD-JavaScript hinzugefügt werden:
-
ESC schließt HUD:
document.addEventListener('keydown', (e) => { if (e.key === 'Escape') window.foxBridge?.hideHud(); }); -
Mac-Aktionen in
onAction():if (payload.action === 'spotify_play') { await window.foxBridge?.macCommand('spotify_play'); return; } // ... weitere Mac-Aktionen -
Nachricht senden (optional, wenn direkt ohne Livewire):
window.foxBridge?.sendMessage(text);
Deployment
- Dev:
npm start(Electron lädt fox.pxo.at/hud direkt) - LaunchAgent
~/Library/LaunchAgents/at.pxo.fox.plistfür Auto-Start beim Login electron-builderfür DMG-Build — später
Abhängigkeiten
npm:
electron^28axios^1.6 (für sendMessage POST)
Python:
openwakewordpyaudionumpytflite-runtime