About DevPet

The Inspiration

DevPet was born from a simple observation: coding alone, for hours on end, gets lonely.

I loved the idea of Tamagotchi as a kid; that little digital companion that lived on your keychain and reacted to how you treated it. I wanted that same feeling for developers. A pixel pal that sits on your desktop, watches you code, and makes those long solo sessions feel a little less isolated.

I was also frustrated by the lack of lightweight productivity tools. Most time-trackers are heavy, bloated, and distract from the actual coding. I wanted something that:

  • Stays out of your way (transparent, always-on-top, click-through)
  • React to what you do, not just track time
  • Helps you stay healthy (hydration, eye breaks, posture)
  • Celebrates your wins (achievements, streaks, personal bests)

How I Built It

Architecture Decision

I chose Tauri 2.0 over Electron for one reason: Rust.

Electron bundles an entire Chromium instance (~100MB+). Tauri uses the system's native WebView, keeping the bundle tiny. The Rust backend handles:

  • Native window management (transparent, always-on-top, ghost mode)
  • File system watching (detecting your code changes in real-time)
  • Active window detection (knowing when you're coding vs. slacking)

The frontend is Vanilla JavaScript with HTML5 Canvas; no frameworks, no dependencies. Just pure, fast DOM manipulation and pixel-perfect rendering.

The Momentum Algorithm

One of the core features is the Momentum Tracker, which maps your coding activity to 5 levels: cold → warming → flowing → hot → fire.

The algorithm uses an exponential decay model:

$$ M(t) = M_0 \cdot e^{-\lambda t} + \sum_{i=1}^{n} w_i \cdot e^{-\lambda (t - t_i)} $$

Where:

  • $M(t)$ is the momentum at time $t$
  • $\lambda$ is the decay constant (how quickly momentum fades when you stop coding)
  • $w_i$ is the weight of each file change event
  • $t_i$ is the timestamp of event $i$

In practice, this means:

  • Rapid edits → momentum spikes fast
  • Slow, thoughtful changes → steady growth
  • Going AFK → momentum decays gracefully (no harsh cutoffs)

Pixel Art & Animation

The character is rendered as a 32×32 pixel spritesheet at 4× scale (128×128 on screen). Each of the 16 animation states has its own row in the spritesheet:

State Row Frames Duration Array
idle 0 3 [200, 300, 250]
coding 1 4 [150, 200, 150, 200]
thinking 2 3 [300, 400, 350]

...

The spritesheet supports runtime palette swapping; skin tones are applied pixel-by-pixel via Canvas API, meaning you can have 12 unique skins with different color schemes without storing 12 separate images.

Procedural Audio

One of my favorite challenges: zero sound files. Every sound is synthesized in real-time using the Web Audio API:

  • 9 voice presets (mumble, squeaky, gruff, alien, robot, mystic, hyper, retro)
  • Each controls: pitch, waveform mix, syllable timing, formants, vibrato
  • Speech-like sounds generated via frequency modulation

The alien voice, for example, uses: $$ f(t) = A \cdot \sin(2\pi f_c t + I \cdot \sin(2\pi f_m t)) $$ Where $f_c$ is the carrier frequency, $f_m$ is the modulation frequency, and $I$ is the modulation index.

What I Learned

  1. Event-Driven Architecture is Powerful

All 80+ modules communicate through a central EventBus (pub/sub pattern). No module directly calls another. This means:

  • Decoupling: The ActivityMonitor doesn't need to know about AchievementSystem
  • Scalability: Adding a new feature is just: subscribe to events, emit your own
  • Debuggability: I can intercept any event and log it
  1. Rust + JavaScript is a Great Combo

Tauri's #[tauri::command] macro makes Rust functions available in JS with zero boilerplate:

#[tauri::command] fn scan_project_markers(dir_path: String) -> Result { // Rust backend doing heavy lifting }

const result = await invoke('scan_project_markers', { dirPath: '/home/sidd/myproject' });

  1. Pixel Art is Hard (But Rewarding)

Designing 16 animation states × up to 4 frames each = 64 unique frames. Each frame is 32×32 = 1,024 pixels to hand-tune. The sprite editor I built inside DevPet helps, but pixel art takes patience.

  1. Desktop Apps Have Unique Challenges
  • Cross-platform window management: macOS, Windows, and Linux all handle "always-on-top" and "transparent windows" differently
  • File system watching: notify-rs handles most cases, but network drives and WSL paths need special handling
  • Binary size matters: Tauri's ~8MB bundle vs. Electron's ~100MB+ makes a huge difference for downloads

Challenges I Faced

  1. The "Stuck Detector" Heuristic

Detecting when a developer is "spinning their wheels" (repeatedly editing the same file without progress) required tuning:

$$ \text{Stuck Score} = \frac{\text{Edits on same file}}{\text{Time window}} \times \text{Frustration multiplier} $$

Too sensitive → false positives. Too lenient → misses real stuck states. I ended up using a rolling window of 10 minutes with a threshold of 3+ edits to the same file.

  1. Claude Code Integration

Hooking into Claude Code's lifecycle (SessionStart, PostToolUse, SessionEnd) meant understanding:

  • How Claude Code's hook system works (~/.claude/settings.json)
  • Event timing (PostToolUse fires after every tool call)
  • State reconstruction (reading JSONL event logs to rebuild session context)

The result: DevPet can tell when you're in an AI pair programming session vs. coding solo — and celebrates when you and Claude ship something together.

  1. Cross-Platform Builds

Each platform has quirks:

  • macOS: Code signing, notarization, macOS-private-api for transparent windows
  • Windows: AppUserModelID for notification branding, Git Bash path detection
  • Linux: Wayland vs. X11 window management differences
  1. The Sprite Editor

Building a pixel art editor inside the app itself was a meta-challenge:

  • Frame navigation (next/prev with keyboard)
  • Color palette with live preview
  • Animation playback with FPS control
  • Minimap of the entire spritesheet

The trickiest part: canvas-to-canvas pixel copying with palette swapping in real-time.


What's Next?

DevPet is live at github.com/okottorika/DevPet. I'm working on:

  • More skins (community contributions welcome!)
  • Plugin system (let users write their own reaction handlers)
  • Discord Rich Presence (show your momentum level in your status)
  • Mobile companion app (check your coding streak from your phone)

Built With

Share this project:

Updates