Pixel-art pets living inside your Neovim editor — vscode-pets equivalent.
v1.2: an animated pet wanders inside a wander box anchored to a screen
corner — idles, walks back and forth (bouncing off the box edges), and
occasionally lies down to rest. The pet also reacts to your work
without ever leaving its corner: it pauses to look at you when you
save, drifts off to sleep after long inactivity, and surfaces a small
random wiggle every few minutes. Sprite size, box size, and corner are
configurable both at setup and at runtime via :Pets* commands.
Why build this when
pets.nvimexists? See docs/why-built-from-scratch.md.
- Neovim >= 0.10
- A terminal that supports the Kitty Graphics Protocol (see compatibility below)
- ImageMagick (
brew install imagemagickon macOS) — only required if you regenerate sprites; not needed at runtime - image.nvim (loaded automatically as a dependency)
| Terminal | Status |
|---|---|
| Kitty | ✅ supported |
| WezTerm | ✅ supported |
| Ghostty | ✅ supported |
| iTerm2 | ❌ no Kitty Graphics support |
| Apple Terminal | ❌ no graphics protocol |
| Alacritty | ❌ no graphics protocol |
| VS Code integrated terminal | ❌ no graphics protocol |
If your TERM_PROGRAM isn't on the known-good list the plugin will print
a one-shot warning on first :Pets and continue anyway, so a new terminal
that supports the protocol will work without a code change.
If you run nvim inside tmux, also enable in your tmux.conf:
set -g allow-passthrough on
set -g focus-events on{
dir = "~/projects/nvim-pets",
dependencies = { "3rd/image.nvim" },
keys = { { "<leader>pp", "<cmd>Pets<cr>", desc = "Pets: toggle" } },
config = function()
require("pets").setup({
-- All optional; values shown are the defaults.
pet = "fox", -- "fox" | "panda" | "dog" | "turtle"
width = 11, -- sprite width in cells (overrides species default)
height = 5, -- sprite height in cells (overrides species default)
fps = 8,
area = {
corner = "br", -- "br" | "bl" | "tr" | "tl"
cols = 0, -- 0 = auto: cover most of the editor width
rows = 0, -- 0 = auto: cover most of the editor height
},
})
end,
}| Command | What it does |
|---|---|
:Pets (or <leader>pp) |
toggle the pet on/off |
:PetsResize <w> <h> |
resize sprite (cells); auto-grows the box if needed |
:PetsArea <cols> <rows> |
resize the wander box (cells) |
:PetsMove <corner> |
move box to corner (br / bl / tr / tl) |
:PetsType <name> |
switch species (fox / panda / dog / turtle) |
:PetsState |
print current pet / action / direction / position / size / area |
:PetsPeek / :PetsWiggle / :PetsSwipe / :PetsObject / :PetsSleep / :PetsWake |
manually trigger lifestyle events (debug) |
Any :Pets* config command applied while the pet is visible briefly hides
and re-shows it with the new settings.
The pet roams a wander box that covers most of the editor by default
(area.cols = 0, area.rows = 0). It walks in any of 8 directions —
up, down, diagonals included — and refuses to step on any cell that
currently contains visible text, signs, line numbers, or sidebar
content. The grid of "blocked" cells is recomputed (debounced ~150ms)
on TextChanged, WinScrolled, WinResized, and a few other events
so the pet's view stays up to date as you edit.
If you'd rather keep the pet in a small corner, set area.cols and
area.rows to specific values and the area.corner to your preferred
anchor.
Each species has its own wander transition probabilities so the way it spends time differs:
- fox — restless: highest
walkprobability, shortestlieruns - dog — balanced: walks and idles a lot, occasionally lies down
- panda — mellow: lies down often even from
idle, walks less - turtle — sleepy: spends most of its time lying down, walks slowly
Combined with the per-species sprite and the periodic swipe animation, the four pets read as visibly distinct over a session.
The pet stays in its corner but reacts to your editing rhythm:
- Peek on save —
BufWritePostfires the pet into a briefpeekstate: it pauses for ~1 second and faces toward the screen center (away from the corner) so it looks like it's looking at you. - Sleep on long idle — after ~10 minutes with no cursor movement / text
change / save, the pet curls up into a
liepose and stays there. Any user activity wakes it back to idle automatically. - Random wiggle — every ~5 minutes (±2 min jitter), if the pet isn't busy, it does a short head-shake (~1.5s of rapid left/right flips). Background sign of life.
- Species swipe — every ~4 minutes (±90s jitter), the pet plays its species-specific swipe animation (fox paw, panda hands-up, dog paw, turtle reach). This is what makes each species feel different beyond just the sprite.
- Environment objects — every ~3 minutes (±60s jitter), a ball appears somewhere in the wander box. The pet walks over to it (using the walk sprite), plays the species swipe animation for ~3 seconds, then the ball disappears and normal wandering resumes. Only one object is active at a time, and the timer is skipped while the pet is busy or asleep.
- Focus loss —
FocusLost(e.g. tmux pane move, app switch) tears the float down completely;FocusGainedbrings it back after a short defer. This is more aggressive than image.nvim'seditor_only_render_when_focusedbecause it also drops the cached Kitty placements, which prevents stale-image build-up that can freeze WezTerm + tmux on long sessions.
All of this reuses the existing idle / lie sprites — no new assets.
Manual debug triggers: :PetsPeek, :PetsWiggle, :PetsSleep, :PetsWake.
- tmux window switching may leave a "ghost" frame at the pet's last
position. This is a tmux + Kitty Graphics Protocol limitation (tmux doesn't
virtualize the graphics layer). Workaround: run
:Petstwice (off → on) to clear the cache and redraw cleanly.
- v0: static sprite in a float window (toggle)
- v1.0: frame-by-frame idle animation
- v1.1: wandering — state machine (idle ↔ walk ↔ lie), sprite flipping, edge bouncing
- v1.1.5: bounded wander box, runtime size/area/corner commands, image-cache fix
- v1.2: lifestyle events — save peek, idle sleep, random wiggle
- v1.3.1: multi-species —
pandaadded alongsidefox, runtime switch via:PetsType - v1.3.2:
dog(akita shiba) andturtle(green) added - v1.3.3: per-species personality — distinct wander probabilities + a periodic swipe signature animation
- v1.4.1: environment objects — ball spawns, pet approaches, plays swipe, ball despawns
- v1.4.2 (Phase 1): wander across the whole editor — 8-direction motion + buffer-aware avoidance so the pet never walks on top of code or sidebar contents
- v1.4.3 (Phase 2): pet reacts to where the cursor is (peek toward edits)
- v1.4.4: more objects (food bowl, box) and species-specific interaction sprites
- v1.4: environment objects (food bowl, ball, box) for richer pet interaction
MIT — see LICENSE.
Sprite asset credits: see LICENSES.md.