OmniPanel-go is a lightweight, open-source application designed to bridge the gap between your PC and any touch device on your local network. Create custom Multi-Function Displays (MFDs) for any gameβturning tablets, phones, or old laptops into dedicated cockpit hardware.
Many existing solutions are proprietary, require accounts, or are too bloated. OmniPanel-go was built to be:
- Simple & Lightweight: No account required. No cloud dependencies. Single Go binary with minimal runtime requirements.
- Open & Flexible: Designed for the community to build, share, and maintain their own designs.
- Key Features
- Architecture
- Configuration
- Using the Editor
- Creating Custom Blocks
- Command Blocks
- Speech Commands
- Data Bus
- API Reference
- Installation Guide
- CI/CD Pipeline
- Roadmap
- Contributing
- User Manual
- Tutorials (Developers)
- Local Hosting: Host your own designs directly on your network.
- Fast Input Detection: Instant communication between touch events and virtual joysticks.
- 3-Finger Swipe Navigation: Switch between panels instantly with a three-finger swipe gesture on touch devices.
- Extreme Customization: Drag and drop blocks your dream cockpit. Advanced users can even create their own blocks using HTML and CSS.
- Command Blocks: Execute shell commands or HTTP requests directly from your panel with adjustable parameters.
- Speech Commands: Control your panel with your voice. Supports offline STT (Vosk with grammar-constrained recognition for high accuracy) and cloud APIs (llama-cpp-server/OpenAI-compatible). Push-to-talk or wake word activation.
- Media Player Control: Display and control MPRIS media players (Spotify, VLC, Firefox) on Linux desktops. Auto-discovers players via D-Bus, shows cover art, title, artist, progress, and playback controls.
- RSS Feed Display: Subscribe to multiple RSS/Atom feeds and display live entries on your panel. Server-side polling avoids CORS, per-client "new entry" highlighting, and click-to-open URLs on the host browser.
- Real-Time Data Bus: Push any data via HTTP or WebSocket and display it live on your panel with the
data_displayblock. - Privacy Focused: No accounts, no cloud, no data tracking.
- Single Binary: Written in Go. Linux builds are fully static. Windows requires
vJoyInterface.dllfor joystick support. Speech features require the Vosk shared library or an external llama-cpp-server.
OmniPanel-go v3 is a Go application that serves as:
| Component | Description |
|---|---|
| HTTP Server | Fiber-based server serving all UI and static assets |
| WebSocket | Real-time communication on /ws for button/slider/joystick/keyboard events + binary audio frames |
| Virtual Joystick | Linux: uinput ioctl (pure Go, no CGO) Β· Windows: vJoy driver (CGO, requires vJoyInterface.dll) |
| Virtual Mouse | Linux: uinput ioctl (pure Go, no CGO) Β· Windows: SendInput API (CGO) |
| Virtual Keyboard | Linux: uinput ioctl (pure Go, no CGO) Β· Windows: SendInput API (CGO) |
| Speech Engine | Vosk (offline, CGO, requires libvosk shared library) or llama-cpp-server (HTTP, no CGO) |
| MPRIS Watcher | Linux D-Bus session bus monitoring for media players (Spotify, VLC, Firefox). Auto-discovers players, polls state, publishes to DataBus |
| RSS Feed Manager | Server-side RSS/Atom feed polling with per-client seen-entry tracking. Pushes updates via WebSocket, opens URLs on host browser on click |
| Host Recording | Uses miniaudio-go (CGO) for host microphone capture |
| Start Page | Served at / β panel list, editor link, host controls, and live connection log |
| Panel Client | Served at /panel?name=X β the MFD display shown on your touch device |
| Panel Editor | Served at /editor β drag-and-drop workspace for building panels |
omnipanel-go/
βββ config.json # Server configuration
βββ static/ # HTML, JS, CSS for client, editor, and start page
βββ user/
β βββ blocks/ # Block templates (.html files, one per block type)
β βββ themes/ # Theme CSS files (default.css, star_citizen.css, etc.)
β βββ assets/ # Images and other assets
β βββ panels/ # Saved panel layouts (.json files)
β βββ speech_commands.json # Voice command definitions
βββ user/speech-models/ # Downloaded Vosk models (auto-created)
βββ omnipanel-go # The compiled binary
omnipanel-go/
βββ main.go
βββ go.mod
βββ go.sum
βββ internal/
βββ config/ # Configuration loading and path discovery
βββ logger/ # Structured logging (color, text, JSON)
βββ state/ # Application state with broadcast channels
βββ devices/ # Virtual input device managers
β βββ virtual_input.go # Platform-agnostic interfaces and managers
β βββ linux.go # Linux uinput joystick (+build linux)
β βββ mousepad_linux.go # Linux uinput mouse (+build linux)
β βββ keyboard_linux.go # Linux uinput keyboard (+build linux)
β βββ windows.go # Windows vJoy joystick (+build windows)
β βββ mousepad_windows.go # Windows SendInput mouse (+build windows)
β βββ keyboard_windows.go # Windows SendInput keyboard (+build windows)
β βββ stub.go # No-op stub for unsupported platforms
βββ routes/ # HTTP route handlers (Fiber)
βββ websocket/ # WebSocket message handling
βββ commands/ # Shell and HTTP command execution
βββ speech/ # Speech recognition and command execution
β βββ speech.go # SpeechManager, STTEngine interface
β βββ vosk.go # Offline Vosk STT backend (+build)
β βββ llama.go # llama-cpp-server HTTP client
β βββ matcher.go # Phrase matching + allowlist
β βββ recorder.go # Host microphone recording (malgo)
β βββ decoder.go # Audio format conversion (pion/opus)
β βββ download.go # Vosk model auto-download
βββ mpris/ # MPRIS D-Bus media player monitoring (Linux only)
β βββ mpris.go # Watcher: D-Bus connection, player discovery, state polling, DataBus publishing
βββ rssfeed/ # RSS/Atom feed polling and per-client update delivery
β βββ rssfeed.go # Manager: feed parsing (gofeed), polling, per-client seen tracking, broadcast callback
β βββ openurl_linux.go # Linux: xdg-open for host URL opening
β βββ openurl_windows.go # Windows: start command for host URL opening
β βββ openurl_stub.go # Stub for unsupported platforms
βββ databus/ # Real-time data distribution system
βββ databus.go # Shared thread-safe store
βββ collect_linux.go # Linux collectors (/proc, Statfs)
βββ collect_windows.go # Windows collectors (GetDiskFreeSpaceExW)
βββ collect_stub.go # No-op for unsupported platforms
Edit config.json to change server settings:
{
"port": 3000,
"numJoysticks": 5,
"speech": {
"enabled": false,
"recording_location": "client",
"trigger_mode": "push-to-talk",
"wake_word": "omnipanel-go",
"stt_engine": "vosk",
"vosk_model_path": "",
"vosk_runtime_url": "",
"llama_cpp_url": "http://localhost:8080",
"llama_cpp_api_key": "",
"llama_cpp_api_mode": "transcriptions",
"llama_cpp_model": "",
"llama_cpp_prompt": "",
"tts_enabled": true,
"speech_allowlist": []
},
"mpris": {
"enabled": false,
"poll_interval": 1000
}
}| Field | Type | Default | Description |
|---|---|---|---|
port |
number | 3000 |
HTTP/WebSocket port |
numJoysticks |
number | 5 |
Number of virtual joysticks to create |
Logging is configured via command-line flag or environment variable (not in config.json):
| Flag | Env Var | Values | Default |
|---|---|---|---|
--log-format |
LOG_FORMAT |
color, text, json |
color |
./omnipanel-go --log-format=json # JSON output for log aggregation
LOG_FORMAT=color ./omnipanel-go # Colored terminal output (default)| Field | Type | Default | Description |
|---|---|---|---|
speech.enabled |
boolean | false |
Enable speech recognition |
speech.recording_location |
string | "client" |
Where to record audio: "client" (browser) or "host" (server microphone) |
speech.trigger_mode |
string | "push-to-talk" |
Activation mode: "push-to-talk" or "wake-word" |
speech.wake_word |
string | "omnipanel-go" |
Wake word phrase for continuous listening mode |
speech.wake_word_listen_sec |
number | 8 |
Seconds to listen for speech after wake word detection (host mode only) |
speech.stt_engine |
string | "vosk" |
STT backend: "vosk" (offline) or "llama-cpp" (HTTP API) |
speech.vosk_model_path |
string | "" |
Path to Vosk model (auto-downloaded if empty) |
speech.vosk_runtime_url |
string | "" |
Windows-only Vosk runtime ZIP URL override. Empty uses built-in fallback URL |
speech.llama_cpp_url |
string | "http://localhost:8080" |
llama-cpp-server endpoint |
speech.llama_cpp_api_key |
string | "" |
API key for llama-cpp-server |
speech.llama_cpp_api_mode |
string | "transcriptions" |
API mode: "transcriptions" (Whisper-compatible) or "chat" (multimodal) |
speech.llama_cpp_model |
string | "" |
Model name for chat mode (e.g., "gemma-3-4b") |
speech.llama_cpp_prompt |
string | "" |
System prompt for chat mode |
speech.tts_enabled |
boolean | true |
Enable text-to-speech confirmations |
speech.speech_allowlist |
array | [] |
Allowed command patterns (empty = all allowed). Supports wildcards: "set * to *" |
The OmniPanel-go editor is a live, "What You See Is What You Get" workspace. It allows you to build and preview your cockpit layout in real-time.
- Layout Management: Drag the move handle (β©) to reposition blocks. Use the bottom-right resize handle to scale elements to fit your screen.
- Block Configuration: Click the gear icon (β) on any block to open its specific settings. Here you can map virtual joystick buttons, adjust colors, or change labels.
- Duplication: Once created a block of your liking use the duplication icon (β§) in the block hierarchy to make a copy of the original, allowing faster panel creation.
Access the editor at http://<your-ip>:3000/editor.
OmniPanel-go is designed to be modular. If you can write basic HTML and CSS, you can build a custom block that the app will recognize immediately.
The app automatically scans the following directory on startup and adds any valid .html files to your library:
user/blocks/
Place your .html files directly in this folder (no subdirectories needed). Each file defines one block type.
To create a new block, place an .html file (e.g., toggle_switch.html) in user/blocks/. A standard block consists of a special <settings> tag that tells the editor which options to show, and HTML with settings-<key> placeholders:
<settings
joystick="0" type-joystick="number" min-joystick="0" max-joystick="9"
button="0" type-button="number" min-button="0" max-button="15"
my_label="default text" type-my_label="text"
some_number="6" type-some_number="number" min-some_number="0" max-some_number="10"
nice_color="#00ff00ff" type-nice_color="color"
></settings>
<div class="my-custom-button" style="--border: settings-some_number ; --color: settings-nice_color ;">
<button virtual-joystick="settings-joystick" emulate-button="settings-button">
settings_my_label
</button>
</div>Note: Block files should NOT contain <style> tags. Styling is provided by theme CSS files in user/themes/. The editor and client load the appropriate theme CSS dynamically and scope all selectors to the block's DOM element ID, preventing conflicts between blocks using different themes.
Interactive elements: Use virtual-joystick and emulate-button attributes on <div> or <button> elements to connect them to the virtual joystick system. The framework automatically handles press/release events and toggles the active CSS class on state change. Add toggle-mode="toggle" for toggle behavior (state persists and signal matches position); default is momentary mode (100ms press/release pulse, visual state still persists).
Icon + text layout: Built-in button blocks (button.html, command_block.html, sequence_button.html) share a common structure using .btn-content, .btn-icon, and .btn-label classes. The initButtonLayout() function in client.js configures icon display and text positioning automatically. Custom blocks can use these same classes to get icon+text support:
<button virtual-joystick="settings-joystick" emulate-button="settings-button">
<div class="btn-content layout-image-text text-bottom">
<img class="btn-icon" data-icon-url="settings-icon_url" alt="" />
<span class="btn-label">settings-label</span>
</div>
</button>Supported layouts: image-only, text-only, image-text with text positions: top, bottom, left, right.
OmniPanel-go ships with four built-in themes stored in user/themes/:
| Theme | CSS File | Style |
|---|---|---|
| Default | user/themes/default.css |
Clean, minimal, system fonts |
| Star Citizen | user/themes/star_citizen.css |
Sci-fi, angled corners, cyan glow, Rajdhani font |
| KDE Breeze | user/themes/kde_breeze.css |
Flat KDE Plasma Dark, solid colors, Breeze blue accent, Noto Sans |
| Windows 11 | user/themes/windows_11.css |
Flat surfaces, Windows accent #0078D4, Segoe UI |
Each theme provides CSS for all built-in block types. You can set a panel-level default theme in the editor's workspace settings, and override it per block in the Properties panel.
You don't need to touch any configuration files. Simply:
- Drop your
.htmlfile into theuser/blocks/folder. - Restart or refresh the OmniPanel-go host app.
- Your new block will appear in the library, ready to be dragged onto your workspace.
OmniPanel-go includes pre-built panels for controlling your desktop environment:
| Panel | File | Description |
|---|---|---|
| KDE Desktop | user/panels/KDE Desktop.json |
Control KDE Plasma: lock screen, screenshots, volume, window management, power |
| Windows Desktop | user/panels/Windows Desktop.json |
Control Windows 11: lock screen, snipping tool, volume, snap windows, power |
Both panels use their respective theme (KDE Breeze / Windows 11) set as the panel-level default theme.
Command blocks let you execute shell commands or HTTP requests directly from your panel. They support adjustable parameters that are substituted into the command at execution time, with visual feedback and output display.
Command blocks are a new block type that bridges your panel with the host system. When clicked, they:
- Read current parameter values from inline controls
- Substitute parameters into the command string
- Execute the command on the host
- Display success/error feedback and output
Command blocks use the same HTML template system as other blocks, with special settings for command configuration:
<settings
command_type="shell" type-command_type="select" options-command_type="shell,http"
command="echo Hello {name}" type-command="textarea"
http_method="GET" type-http_method="select" options-http_method="GET,POST,PUT,DELETE,PATCH"
http_url="http://localhost:8080/api" type-http_url="text"
http_body="" type-http_body="textarea"
label="Execute" type-label="text"
hold_repeat="false" type-hold_repeat="toggle"
hold_interval="200" type-hold_interval="number" min-hold_interval="50"
param_name="World" type-param_name="text"
></settings>| Setting | Type | Description |
|---|---|---|
command_type |
select (shell, http) |
Execution mode |
command |
textarea |
Shell command to execute (for shell mode) |
http_method |
select |
HTTP method (GET, POST, PUT, DELETE, PATCH) |
http_url |
text |
Target URL (for http mode) |
http_body |
textarea |
Request body (for POST/PUT/PATCH) |
label |
text |
Button label |
hold_repeat |
toggle |
Enable repeat-while-held behavior |
hold_interval |
number |
Milliseconds between repeats when held |
Parameters are managed dynamically through the Parameters section in the properties panel. Click "+ Add Parameter" to create new parameters. Each parameter is stored with the param_ prefix in settings and appears as an inline control above the button in the panel.
| Setting Pattern | Description |
|---|---|
param_<name>="value" |
Default value for parameter <name> |
type-param_<name>="number" |
Numeric input with optional min/max |
type-param_<name>="text" |
Free-form text input |
type-param_<name>="toggle" |
Checkbox (true/false) |
Parameters are substituted into commands using {name} syntax:
<!-- Settings (added via properties panel) -->
param_count="5" type-param_count="number"
param_message="hello" type-param_message="text"
<!-- Command -->
command="echo Count: {count}, Message: {message}"Shell Mode:
Executes commands via sh -c. Supports pipes, redirections, and shell features.
command_type: shell
command: ls -la {path} | grep {pattern}
param_path: "."
param_pattern: ".json"
HTTP Mode: Sends HTTP requests using the configured method, URL, and body. Parameters are substituted into both URL and body.
command_type: http
http_method: POST
http_url: https://api.example.com/data?id={id}
http_body: {"name": "{name}", "value": {value}}
param_id: "123"
param_name: "test"
param_value: "42"
When hold_repeat is enabled, the command executes repeatedly while the button is held down, at intervals specified by hold_interval (in milliseconds). Useful for continuous actions like volume control or repeated API polling.
- Executing: Button glows with active color during execution
- Success: Brief green border flash
- Error: Red border flash
- Output: Toast notification at bottom of screen showing command output (stdout/response body). Tap to dismiss. Auto-dismisses after 5 seconds.
Simple echo with parameter:
command: echo "Hello {name}!"
param_name: "World"
List directory contents:
command: ls -la {path}
param_path: "."
HTTP GET with query param:
command_type: http
http_method: GET
http_url: https://httpbin.org/get?query={search}
param_search: "test"
HTTP POST with JSON body:
command_type: http
http_method: POST
http_url: https://httpbin.org/post
http_body: {"message": "{msg}", "timestamp": "{ts}"}
param_msg: "Hello"
param_ts: "2024-01-01"
Hold-to-repeat counter:
command: echo "Repeat #{count}"
hold_repeat: true
hold_interval: 150
param_count: "1"
The push_to_talk block provides a dedicated button for voice recording on your panel. Press and hold to start recording, release to stop and process speech.
<settings
label="Push to Talk" type-label="text"
font_size="14" type-font_size="number" min-font_size="1"
width="80%" type-width="percentage" min-width="10" max-width="100"
height="80%" type-height="percentage" min-height="10" max-height="100"
border_radius="8" type-border_radius="number" min-border_radius="0" max-border_radius="100"
button_color="#2a3a4aff" type-button_color="color"
button_color_active="#1ccad8ff" type-button_color_active="color"
label_color="#8ba4b8ff" type-label_color="color"
icon_color="#1ccad8ff" type-icon_color="color"
></settings>| Setting | Type | Description |
|---|---|---|
label |
text |
Button label text |
font_size |
number |
Base font size for responsive scaling |
width |
percentage |
Button width relative to block |
height |
percentage |
Button height relative to block |
border_radius |
number |
Border radius in pixels |
button_color |
color |
Default button background color |
button_color_active |
color |
Background color while recording |
label_color |
color |
Label text color |
icon_color |
color |
Microphone icon color |
- Press and hold: Starts recording audio (client or host, based on
recording_locationconfig) - Release: Stops recording and processes speech
- Visual feedback: Button changes to
button_color_activewhile recording - Host wake-word mode: The block is disabled when
trigger_modeis"wake-word"andrecording_locationis"host", since the server handles continuous listening automatically
Speech commands let you control your panel with your voice. Hold the microphone button on your panel, speak a command, and OmniPanel-go transcribes and executes it.
Speech commands support two recording locations:
Client recording (default): The browser on your tablet/phone records audio and sends it to the server via WebSocket binary frames.
Host recording: The server records audio directly from the PC's microphone. The client only sends start/stop signals β no audio leaves the browser.
When you speak a command:
- Audio is recorded (client browser or host microphone)
- Server transcribes audio using the configured STT engine
- Transcribed text is matched against speech commands
- Matched command is executed (shell, HTTP, button press, or slider change)
- Visual feedback + optional TTS confirmation is sent back to the client
Vosk (Offline):
- Fully offline, no internet required
- Downloads model automatically on first use (~50MB)
- Grammar-constrained recognition: Only recognizes your defined phrases, dramatically improving accuracy
- Fast, lightweight, supports many languages
- Requires CGO and the Vosk shared library
- Grammar updates automatically when you add new speech triggers
llama-cpp-server (HTTP API):
- Uses your existing llama-cpp-server instance
- Supports two API modes:
transcriptions: Whisper-compatible/v1/audio/transcriptionschat: OpenAI-compatible/v1/chat/completionswith audio content (for multimodal models like gemma-3)
- Higher accuracy with larger models
Create user/speech_commands.json:
[
{
"phrase": "gear up",
"aliases": ["landing gear up"],
"type": "shell",
"command": "echo gear_up"
},
{
"phrase": "set throttle to {value}",
"type": "slider",
"block_id": "throttle-block-id",
"value_pattern": "number"
},
{
"phrase": "open hangar",
"type": "http",
"http_method": "GET",
"http_url": "http://localhost:8080/hangar"
}
]| Type | Description |
|---|---|
shell |
Execute a shell command with parameter substitution |
http |
Send an HTTP request |
button |
Simulate a button press on a specific block |
slider |
Set a slider value (extracted from speech) |
Use {param} placeholders in phrases to capture values:
{
"phrase": "set throttle to {value}",
"type": "slider",
"block_id": "throttle-block-id"
}Saying "set throttle to 75" extracts value=75 and sends it to the slider block.
In the editor, click the gear icon on any block and set:
- Speech Trigger: The phrase that activates this block (e.g., "gear up")
- Speech Aliases: Comma-separated alternative phrases (e.g., "landing gear up, gear up please")
- Trigger Type:
button(simulate click) orslider(set value)
Restrict which speech commands can execute:
{
"speech_allowlist": [
"gear up",
"gear down",
"set * to *"
]
}Commands not matching any pattern are blocked and logged.
These modes are mutually exclusive β set one in config.json.
Push-to-Talk ("push-to-talk"):
- Hold the floating microphone button on the panel
- Release to stop recording and process
- Visual feedback: red pulse while recording, yellow while processing
- Works with both client and host recording
Wake Word ("wake-word"):
- Continuous hands-free listening
- Host mode (
"recording_location": "host"): The server microphone continuously listens for the wake word using the STT engine. When detected, it recordswake_word_listen_secseconds of follow-up speech and processes it. Works on all browsers. - Client mode (
"recording_location": "client"): The browser listens for the wake word using the Web Speech API (Chrome/Edge only). When detected, it records follow-up speech via the tablet microphone. - Visual feedback: cyan pulse while listening, faster pulse when wake word detected
- No mic button interaction needed
- Visual: Toast notification showing recognized text and match status
- Audio: TTS confirmation ("Gear up confirmed") if
tts_enabledis true - Block flash: Matched blocks briefly glow cyan
The Data Bus is a real-time data distribution system that allows any data source to push values to the server, which then broadcasts them to all connected panel clients. Blocks can subscribe to data keys and display live updating values.
The Data Bus supports three types of data sources:
| Source | Description | Example Keys |
|---|---|---|
| System metrics | Automatically collected every 500ms (platform-specific) | cpu_usage, memory_usage, disk_usage, network_rx, network_tx |
| HTTP API | Push data via POST /api/data/push |
Any custom key |
| WebSocket | Push data via push-data message |
Any custom key |
The data_display block subscribes to any key on the Data Bus and shows live values:
<settings
title="CPU USAGE" type-title="text"
data_key="cpu_usage" type-data_key="text"
unit="%" type-unit="text"
decimal_places="1" type-decimal_places="number" min-decimal_places="0" max-decimal_places="3"
font_size="14" type-font_size="number" min-font_size="1"
width="90%" type-width="percentage" min-width="10" max-width="100"
height="60%" type-height="percentage" min-height="10" max-height="100"
title_color="#8ba4b8ff" type-title_color="color"
value_color="#1ccad8ff" type-value_color="color"
border_color="#1ccad8ff" type-border_color="color"
bg_color="#1a2636ff" type-bg_color="color"
></settings>| Setting | Type | Description |
|---|---|---|
title |
text |
Display label shown above the value |
data_key |
text |
Data Bus key to subscribe to |
unit |
text |
Unit suffix displayed after the value |
decimal_places |
number |
Number of decimal places for numeric values (0-3) |
font_size |
number |
Base font size for responsive scaling |
width |
percentage |
Inner box width relative to block |
height |
percentage |
Inner box height relative to block |
title_color |
color |
Title text color (8-digit hex with alpha) |
value_color |
color |
Value text color (8-digit hex with alpha) |
border_color |
color |
Border and glow color |
bg_color |
color |
Background color |
curl -X POST http://localhost:3000/api/data/push \
-H "Content-Type: application/json" \
-d '{"key": "server_temp", "value": 42.5, "unit": "Β°C", "source": "sensors"}'| Field | Type | Required | Description |
|---|---|---|---|
key |
string | Yes | Data key that blocks subscribe to |
value |
any | Yes | Value to display (number, string, boolean) |
unit |
string | No | Unit label (e.g., %, Β°C, KB/s) |
source |
string | No | Source identifier for tracking |
socket.send(JSON.stringify({
type: "push-data",
data: {
key: "custom_metric",
value: 99.9,
unit: "pts",
source: "my_app"
}
}));| Key | Description | Unit | Linux Source | Windows Source |
|---|---|---|---|---|
cpu_usage |
CPU utilization percentage | % |
/proc/stat |
Stub (requires WMI/PerfCounters) |
memory_usage |
RAM utilization percentage | % |
/proc/meminfo |
Stub (requires GlobalMemoryStatusEx) |
disk_usage |
Root filesystem utilization | % |
syscall.Statfs("/") |
GetDiskFreeSpaceExW("C:\\") |
network_rx |
Network receive rate (all interfaces, excluding loopback) | KB/s |
/proc/net/dev |
Stub (requires IPHelper API) |
network_tx |
Network transmit rate (all interfaces, excluding loopback) | KB/s |
/proc/net/dev |
Stub (requires IPHelper API) |
The server broadcasts all Data Bus values to every connected client every 500ms:
{
"type": "data-update",
"data": {
"cpu_usage": { "value": 45.2, "unit": "%", "source": "system" },
"memory_usage": { "value": 62.1, "unit": "%", "source": "system" },
"server_temp": { "value": 42.5, "unit": "Β°C", "source": "sensors" }
}
}- System monitoring: Display CPU, memory, disk, and network stats on your panel
- Game telemetry: Push game-specific data (fuel, shields, cargo) via WebSocket
- Home automation: Display temperature, humidity, or sensor readings via HTTP API
- Build status: Show CI/CD pipeline status, deployment progress, or test results
- Custom dashboards: Any data you can push, any block can display
| Method | Path | Description |
|---|---|---|
GET |
/ |
Start page (panel list, editor link, host controls, connection log) |
GET |
/panel |
Panel client (MFD display for touch devices) |
GET |
/editor |
Panel editor UI |
GET |
/* |
Static files (JS, CSS, block assets from static/; JS/CSS served with Cache-Control: no-cache to prevent stale browser cache) |
GET |
/blocks/* |
Block HTML files from user/blocks/ (flat, no theme subdirectories) |
GET |
/themes/* |
Theme CSS files from user/themes/ |
GET |
/assets/* |
Asset files from user/assets/ |
GET |
/api/blocks |
Returns flat list of available block templates |
GET |
/api/themes |
Returns array of available theme names (e.g., ["default", "star_citizen", "kde_breeze", "windows_11"]) |
GET |
/api/panels |
Returns { "allPanels": [...] } |
GET |
/api/config |
Returns current configuration |
GET |
/api/panel/content?name=X |
Returns panel JSON by name |
POST |
/api/panel/save |
Save panel. Body: { "fileName": "name", "content": { version: 2, blocks: [...], ... } } |
POST |
/api/data/push |
Push data to Data Bus. Body: { "key": "...", "value": ..., "unit": "...", "source": "..." } |
POST |
/api/joystick-count |
Update joystick count. Body: { "count": N } |
GET |
/api/mpris/players |
List connected MPRIS media players and their state (Linux only) |
POST |
/api/mpris/control |
Send playback command. Body: { "action": "play"|"pause"|"playpause"|"stop"|"next"|"previous"|"volume", "volume": 0.5, "player": "spotify" } |
POST |
/api/mpris/select |
Set the active player. Body: { "player": "spotify" } |
GET |
/api/mpris/cover |
Proxy cover art file for browser access. Query: ?url=<local-file-path> |
Connect to ws://<host>:<port>/ws (or wss:// behind a reverse proxy).
Server β Client messages:
| Type | Data | Description |
|---|---|---|
force-reload |
β | Client should reload (panel changed) |
enter-fullscreen |
β | Request client to enter fullscreen |
exit-fullscreen |
β | Request client to exit fullscreen |
data-update |
{ "key": { "value": ..., "unit": "...", "source": "..." } } |
Data Bus snapshot broadcast (every 500ms). MPRIS keys: mpris_title, mpris_artist, mpris_album, mpris_cover_url, mpris_progress (0-100%), mpris_volume (0-100%), mpris_playback_status ("Playing"/"Paused"/"Stopped"), mpris_player_name, mpris_identity, mpris_can_play, mpris_can_pause, mpris_can_go_next, mpris_can_go_previous, mpris_can_control, mpris_available_players (JSON array of {name, identity} objects for multi-player selection) |
rss-update |
{ "block_id": "...", "entries": [{ "guid": "...", "title": "...", "link": "...", "published": "...", "description": "...", "feed_label": "...", "is_new": true }] } |
Per-client RSS feed update. is_new is true for entries the client hasn't seen yet |
log-event |
{ "timestamp": "...", "data": "..." } |
Connection log event (client connect/disconnect) |
speech-result |
{ "text": "...", "matched": true, "speak": "..." } |
Speech transcription result |
speech-error |
{ "error": "..." } |
Speech processing error |
recording-status |
{ "state": "listening" } |
Recording state change |
speech-button-trigger |
{ "block_id": "..." } |
Speech-triggered button press |
speech-slider-trigger |
{ "block_id": "...", "value": "..." } |
Speech-triggered slider change |
Client β Server messages:
| Type | Data | Description |
|---|---|---|
simulate-button |
{ "js": 0, "id": 0, "state": 1 } |
Press/release button |
simulate-slider |
{ "js": 0, "id": 0, "value": 128 } |
Set slider value (0 to max_value, default 255) |
simulate-joystick |
{ "js": 0, "id": 0, "value": { "x": 127, "y": 127 } } |
Set joystick X/Y (0-255) |
simulate-keyboard |
{ "keyboard_index": 0, "key": "ctrl+a", "state": 1 } |
Press/release key or combo |
push-data |
{ "key": "...", "value": ..., "unit": "...", "source": "..." } |
Push data to Data Bus for broadcast |
execute-command |
{ "block_id": "...", "command_type": "shell", "command": "...", "http_method": "GET", "http_url": "...", "http_body": "...", "params": {...} } |
Execute command with parameters |
start-recording |
{ "mode": "push-to-talk" } |
Client begins audio recording |
stop-recording |
β | Client finished recording |
speech-config |
{ "enabled": true } |
Toggle speech on client |
register-speech-trigger |
{ "block_id": "...", "phrase": "...", "aliases": [...], "type": "button", "joystick_index": 0, "button_id": 3, "axis_id": 0 } |
Register speech trigger for block with hardware IDs |
rss-configure |
`{ "block_id": "...", "feed_urls": ["URL | Label", "..."], "refresh_interval": 60, "max_entries": 20 }` |
open-url |
{ "url": "https://..." } |
Open a URL in the host's default browser (triggered by clicking RSS entries when open_url_location is "host") |
Binary WebSocket frames:
| Content | Description |
|---|---|
| Audio data (PCM 16kHz mono 16-bit) | Raw PCM audio chunks from client recording, processed directly by STT engine |
Server β Client messages (additional):
| Type | Data | Description |
|---|---|---|
command-result |
{ "block_id": "...", "success": true, "output": "..." } |
Command execution result |
Requires Go 1.23+.
Linux (no CGO needed for core features):
git clone https://github.com/your-org/OmniPanel-go.git
cd OmniPanel-go
go build -o omnipanel-go .
./omnipanel-goLinux builds are fully static for core features (web server, virtual joystick, virtual mouse). CGO is only needed for speech host recording (miniaudio-go) and Vosk STT.
Linux (with speech host recording):
sudo apt install gcc pkg-config libasound2-dev # ALSA development files
CGO_ENABLED=1 go build -o omnipanel-go .macOS (web server only, no virtual input):
git clone https://github.com/your-org/OmniPanel-go.git
cd OmniPanel-go
go build -o omnipanel-go .
./omnipanel-goWindows: Requires MinGW-w64 or MSYS2 GCC for CGO, and the vJoy SDK for joystick support.
git clone https://github.com/your-org/OmniPanel-go.git
cd OmniPanel-go
# Ensure vJoyInterface.dll is in your PATH or project directory
set CGO_ENABLED=1
go build -o omnipanel-go.exe .
omnipanel-go.exeLinux uses the native uinput kernel module for high-performance virtual input.
- Enable uinput Module:
sudo modprobe uinput
- Set Permissions:
(Note: You must log out and back in for group changes to take effect).
echo 'KERNEL=="uinput", MODE="0660", GROUP="uinput", OPTIONS+="static_node=uinput"' | sudo tee /etc/udev/rules.d/99-uinput.rules sudo groupadd -f uinput sudo usermod -aG uinput $USER
- Enable on Startup:
echo "uinput" | sudo tee /etc/modules-load.d/uinput.conf
- Run:
./omnipanel-go
- Done.
The Linux joystick backend uses a custom uinput ioctl wrapper built on golang.org/x/sys/unix. Each virtual joystick provides:
- 8 analog axes (ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ, ABS_THROTTLE, ABS_RUDDER) with range 0-255
- 16 buttons (BTN_JOYSTICK 0x100-0x10F)
The uinput device is created at startup and destroyed on graceful shutdown (SIGINT/SIGTERM).
Windows uses vJoy for virtual joysticks and the built-in SendInput API for mouse simulation.
- Install vJoy Driver: Download and install vJoy v2.2.2.0 (signed, works on Win10/Win11).
- Configure vJoy Devices:
Open the vJoy Configure utility and enable at least as many devices as your
numJoysticksconfig value. Each device should have 8 axes and 16 buttons configured. - Runtime DLL:
Place
vJoyInterface.dll(from the vJoy SDK) next toomnipanel-go.exeor in a directory in yourPATH. The binary requires this DLL at runtime for joystick functionality. - Build with CGO (if building from source):
Install MinGW-w64 or MSYS2 GCC.
set CGO_ENABLED=1 go build -o omnipanel-go.exe .
- Run:
omnipanel-go.exe
- Done.
Note: Virtual mouse simulation uses Windows
SendInputAPI and requires no additional drivers. CPU, memory, and network metrics are stubbed on Windows (only disk usage is collected).
| Feature | Linux | Windows | macOS/BSD |
|---|---|---|---|
| Web Server | Yes (pure Go) | Yes (pure Go) | Yes (pure Go) |
| Virtual Joystick | Yes (uinput, pure Go) | Yes (vJoy, CGO + vJoyInterface.dll) |
No |
| Virtual Mouse | Yes (uinput, pure Go) | Yes (SendInput, CGO) | No |
| Virtual Keyboard | Yes (uinput, pure Go) | Yes (SendInput, CGO) | No |
| System Metrics | Full (pure Go) | Disk only (pure Go) | No |
| Speech (Vosk) | Yes (CGO + libvosk.so) |
Yes (CGO + vosk.dll) |
Yes (CGO + libvosk.dylib) |
| Speech (llama-cpp) | Yes (HTTP, no CGO) | Yes (HTTP, no CGO) | Yes (HTTP, no CGO) |
| Host Recording | PulseAudio/ALSA (CGO) | WASAPI (CGO) | CoreAudio (CGO) |
| Client Recording | Yes | Yes | Yes |
| Client Wake Word | Chrome/Edge | Chrome/Edge | Safari/Chrome |
OmniPanel-go uses Forgejo Actions for continuous integration and deployment:
Triggers on every push and pull request to main:
- Linux: Builds binary and runs
go test ./... - Windows: Linux-to-Windows CGO cross-compile is currently not reliable and should not be treated as a working path
For a native Windows build (same behavior used by contributors locally), use the maintained script in scripts/build-with-vosk.ps1:
.\scripts\build-with-vosk.ps1The script handles Vosk asset discovery/download, MinGW-friendly import library generation, runtime DLL staging, and build logs (bin/build.stdout.log, bin/build.stderr.log).
Triggers on version tags (v*, e.g., v1.0.0):
- Builds Linux release artifacts in CI. Windows artifacts should be produced with the native Windows script path.
- Creates a Forgejo release
- Uploads binaries to the release page (visible in project's Releases section)
To create a release:
git tag v1.0.0
git push origin v1.0.0A comprehensive, beginner-friendly user manual is available in two languages:
- English β 16 chapters covering everything from first launch to RSS feeds
- German β VollstΓ€ndige deutsche Γbersetzung mit 16 Kapiteln
Written for gamers with no technical expertise.
The tutorials are a guided tour through the OmniPanel-go codebase, written for developers who are new to Go (and web development). Each chapter explains the concepts first, then walks through the actual source code.
| Part | Topic | Chapters |
|---|---|---|
| A | Go Backend Fundamentals | Project overview, configuration, state & concurrency, databus |
| B | HTTP, WebSocket & Commands | HTTP routing, WebSocket, command execution |
| C | Platform-Specific Code | Virtual input devices (Linux/Windows) |
| D | Speech Recognition | Overview, STT engines, phrase matching, audio recording |
| E | Web Frontend | Panel UI, Editor UI, Start Page |
| F | Architecture & Data Flow | End-to-end data flow |
| G | Platform Integrations | MPRIS media player, RSS feed polling, WebSocket push, host URL opening |
- Read chapters in order β each builds on concepts from the previous ones
- Code excerpts include line numbers referencing the original files
- "Concept" boxes explain Go/JavaScript fundamentals for novices
- "Key Pattern" callouts highlight idiomatic techniques worth remembering
Contributions make the open-source community amazing.
- Fork the Project.
- Create your Feature Branch (
git checkout -b feature/AmazingFeature). - Commit your Changes (
git commit -m 'Add some AmazingFeature'). - Push to the Branch (
git push origin feature/AmazingFeature). - Open a clear Pull Request so I can easily understand your changes.
Thank you for trying OmniPanel-go!



