Text overlay support

This commit is contained in:
2026-04-18 11:38:16 -06:00
parent 44dc22d8ee
commit 962ee747fd
7 changed files with 495 additions and 33 deletions

View File

@@ -21,10 +21,11 @@ No Elgato software required — communicates directly with the device over USB H
- Runs as a systemd user service (Linux) or launchd agent (macOS), starts automatically at login
- No Stream Deck app, no Node.js, no Electron
- **Text overlays** — add a `text` field to any key for auto-sized, word-wrapped labels; white by default, or set `text_color` to black, red, blue, or any `#RRGGBB` hex. Works with icons (overlaid), without icons (white text on black), and on toggle keys. See [Text overlays](#text-overlays).
- **Modules** — define reusable, parameterised commands in `modules.yaml` with Go templates; secrets stay in env vars, config stays in dotfiles. Built-in examples: Slack (status, presence, snooze) and OBS Studio (recording, streaming, scene switching, media control). See [Modules](#modules).
- **Interactive config builder** — TUI tool (`streamdeck-init`) that walks you through key setup: pick a slot, pick a module/function, customize params, choose an icon. No YAML editing required. See [Config builder](#config-builder).
**Planned:** text/label overlays on keys, multi-page layouts, AUR package — see [Roadmap](#roadmap)
**Planned:** multi-page layouts, AUR package — see [Roadmap](#roadmap)
---
@@ -69,6 +70,8 @@ streamdeck-go/
│ └──▶ registry.Resolve() → rendered shell command
│ (templates expanded, env vars resolved)
├── text overlay? ──▶ overlayText() (auto-size font, word wrap, outline)
├── static icon ──▶ device.SetKeyImage() (scale → flip → JPEG → HID)
├── animated GIF ──▶ device.EncodeFrame() (pre-encode all frames once)
@@ -96,7 +99,7 @@ interleave partial image data across keys.
|---|---|
| [`github.com/sstallion/go-hid`](https://github.com/sstallion/go-hid) | Bindings for `libhidapi` — USB HID read/write |
| [`github.com/fsnotify/fsnotify`](https://github.com/fsnotify/fsnotify) | Config file watching for live reload |
| [`golang.org/x/image`](https://pkg.go.dev/golang.org/x/image) | Bi-linear image scaling |
| [`golang.org/x/image`](https://pkg.go.dev/golang.org/x/image) | Bi-linear image scaling, font rendering (text overlays use embedded Go Bold font) |
| [`gopkg.in/yaml.v3`](https://pkg.go.dev/gopkg.in/yaml.v3) | YAML config parsing |
| [`github.com/srwiley/oksvg`](https://github.com/srwiley/oksvg) | SVG rasterisation |
| Go stdlib `image/gif`, `image/jpeg`, `image/png` | Image decoding and JPEG encoding |
@@ -403,6 +406,68 @@ keys:
---
### Text overlays
Add a `text` field to any key to render a small label at the bottom of the key. The text is rendered at a fixed label size (~15pt at 96×96 key resolution), bottom-aligned so the icon stays visible above it. A contrasting outline is drawn automatically for readability on any background.
Text stays on a single line unless you add explicit line breaks with `\n` or YAML's `|` literal block syntax. If the text is too wide for the key, the font shrinks to fit. Multi-line text (up to 4-5 lines) is supported via explicit newlines.
The source image is scaled to key resolution (96×96 for XL, 72×72 for MK.2) before text is rendered, so label size is consistent regardless of source icon dimensions.
```yaml
keys:
# Label on an icon — single line, bottom-aligned
9:
icon: lock.png
text: "Lock Machine"
command: hyprctl dispatch exec omarchy-lock-screen
# Multi-line (explicit newlines only — no automatic word wrap)
16:
icon: server.png
text: |
Restart
Web Server
command: systemctl restart nginx
# Text-only key (no icon — white text on black background)
17:
text: "Build\nDeploy"
command: make deploy
# Custom text color
18:
icon: alert.png
text: "DANGER"
text_color: red
command: nuke-from-orbit
# Hex color
19:
icon: status.png
text: "Online"
text_color: "#00FF00"
command: ""
```
**`text_color`** is optional and defaults to white. Supported values:
| Value | Color |
|---|---|
| `white` (default) | White |
| `black` | Black |
| `red` | Red |
| `blue` | Blue |
| `#RRGGBB` | Any hex color |
Text overlays work on:
- **Static keys** — label at the bottom of the icon
- **Text-only keys** — no icon needed, renders on a black background
- **Toggle keys** — text appears on both `icon_true` and `icon_false`
- GIF keys do not currently support text overlays
---
### Launching applications
On Linux, GUI apps are typically launched by their binary name (`firefox`, `ghostty`, `nautilus`). On macOS, apps live in `/Applications/` as `.app` bundles and need to be opened differently.
@@ -1004,10 +1069,10 @@ To add a model, edit the `models` map in [internal/device/streamdeck.go](interna
## Roadmap
### Text / label overlay on icons
### Dynamic text from command output
Render dynamic text directly onto a key image at runtime — useful for showing
live state like volume level, a clock, a counter, or the current git branch.
Extend the text overlay feature to render live output from a shell command —
useful for showing volume level, a clock, a counter, or the current git branch.
Example config (proposed):
@@ -1015,8 +1080,7 @@ Example config (proposed):
keys:
4:
icon: volume.png
label: "$(pactl get-sink-volume @DEFAULT_SINK@ | awk '{print $5}')"
label_position: bottom # top | center | bottom
text: "$(pactl get-sink-volume @DEFAULT_SINK@ | awk '{print $5}')"
refresh: 5s
```