Vahag Byurat  ·  All Projects
Rust · egui / eframe · Native + WASM

Tomato Dragon

A playful Pomodoro timer with task tracking, session controls and progress analytics: one Rust codebase that compiles to a native desktop window and to a browser canvas.

v0.1.0 alpha egui 0.29 Native + WASM 58 tests
Tomato Dragon icon
The app

A timer that keeps the receipts

Most Pomodoro timers count down and forget. Tomato Dragon writes every round to disk as it happens (which phase it was, how long it actually ran, and whether you skipped out of it early), so the history you look at afterwards is the history that happened, not a tidy reconstruction of it.

The whole thing is one immediate-mode egui tree. There is no DOM, no template layer and no state library: the UI is a pure function of the timer, task and stats structs, redrawn every frame.

Tomato Dragon interface: a countdown ring at 18:42 with pause and skip controls, a row of five tomato pips, and a stats sidebar showing today's count, a weekly bar chart and a recent-rounds list.
The primary view. Timer ring and dragon companion on the left; the stats sidebar on the right carries the daily count, the weekly graph and the recent-rounds log.

Features

Four things it actually does

Timer and sessions

Work and break phases with numbered sessions, and a start / pause / reset / skip control set. Sessions can also be started by hand rather than rolling on automatically.

Task tracking

Tasks carry state across rounds and persist between launches through eframe’s storage layer, so closing the window does not reset the day.

Stats with switches

Two graph modes, This Week and Sessions, with independent Work and Breaks toggles. Rounds you skipped out of are logged and labelled as skipped rather than dropped.

Your data, movable

Backup, restore and reset, each behind a confirmation step, plus a JSON report you can generate and save if you want to chart the numbers somewhere other than the app.


Settings

The tomato budget

A daily tomato goal, and a policy for when that counter goes back to zero. The three policies are the whole configuration surface. The names are the ones the app ships with.

Erry Day
Counter resets at the day boundary. This is the default.
Erry Sess
Counter resets at the start of each new session.
Never
Counter accumulates for as long as the data file lives.

Stack

One codebase, two render targets

The same crate builds for the desktop and for the browser. Platform differences are confined to two cfg-gated dependency blocks; everything above them (timer, tasks, stats, storage) is shared.

egui / eframe 0.29Immediate-mode UI, glow renderer, accesskit enabled for platform accessibility
Rust 1.76+Edition 2021; release profile builds with LTO
serde · serde_jsonSettings, stats and the saved report
chronoDay boundaries and week bucketing for the graphs
Native onlynotify-rust for desktop notifications, directories for the data path
WASM onlywasm-bindgen and web-sys, with the browser Notification API in place of notify-rust
Status: alpha, unreleased

Version 0.1.0. The desktop and WASM targets both build and the test suite (58 tests) runs in the pre-push gate, but there are no tagged releases yet: no installer, no hosted demo, and the repository is private.

Listing platform download buttons before any build has been published would be inviting you to click nothing, so there are none here. Ask me for a build and I will send you one.

Written mostly to find out what an immediate-mode GUI feels like to maintain once it grows past a demo, and the honest answer is that the redraw-everything model stays pleasant far longer than expected, right up until you want a scroll position to survive a state change.