A lightweight desktop mate for Omarchy: a little pixel cat that roams your screen, rides along when you pick it up, purrs when you pet it, naps when you ignore it, and drops by with messages. Pure QML on Quickshell — no AI, no network, no dependencies beyond the shell you already run.
Inspired by Mate-Engine's interaction model.
| Settings panel | Sitting on floating windows | Natural sizes |
|---|---|---|
![]() |
![]() |
![]() |
| Reminders page — timers and daily alarms | Right-click reminders menu |
|---|---|
![]() |
![]() |
Sitting works on any floating window — and she falls off when it closes. Sizes range from the 24px cat up to 250px Totoro, settable per pack.
- Omarchy with its Quickshell shell (the default)
- Hyprland (window tracking for window-sitting; the default)
- PipeWire's
pw-playfor sound effects (stock on Omarchy; mute in the panel) - Optional, only for the character converters in
tools/:python3(pluspillowfor the GIF importer). The plugin itself never runs Python.
- Crosses monitors: drag her past a screen edge and the whole overlay follows to the neighboring output; a strong flung toss near an edge throws her across too. Falls, window-sitting and hopping all work on whichever screen she's on. If the screen she's on gets unplugged, she returns to the auto-picked home output.
- Roams the bottom edge of your screen (walks on top of the bar's reserved strip, never covers your work).
- Sits on floating windows: climbs up onto the tops of floating windows, rides along when you move them, and falls when the window closes, unfloats, or slides out from under it.
- Drag & throw: pick it up and toss it — real gravity, soft landings on window tops or the floor, and it gets dizzy if you drop it too far.
- Pet it: hold the mouse still on it for a moment — purrs and hearts. Petting a sleeping cat keeps it asleep.
- Poke it: a quick tap gets a mew and a startled face.
- Sleeps after 10 idle minutes (configurable), wakes when grabbed.
- Corner trips: a pack that ships a
corneranimation will occasionally wander to the nearest edge of whatever it is standing on, turn around and play that pose before carrying on. Packs without that art never do it, so none of the bundled characters are affected. - Chase the cursor (off by default): switch it on and the mate stalks
your mouse pointer, hauls it in when it strays close, bites it, and hands
it straight back to where it picked it up. It can never keep the pointer —
every pull is capped and always ends by returning it — so you win a tug of
war just by out-lasting it. Switching it on lives only in the settings
panel, next to the cadence — every ten seconds through twice an hour — so
it cannot be armed by a stray click; the right-click menu only ever stops
it. The chomp is played with the pack's
pokepose, so a character that ships nopokeart is never offered the chase at all — the pointer would be hauled in and nothing would visibly happen. - Time of day: once per stretch of the day the mate has something fitting to say — a good-morning line, a lunch nudge, a "go touch some grass" in the afternoon, a good night late. Set your name in the settings panel (letters and digits, up to 20 characters) and some of those lines will use it.
- Reminders and alarms: right-click the mate → "Reminders…" for quick
break timers ("Break in 25 min") and to snooze, pause, or delete what's
armed; the panel's Reminders page adds named one-shot timers and daily
alarms (name + time, with a snooze button and a delete per row). When a
reminder comes due the mate wakes, plays a sound, and speaks it:
"taps paw Take a break, Palccod!". Daily alarms reschedule themselves
for the next day; snoozing pushes one out by 10 minutes or an hour. The
list survives restarts (
~/.local/state/omarchy/omate-reminders.json), andomarchy-shell omate remind 25 "Take a break"sets one from the CLI. - Speech bubbles: idle chatter, event reactions, and any message you send it.
- Multi-screen: with more than one monitor the mate occasionally takes a trip to another output on its own (drops in from the top), dragging it past a screen edge carries it over to the next screen, and a strong fling along an edge throws it across. "Lock to this screen" in the menu pins it where it is and stops all of that until unlocked.
- Sounds: tiny synthesized blips (grab, purr, poke, thud, zzz, wake).
- Menu: right-click the cat for settings / reminders / walk / nap /
screen lock / mute / hide (plus "Find a corner" for packs with
cornerart, and "Stop chasing" while a chase is armed). - Settings panel: click the bar button (or the cat's "Settings…" menu entry) for a popup card styled like the plugin manager's rows — an animated sprite in the header, an enable/disable power switch in the top right, a skin picker where every installed pack previews its own idle animation, live controls for roaming, volume, size, walkiness, home screen, your name, nap/chatter cadence, and the cursor chase — plus a Reminders page (open it from the "Reminders" row) with one-shot timers, daily alarms, and snooze.
- Eighteen characters bundled — Pikachu, Miku, Totoro, SpongeBob, Spider-Man, Deadpool, Luffy, Dieter the cat, Hornet, Gojo, Rem, Mitsuri, a fox, an akita, a panda, a turtle, a rubber duck, and Perry the Pug; import your own with the built-in converters.
- Full behavior set where the art allows it — besides walking,
roaming and napping, characters with the right frames sit down, lie
down, and hit a ground-impact pose after a fall (sleep uses the lying
pose whenever a pack ships one, and pokes get a stumble reaction);
every shimeji import maps those animations automatically. Name an
import's impact sprite
land_00.png(or let the converter take the bounce action) and it plays on every landing. - Click-through everywhere except the cat itself — your desktop stays fully usable.
One command — no build steps, no extra setup:
omarchy plugin add https://github.com/Palccod/Omate.git --enableThat's the whole setup: a bar button appears in the right section, the mate walks in on your desktop, and all eighteen characters are bundled — left click opens her settings, middle click pets the bar sprite. Future updates bring new packs and fixes through the same update command; her position, settings, and any characters you imported yourself live outside the plugin folder and survive updates.
omarchy plugin enable palccod.omate # bar widget + roaming mate return
omarchy plugin disable palccod.omate # both disappear; files stay put
omarchy plugin list # see what's installed and enabledThe mate's own power switch in the settings panel only hides her — disabling the plugin unloads the service itself.
omarchy plugin update palccod.omateIf the shell somehow keeps running old code after an update,
omarchy restart shell.
omarchy plugin remove palccod.omate # disables + deletes the pluginYour mate's memory lives outside the plugin folder — remove these too if you want a clean break:
rm -rf ~/.local/state/omarchy/omate-packs/ # characters you imported
rm ~/.local/state/omarchy/omate-settings.json
rm ~/.local/state/omarchy/omate-state.jsonEverything works out of the box: the eighteen bundled characters need no setup at all. This section is only for adding an nineteenth of your own — the converters take three formats, all offline.
MikuPet-style (a directory with character.json + sprite strips):
python3 tools/import-spritesheet.py ~/Downloads/miku-char \
~/.local/state/omarchy/omate-packs/mine "My Character"Shimeji (img/shime*.png + conf/ — the classic desktop-shimeji
zips; both the English shimeji-ee and the original Japanese conf formats
work, and sit/lie/jump animations are mapped automatically):
unzip ~/Downloads/some-shimeji.zip -d /tmp/pet
python3 tools/import-shimeji.py /tmp/pet \
~/.local/state/omarchy/omate-packs/pet "Pet Name"Animated-GIF pets (one <anim>.gif per animation, like the
vscode-pets media files;
needs Pillow):
python3 tools/import-gifpet.py ~/Downloads/pet-gifs \
~/.local/state/omarchy/omate-packs/pet2 "Pet Name" --flipImported packs live in ~/.local/state/omarchy/omate-packs/<name>/ (so
your characters survive plugin updates) and shadow bundled packs of the
same name. Each carries its own messages.json and pack.json. Good
hunting grounds: shimeji.org, the
DeviantArt shimeji tag, and
MikuPet releases.
Characters are fan art of copyrighted characters: fine for personal
offline use, don't redistribute. Every pack keeps its author credit in
its own pack.json; the eighteen bundled ones are inventoried in
THIRD_PARTY.md.
omarchy-shell omate say "Time to stretch!"
omarchy-shell omate pet
omarchy-shell omate poke
omarchy-shell omate wake # or: doze
omarchy-shell omate setRoam false # or: toggleRoam
omarchy-shell omate hide # or: show, toggleVisible
omarchy-shell omate setVolume 0.3
omarchy-shell omate setScale 4 # 1-6
omarchy-shell omate setScreen DP-1 # home output; "" = largest
omarchy-shell omate gotoScreen DP-1 # one-off trip: drop in from the top
omarchy-shell omate lockScreen # pin the mate to its current screen
omarchy-shell omate unlockScreen # free it to roam and follow drags again
omarchy-shell omate setPack miku # or: setPack default
omarchy-shell omate packs # list installed character packs
omarchy-shell omate corner # wander to the nearest corner (packs
# with "corner" art only)
omarchy-shell omate setCursorChase true # chase the mouse pointer
omarchy-shell omate toggleCursorChase
omarchy-shell omate setChaseCooldown 300 # seconds between chases, 5-3600
omarchy-shell omate remind 25 "Take a break" # one-shot reminder, minutes
omarchy-shell omate hop # teleport onto a random floating window
# (or leap for joy if none are around)
omarchy-shell omate status
omarchy-shell palccod.omate toggle # open/close the settings panelEverything lives in plain files; edit and run omarchy restart shell.
- Messages —
packs/default/messages.json: pools of lines the cat picks from (greet,idle,drag,pet,poke,land,dizzy,sleep,wake,corner,chase,bite, and the time-of-day poolsmorning,lunch,afternoon,evening,night, plusreminderfor when a reminder comes due — it uses{task}for the reminder's name). Any line can carry the placeholder{name}— it is replaced with the name set in the settings panel, and lines that use it are only picked when a name is set. Every pack'smessages.jsonsits on top of built-in defaults, so a pack that omits a pool (say,night) still falls back to the built-in lines. - Settings —
~/.local/state/omarchy/omate-settings.json:visible,roamEnabled,cursorChase(off by default),chaseCooldownSec(5–3600, default 300),scale(1–6),walkiness(0–1),screen(Hyprland output name, empty = largest),screenLocked(pins the mate toscreen),userName(what the mate calls you; letters and digits, 20 characters max),soundVolume,sleepMinutes,chatterMinutes. Every one of these is editable live from the settings panel; the file is just where they persist. - Sprites — 24×24 PNGs in
packs/default/sprites/, generated from ASCII grids intools/gen-sprites.py(edit the grids, rerun the script). Missing animations fall back to idle, so you can add frames gradually. - Sounds — WAV files in
sounds/, named after events (grab,pet,poke,land,zzz,wake). Replace freely.
manifest.json Omarchy plugin manifest (service + bar-widget)
Service.qml Brain: settings, persistence, sleep, messages, sounds, IPC
OmateWindow.qml Roaming overlay: physics, interactions, bubble, menu
OmatePanel.qml Settings card: skin picker with previews, power switch
BarWidget.qml Bar button (opens the panel, middle-click pets)
PetSprite.qml Frame-by-frame sprite animator
packs/default/ Sprites, pack.json (sizes/timings), messages.json
sounds/ Synthesized event blips
tools/ Sprite & sound generators (pure Python stdlib)
State (position, nap status) persists in
~/.local/state/omarchy/omate-state.json and is restored on login.
- No network access — fully offline; nothing is ever downloaded or phoned home
- No privileged behavior — no sudo, pkexec, systemctl, or services
- Pointer control — only if you turn on cursor chasing, which is off by default. It reads the pointer position from Hyprland's IPC socket and, while actively hauling, moves the pointer through Hyprland's own dispatcher. Each pull is capped in duration, always ends by releasing the pointer clear of the mate, and is followed by a cooldown; nothing about it can hold the pointer against you. Turn it off and none of that code runs.
- File access — reads and writes only its own state under
~/.local/state/omarchy/:omate-settings.json,omate-state.json,omate-reminders.json(your reminder list), andomate-packs/(characters you import yourself). Writes are atomic; reads are size-capped - Process execution — exactly two things, always with fixed argument
arrays:
pw-playfor the bundled sound effects, andhead -cfor bounded reads of its own state and pack files. Nothing is executed at install time and nothing is downloaded - No data collection — no telemetry, no clipboard access, no credentials
- The mate lives on the
Toplayer-shell layer: above your windows, below fullscreen apps (a fullscreen app covers it — same as the bar). - Like every Omarchy shell plugin it runs inside the main shell instance; restart the shell after changing files.
Contributors only — users never need this. Clone or link the repo into
~/.config/omarchy/plugins/palccod.omate/, then run
omarchy plugin enable palccod.omate (or
omarchy-shell shell rescanPlugins) and omarchy restart shell after
editing files. Lint with qmllint -I /usr/share/omarchy/shell *.qml,
validate with omarchy plugin validate .





