← Back to work

DeskPet

A desktop companion app — a transparent, always-on-top cat lives at the edge of your screen and gently reminds you to drink water and stretch.

Role · Solo developer 2026 Desktop app / Tauri Stack · Tauri 2 / Rust / React / TypeScript
DeskPet

A little cat sits at the edge of your screen: transparent, always on top, draggable. It rests, walks, gets picked up, talks to you, occasionally heads out — and at the right moments, gently reminds you to drink some water or stand up and stretch. The product is deliberately subtractive: no feeding, no leveling, no affection meters, no AI chat — companionship should be low-noise, and restraint is itself a product decision.

Built-in pet Jiaojiao: a fluffy white long-haired catBuilt-in pet Dimo

Two pets ship built-in — Jiaojiao and Dimo — and custom pet packs are supported: drop spritesheets and a manifest into a folder and you have a new pet, with versioned manifests (v1/v2) and forward-compatible unknown fields. Settings persist locally and restore on launch. It stays polite as a resident app: a tiny transparent window, preloaded spritesheets, low-frequency polling, and every timer and animation paused while hidden or away.

Engineering

Technical highlights

~4,400 lines of source, split between Rust and TypeScript by responsibility rather than by technology.

Three-layer boundaries

One iron rule throughout: Rust owns system and file concerns only (transparent always-on-top window, tray, settings I/O, pet-pack scanning); every visual state and animation behavior stays in TypeScript.

Testable behavior layer

The state machine is a pure reducer; scheduling, sprite parsing and edge bouncing are pure functions; anything touching the window goes through dependency injection — 132 tests run entirely without a real Tauri window.

Drag race-condition controller

Dragging must query the native window position asynchronously while pointer events arrive synchronously. A generation counter + pendingStart buffer + move coalescing resolves the race; a 6px threshold splits click from drag.

Defensive self-healing

Corrupted settings are clamped and repaired on both the Rust and TS sides; pack manifests canonicalize every file path to block ../ traversal; invalid packs are quarantined and reported instead of crashing the app.

DeskPet three-layer architecture: Pet Runtime (React/TS) calls the Rust/Tauri shell through a bridge, reading and writing settings and pet packs
Split by responsibility: invoke commands go down, events come up — behavior logic never touches the real window
132
automated tests (TS + Rust)
~4,400
lines of source
6
states in the pet state machine
2
built-in pets + custom packs

No feeding, no leveling, no AI chat — restraint is itself a product decision.

— Product principle
Next project
PodEcho →