Skip to content

About

Motion-first Pomodoro focus app — rain-on-glass timer, reminders, tasks and streak stats. FastAPI + SQLite, no build step.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Repository files navigation

Focus 🌧️

CI

A motion-first focus web app — Pomodoro timer, reminders, focus tasks and streak tracking, built around a rain-on-glass porthole that clears as you work. One Python process, one SQLite file, no build step, no npm.

Grown from Youth Reminder App, the small Tkinter reminder tool that used to live in this repo. That version is still in the history (and remainder_app_py), and its three quick presets — Study Break, Workout, Chill Time — are still here on the Reminders page.

The timer, light theme

Screenshots

Timer, night rain theme Stats
Timer — the pane fogs at the start and clears as the session elapses; a progress arc fills the rim. Stats — today's focus, day streak, totals, and an animated 7-day chart.

Reminders

Tasks

Stack

  • Backend: FastAPI + Jinja2 (server-rendered pages plus a small JSON API), SQLite. Single-user, no login.
  • Frontend: Tailwind (standalone, vendored) + anime.js v4 (vendored). No bundler, no npm.
  • Design: "rainy paper" — warm kraft surfaces, espresso ink, a muted rain slate-blue accent. Controls are embossed from the sheet (soft-UI / neumorphism) rather than boxed on top of it: no hard borders, a highlight up-left and a warm shade down-right, and buttons that press in on :active. Light kraft "day" is the default; a warm "night rain" theme lives under .dark. Reduced motion and reduced transparency are respected throughout.

Run

python -m venv .venv && .venv/Scripts/python -m pip install -r requirements.txt   # Windows
# (macOS/Linux: source .venv/bin/activate && pip install -r requirements.txt)
.venv/Scripts/python -m uvicorn app:app --reload

Open http://127.0.0.1:8000 — /styleguide shows the design system.

Optional: drop any looping rain recording at static/audio/rain.mp3 for the ambient track. It's gitignored (a ~24MB binary), and the app is missing-file-safe without it — the switch simply plays nothing.

Test

.venv/Scripts/python -m pytest -q          # 46 tests: pure logic, the HTTP layer, and the CSS guard
python focus.py && python reminders.py     # inline self-checks

tests/test_focus.py and tests/test_reminders.py cover the pure modules; tests/test_api.py drives every route through TestClient against a temp SQLite file; tests/test_css.py guards the theme against a silent CSS parse failure (see Known ceilings).

Features

  • Timer — Focus/Break/Deep presets plus custom minutes via a ± stepper. The countdown runs on a circular rain-on-glass porthole: condensation fogs the pane at the start and clears as the session elapses, rain streaks run down the glass, a progress arc fills the rim, and a ripple blooms on completion. Sessions are logged to the DB; a browser notification fires on finish.
  • Ambient rain — a header toggle switch. Start turns it on with the session; Pause and Reset turn it back off. Switching mode or finishing a session leaves it playing. State persists in localStorage.
  • Reminders — custom (message + h/m) plus the original app's quick presets, once/daily/weekly recurrence, snooze; notifications fire while a tab is open.
  • Tasks — a focus list; pick a task on the timer to log time against it.
  • Stats — today's focus, day streak, totals, and an animated 7-day bar chart.

Only completed focus sessions count toward streaks and totals — breaks and abandoned sessions are stored but excluded from every stat (focus._focus).

Known ceilings

  • Notifications fire only while a Focus tab is open (in-tab poll + Notification API). Closed-tab firing needs a service worker + Web Push + a server scheduler.
  • The countdown runs on an interval, so it keeps going in a background tab — but browsers throttle hidden-tab timers to roughly once a minute, so a completion notification can arrive up to a minute late if you never return to the tab. The clock itself is wall-clock derived and always correct on return.
  • The <select> option list is drawn by the OS and can't be styled; it follows color-scheme, which is why that is declared on :root and .dark.
  • A stray */ inside a CSS comment silently deletes the rule that follows it — that once cost the whole light theme. tests/test_css.py now fails if one reappears.
  • Tailwind standalone (no purge/build); fonts via Google Fonts CDN — self-host if offline matters.
  • Single-user by design: no auth, one SQLite file, no multi-device sync.

Layout

app.py (routes + API) · db.py (SQLite) · focus.py / reminders.py (pure, tested logic) · templates/ · static/{css,js,vendor,audio} · tests/ · docs/ (README images).

Design tokens live in static/css/tokens.css (HSL custom properties plus the soft-UI and rain/glass primitives); the shared motion vocabulary is static/js/motion.js.

About

Motion-first Pomodoro focus app — rain-on-glass timer, reminders, tasks and streak stats. FastAPI + SQLite, no build step.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages