OmaPower brings satisfying particle bursts to terminals on Omarchy. Every printable key launches a compact spray of pixels from the live block cursor. The default colors move through the white, cyan, blue, indigo, and purple shades of the Omarchy logo.
The effect runs as a click-through Wayland overlay inside omarchy-shell. With
the native Bash and Foot integration, particles follow the real terminal cell
through wrapped lines, directory changes, new prompts, and scaled monitors.
OmaPower never receives the character or command being typed, and its animation
clock stops when no particles are active.
Recorded in Foot with OmaPower's default motion and Omarchy color palette.
The plugin targets Omarchy 4.0.1's schema version 1 plugin API. The current plugin release is 0.6.6.
- Exact Foot cursor positioning through the native Bash Readline hook
- Prompt-aware cleanup, so a finished command cannot leave particles on the wrong terminal row
- Adjustable particle count, size, spread, speed, gravity, lifetime, and fade
- Full Omarchy logo, accent, rainbow, and fixed color modes
- Foot, Ghostty, Kitty, and Alacritty focus filtering through Quickshell's native Hyprland integration
- One click-through overlay per monitor, using Wayland logical coordinates
- Bash-compatible fallback detection through Wayland's idle-notify protocol
- A hard particle limit with no animation loop while idle
- Optional visual shake of the particle field
- Direct controls through Omarchy shell IPC
The default activity mode needs only Omarchy 4.0.1 or a compatible Quattro release. It uses the Wayland idle-notify support already available in the Omarchy shell.
Exact cursor tracking is optional. The Bash integration requires Foot, GCC,
and the development headers included with Arch's bash package. The Zsh
integration requires Zsh's bundled zsh/net/socket module.
omarchy plugin add https://github.com/nivekcode/omapower --enable
omarchy restart shellThe restart is required after an install, update, or reinstall. OmaPower's
background service stays loaded inside omarchy-shell, so a plugin rescan can
update the files without replacing the running service instance.
For local development:
omarchy plugin validate .
mkdir -p ~/.config/omarchy/plugins
cp -R . ~/.config/omarchy/plugins/io.github.nivekcode.omapower
omarchy plugin enable io.github.nivekcode.omapower
omarchy-shell shell rescanPluginsThe standard plugin install does not edit Omarchy, Hyprland, or terminal
configuration. The optional Bash integration described below adds one marked
line to .bashrc only when you run its installer. It makes a timestamped
backup first and compiles only the C source included in this repository. It
does not use the network or elevated privileges.
If you installed the optional Bash integration, remove it before removing the
plugin. The uninstaller deletes only OmaPower's marked .bashrc entry and
cached native module. It backs up .bashrc before editing it.
~/.config/omarchy/plugins/io.github.nivekcode.omapower/scripts/uninstall-bash-integration
omarchy plugin remove io.github.nivekcode.omapower
omarchy restart shellThe uninstaller is safe to run when the integration is not installed. It does
not delete earlier .bashrc backups.
The bundled helper is optional. Run it from the repository:
./scripts/omapowerctl burst
./scripts/omapowerctl toggle
./scripts/omapowerctl status
./scripts/omapowerctl set particleCount 7
./scripts/omapowerctl set particleColorMode rainbowThe underlying current Omarchy IPC commands are:
omarchy-shell omapower burst
omarchy-shell omapower enable
omarchy-shell omapower disable
omarchy-shell omapower toggle
omarchy-shell omapower reloadSettings
omarchy-shell omapower status
omarchy-shell omapower set particleSize 5burst is intentionally allowed in any focused window. It is a visual test.
Automatic shell-integration events are rejected unless a supported terminal is
focused.
Wayland does not let an ordinary shell plugin observe another application's
keypresses or caret. That separation is a security feature. OmaPower does not
use /dev/input, a global shortcut for every key, accessibility scraping, or
terminal screen capture.
The default activity input mode uses Wayland's idle-notify protocol with a
10 ms reset delay. It sees only that user activity resumed, then checks whether
a supported terminal is focused. It does not receive a key code, character, or
device type. This works with Bash and other shells, but it can also create one
burst when mouse activity resumes while a terminal is focused. Continuous
pointer movement does not produce a stream of bursts because the monitor must
be idle for 10 ms before it can resume again.
If the native Bash hook is present, its exact cursor report takes priority even
when a reinstall has reset this setting to activity. The matching Wayland
activity event is discarded, so it cannot replace the exact position with the
window approximation.
./scripts/omapowerctl set inputMode activity
./scripts/omapowerctl set activityResetDelay 10For Zsh, source the included integration after your line editor configuration:
source /path/to/omapower/integrations/omapower.zshIt opens one Unix-socket connection per interactive Zsh and sends the literal
token burst after ZLE's built-in self-insert widget runs. It never sends the key, line
buffer, command, cursor index, or environment. The plugin checks the focused
window again before rendering. It uses Zsh's bundled zsh/net/socket module,
so it does not start a helper process or add a dependency.
Switch to socket-only mode to prevent the Wayland fallback from creating a second burst for the same key:
./scripts/omapowerctl set inputMode socketThe Zsh hook covers printable self-insert events. It does not add particles for cursor movement, deletion, completion, or bracketed paste. Fish does not have an equally small, content-blind hook, so its automatic integration remains disabled. Manual bursts still work.
An external Wayland overlay cannot access Foot's caret. OmaPower's Bash
integration loads a small native Readline function compiled on the local
machine. That function calls Readline's
own rl_insert, reads the resulting cursor index, and sends numeric cursor and
terminal-grid geometry plus Foot's process ID. It does not run a shell callback
or rewrite READLINE_LINE for each key. This keeps Foot's block cursor on the
normal Readline rendering path and prevents another terminal's prompt update
from moving the active cursor.
Install it once, then open a new terminal:
~/.config/omarchy/plugins/io.github.nivekcode.omapower/scripts/install-bash-integrationThe installer builds ~/.cache/omapower/omapower-readline.so against the
installed Bash headers and selects socket mode. Keeping the compiled module out
of the plugin directory prevents an installation-time shell reload. Foot's
terminal API reports the grid's physical pixel size, so the native hook sends
the exact cell width and height with each cursor position. This avoids
accumulated drift in wide windows and on lower terminal rows. After each native
self-insert, the overlay waits 8 ms for Foot to paint and starts the burst at
the leading edge of the reported block cursor. Keys inside one redraw cycle
collapse to the newest position. The native function receives Readline's key
argument because Readline calls it, but it never sends, logs, or retains that
value or the command line. The Unix socket receives cursor-grid numbers and the
terminal process identifier only.
Prompt color and formatting codes are removed using bytewise parsing, so the
system locale cannot count invisible Starship control sequences as cursor cells.
When Bash draws a new prompt, OmaPower removes particles left on the previous
command line before accepting new input.
Each terminal loads its own non-exported integration guard. A Foot window opened through Super+Enter cannot inherit a stale "already loaded" state from its parent process.
Generic Wayland and Hyprland do not expose terminal caret coordinates. Quickshell's toplevel API provides window geometry rather than terminal grid state. The optional Bash integration closes that gap for Foot by requesting one standard numeric cursor-position report before each prompt, then combining that anchor with Readline's post-insert cursor index. The result is the current block cursor cell without querying the terminal while the user is typing.
Without the Bash integration, the origin is an approximation inside the active terminal window. By default it is 18 percent across the window and 52 logical pixels above the bottom edge. Tune these for your prompt and terminal padding:
./scripts/omapowerctl set originXRatio 0.12
./scripts/omapowerctl set originBottomOffset 64Window geometry comes from Hyprland in global logical coordinates. The overlay subtracts the selected screen's logical origin, which keeps placement consistent across monitors with different scales.
Settings persist in the plugin's entry in ~/.config/omarchy/shell.json. The
set command writes them through Omarchy's own configuration mutator.
| Setting | Default | Range or values |
|---|---|---|
particlesEnabled |
true |
boolean |
particleCount |
6 |
1 to 24 |
particleLifetime |
360 |
120 to 2000 ms |
particleSize |
2.4 |
1 to 18 logical px |
particleSpread |
90 |
15 to 500 logical px |
initialVelocity |
200 |
20 to 800 |
gravity |
360 |
-500 to 1400 |
opacity |
0.96 |
0.05 to 1 |
maximumActiveParticles |
160 |
8 to 500 |
particleTrail |
false |
boolean |
cursorFlash |
false |
boolean |
shakeEnabled |
false |
boolean |
shakeStrength |
2 |
0 to 12 logical px |
shakeDuration |
90 |
20 to 400 ms |
particleColorMode |
omarchy |
omarchy, accent, rainbow, fixed |
customParticleColor |
#ffffff |
six or eight digit hex color |
inputMode |
activity |
activity, socket, both |
activityResetDelay |
10 |
10 to 250 ms |
caretTrackingEnabled |
true |
boolean |
terminalPaddingX |
14 |
0 to 100 logical px |
terminalPaddingY |
14 |
0 to 100 logical px |
terminalIdentifiers |
common terminals | JSON array or comma-separated list |
originXRatio |
0.18 |
0 to 1 |
originBottomOffset |
52 |
0 to 400 logical px |
Example terminal list:
./scripts/omapowerctl set terminalIdentifiers '["foot","my-terminal"]'Shake affects the particle field, not the terminal window. Moving a tiled Hyprland client for every key can disturb layout and leave geometry behind after an interrupted animation, so OmaPower does not do that.
The default burst uses a narrow, balanced upward cone rather than a radial explosion. Every spark begins at the exact emitter coordinate, then uses frame-rate-independent velocity, drag, gravity, exponential alpha decay, and a final eased fade. Particle cores stay square and align to physical pixels so the effect remains sharp at small sizes. Trails and the cursor flash remain available as options but are off by default. Successive bursts rotate through every white, cyan, blue, indigo, and purple shade sampled from the Omarchy logo.
All active particles on a monitor share one vsync-driven framebuffer canvas. The overlay stays mapped while OmaPower is enabled, which avoids layer-surface creation on the first character after an idle period.
The Wayland activity monitor exposes no key or pointer data. The socket accepts
the burst token, numeric terminal-grid positions, and the terminal process
identifier from optional shell integrations. Events are used immediately and
are not written to disk, logged, transmitted, or kept as a history. The service
stores only a lifetime burst counter for its status output. Disable and
re-enable the plugin to reset it.
Each monitor uses one canvas driven by Qt's vsync-aligned FrameAnimation.
Particles share that clock, expired particles are removed in batches, and new
bursts stop at maximumActiveParticles. The layer surface has an empty input
region and never requests keyboard focus.
omarchy plugin validate .
qmllint ./*.qml
shellcheck scripts/* integrations/*Use omarchy-shell shell rescanPlugins after copying a new local checkout if
the file watcher has not reloaded it. Restart the shell after changing the
keep-loaded service itself:
omarchy restart shellMIT

