A minimal desktop timer for deep work sessions. Pick a block, press start, get things done.
- Three focus blocks — 15 min, 30 min, 1 hour
- Circular progress ring with smooth countdown animation
- Ambient tick sound every second while running (3 styles or off)
- Bell alert when the session ends (3 styles or off)
- 6 color themes — Purple, Blue, Teal, Green, Amber, Rose
- Persistent settings — sound and theme choices survive restarts
- All audio is synthesised in real-time via the Web Audio API — no audio files bundled
Prerequisites: Node.js 18+ and npm.
git clone https://github.com/your-username/focus-timer.git
cd focus-timer
npm install
npm start| Action | How |
|---|---|
| Choose duration | Click 15 min, 30 min, or 1 hr |
| Start / Pause | Click the large play button |
| Reset | Click the reset (↺) button |
| Open settings | Click the ⚙ icon (top right) |
| Close settings | Click ← or press Esc |
Tick Sound — the soft sound that plays every second:
| Option | Character |
|---|---|
| Tik (default) | Triangle wave sweep, 1100 → 500 Hz |
| Click | Short sine pulse at 1800 Hz |
| Deep | Low triangle sweep, 380 → 180 Hz |
| Off | Silent |
Bell Sound — plays when the session ends:
| Option | Character |
|---|---|
| Chime (default) | C major arpeggio (C5 → E5 → G5 → C6), 3.5 s decay |
| Bell | Single tone with inharmonic partials (440 / 1213 / 2376 Hz), 5 s decay |
| Triple | Three quick ascending pings (C–E–G) |
| Off | Silent |
Plain Electron, no framework, no bundler.
main.js Electron main process — creates the BrowserWindow
index.html UI layout and SVG ring markup
styles.css Dark theme, CSS custom properties for theming
renderer.js All app logic: timer state machine, Web Audio synthesis, settings
The renderer runs with nodeIntegration: true / contextIsolation: false (no external content is loaded).
Timer states: idle → running → paused → running → done. State is a CSS class on #timerContainer; all visual changes (ring animation, glow, status text) are driven by CSS selectors off that class.
Theming: 11 CSS custom properties on :root are recomputed from a single hue value by applyTheme(hue) in renderer.js. The SVG gradient uses style="stop-color: var(--a1)" so it picks up theme changes without any JS.
Audio: AudioContext is lazy-initialised on the first user gesture. All sounds (tick and bell) are synthesised from oscillators and gain envelopes — no audio files.
Pre-built binaries for macOS and Windows are available on the Releases page.
To build locally:
# macOS — produces a Universal binary (Intel + Apple Silicon) in dist/
npm run build:mac
# Windows — produces an NSIS installer + portable .exe in dist/
npm run build:winNote: Building the Windows installer (NSIS) on macOS requires Wine. For cross-platform builds without a local Wine install, push a tag — GitHub Actions will build both platforms automatically and attach the artifacts to a Release.
git tag v1.0.0
git push origin v1.0.0The release.yml workflow triggers on any v* tag, builds macOS (Universal DMG + ZIP) and Windows (x64/arm64 NSIS + portable) on their respective runners, then publishes a GitHub Release with all artifacts attached.
- Fork the repository
- Create a feature branch:
git checkout -b feat/your-feature - Commit your changes:
git commit -m 'feat: add your feature' - Push and open a pull request
Bug reports and feature requests are welcome via Issues.

