Skip to content

About

A whimsical desktop time-tracker that lives in your tray — glassmorphic widget, custom weekly rounding, idle detection.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Chronoscribe logo — a glowing violet orb

Chronoscribe

A whimsical little familiar that lives in your tray and keeps your ledger of hours.

platform tauri react rust license


Chronoscribe is a real, packaged desktop time-tracking app — not a script, not a browser tab. It's a tiny glassmorphic widget that docks itself to the top-right corner of your screen with one job: Start and Stop. Click it and it expands into a full dashboard for editing entries, browsing past weeks, and watching your Familiar breathe while it keeps count.

Everything runs locally. Your hours live in a SQLite file on your own disk — nothing is sent anywhere.

Why it exists

Most time trackers ask you to open an app, find a project, click into a timer view, and then start tracking. Chronoscribe's whole premise is that starting and stopping a timer should be as fast as glancing at a clock — so the entire "start tracking" interaction is one click on a widget that's already sitting in the corner of your screen, always. The dashboard exists for everything else: fixing a forgotten clock-in, trimming a session you left running overnight, or seeing how the week shaped up.

Features

  • The floating widget — an always-on-top, borderless, transparent glass pill docked to your screen's top-right corner. Click Start/Stop. Hover to reveal an expand button that opens the full dashboard.
  • The Familiar — the little orb at the widget's heart. It breathes slowly and glows violet when idle; when you're tracking, it quickens, turns ember-orange, and pulses outward rings. Pure decoration, but it's the detail that makes this feel alive instead of like a stopwatch.
  • The Dashboard — a full glassmorphic window (This Week / History tabs) for reviewing and editing your ledger.
  • Full CRUD on sessions — forgot to clock in? Add 3 hours manually, backdated to any time. Left it running overnight? Edit the entry down, or delete it outright.
  • Custom weekly rounding — end-of-week totals round to the nearest hour using a 15-minute threshold: 5:14 rounds down to 5h, 5:15 rounds up to 6h. This is a deliberate payroll-style rule, not Math.round.
  • Weeks auto-archive on rollover — the live counter is always just the current week's total; past weeks close automatically and move to History.
  • The Weekly Chronicle — an auto-generated recap card with a bit of flavor text summarizing the week, showing both the raw and rounded total.
  • Idle Nudge — two-stage, both measured from the same idle stretch:
    • 45 min idle while tracking: the widget grows a banner ("the scribe grew restless — still working?") plus a system notification. The session keeps counting; ignoring it changes nothing.
    • 60 min idle (i.e. the 45-min nudge went unanswered and idle continued another 15 min): the session auto-stops, exactly as if you'd clicked Stop right then, and the banner switches to a "the scribe dozed off — stopped the clock" choice.
    • Either banner offers Keep it all (leave the full idle-inclusive duration — the default, and what happens if you never respond) or Trim idle time (cut the idle stretch off the end). (Windows only for now — see Roadmap.)
  • Global hotkey — Ctrl+Shift+K starts/stops tracking from anywhere, even with the widget out of focus.
  • Launch at login — Chronoscribe registers itself to start automatically when you log in (toggleable any time from the tray menu — "Launch at Login"), so it's just there, the way a tray app should be.
  • Lives entirely in the tray — no taskbar icon, no dock clutter. Quit from the tray icon's context menu.

Screenshots

The Chronoscribe widget, docked to the top-right corner, mid-session

The Chronoscribe dashboard, showing the current week's ledger

Stack

Layer Choice Why
Shell Tauri v2 (Rust) Native tray/multi-window support, ~10–15MB installer vs. Electron's 150MB+, low idle memory footprint — important for something that runs 24/7
UI React 18 + TypeScript
Styling Tailwind CSS glassmorphism theme, dark mode, custom color tokens
Motion Framer Motion the breathing Familiar, spring transitions, layout animations
Database SQLite, via tauri-plugin-sql local-only, zero-config, transactional
Icons lucide-react

Project structure

chronoscribe/
├── src/                          # React frontend (shared by both windows)
│   ├── widget/                    # The floating pill
│   │   ├── Widget.tsx               # Start/Stop, live clock, idle-nudge banner
│   │   ├── Familiar.tsx             # the breathing/pulsing orb
│   │   └── IdleNudge.tsx            # the "still working?" banner
│   ├── dashboard/                 # The expanded ledger view
│   │   ├── Dashboard.tsx            # tabs, layout, data loading
│   │   └── components/
│   │       ├── ChronicleCard.tsx      # weekly recap card
│   │       ├── SessionList.tsx        # this week's entries
│   │       ├── SessionEditor.tsx      # add/edit modal (manual CRUD)
│   │       └── HistoryPanel.tsx       # past weeks
│   ├── db/
│   │   ├── client.ts                # shared SQLite connection
│   │   └── sessions.ts              # all session/week queries + rounding hookup
│   ├── lib/
│   │   ├── rounding.ts              # the 15-minute weekly rounding rule
│   │   └── week.ts                  # week-boundary math (Mon–Sun)
│   └── index.css                    # glassmorphism theme, Tailwind layers
├── src-tauri/                    # Rust backend
│   ├── src/lib.rs                   # tray icon, windows, global shortcut,
│   │                                 # idle watcher, autostart, Tauri commands
│   ├── migrations/001_init.sql      # SQLite schema
│   ├── capabilities/default.json    # Tauri v2 permission grants
│   ├── icons/                       # app/tray icons
│   └── tauri.conf.json              # window configs (widget + dashboard)
├── dev-mock/                     # browser-only stand-ins for the Tauri API,
│                                    # used only by `npm run dev:mock`
├── assets/                       # logo + README screenshots
├── widget.html                   # entry point for the widget window
├── dashboard.html                # entry point for the dashboard window
└── package.json

Database schema

sessions — every tracked interval. A row with end_time IS NULL is the one currently-running session (enforced by a partial unique index — SQLite can't have two active sessions at once).

column type notes
id INTEGER primary key
start_time TEXT ISO 8601
end_time TEXT NULL while running
duration_seconds INTEGER NULL while running
is_manual INTEGER 0/1 — manually added vs. tracked live
note TEXT optional
week_start TEXT Monday of that week, yyyy-MM-dd (denormalized for fast weekly queries)
created_at / updated_at TEXT ISO 8601

weeks — one row per week, summarized and archived on rollover.

column type notes
week_start TEXT primary key, yyyy-MM-dd
week_end TEXT
total_seconds INTEGER raw sum of that week's sessions
rounded_minutes INTEGER after the 15-minute rounding rule
closed_at TEXT NULL = current/live week

Getting started

Prerequisites:

  • Node.js 18+
  • Rust (stable, MSVC toolchain on Windows)
  • The Tauri prerequisites for your OS — on Windows, that's the MSVC C++ Build Tools (with the Windows 10/11 SDK component — easy to miss, since the compiler can be present without it) and the WebView2 Runtime (preinstalled on Windows 11).
npm install
npm run tauri dev

This launches the widget docked to your screen's top-right corner. Click it to open the dashboard, or use Ctrl+Shift+K to start/stop from anywhere.

To build the production app + installer:

npm run tauri build

The installer and standalone .exe land in src-tauri/target/release/bundle/. Chronoscribe registers itself to launch at login on first run (toggleable from the tray menu).

Browser-only preview (no Rust needed)

For quick visual iteration on styling/animation without the Rust toolchain, dev-mock/ provides in-memory stand-ins for the Tauri/SQLite APIs:

npm run dev:mock

Then open http://localhost:1420/widget.html or .../dashboard.html directly in a browser. This is dev-only tooling — npm run build and npm run tauri dev never touch it, and it never ships in the packaged app.

Icons

The tray/app icons in src-tauri/icons/ are a generated violet orb matching the Familiar — good enough for Windows dev/build. Before shipping cross-platform, regenerate the full set (including .icns for macOS) from a 1024×1024 master image:

npx tauri icon path/to/master-icon.png

Known platform notes

  • WebView2 + OneDrive-synced project folders: if your project directory is live-synced (OneDrive, Dropbox, etc.), set WEBVIEW2_USER_DATA_FOLDER to a non-synced path (e.g. %LOCALAPPDATA%\chronoscribe-webview2) before running tauri dev/tauri build. Sync clients can interfere with WebView2's runtime cache.
  • Dashboard window: it's declared statically in tauri.conf.json (hidden until opened) rather than built dynamically at runtime — creating a second Tauri window on demand was unreliable on Windows (the WebView2 control could fail to attach). If you add more windows, prefer this same pattern: declare in config, toggle visibility, don't WebviewWindowBuilder::build() post-startup.

Roadmap

  • macOS (CGEventSourceSecondsSinceLastEventType) / Linux (X11 XScreenSaverQueryInfo) idle detection — get_idle_seconds() in src-tauri/src/lib.rs currently only implements Windows and stubs everything else to 0 (Idle Nudge silently disabled)
  • CSV/PDF export of the weekly Chronicle for payroll
  • Sound design: soft chime on start/stop (toggleable)
  • Configurable week-start day / rounding threshold / idle timeouts in a settings panel (currently constants: WEEK_STARTS_ON in src/lib/week.ts, IDLE_NUDGE_THRESHOLD_SECS / IDLE_AUTOSTOP_THRESHOLD_SECS in src-tauri/src/lib.rs)

About

A whimsical desktop time-tracker that lives in your tray — glassmorphic widget, custom weekly rounding, idle detection.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages