---
## π‘ Why does this exist?
Repetitive strain injury and eye strain are not personal failings. They are the predictable result of systems that treat human attention as an extractable resource. Every person at a screen deserves a tool that gently interrupts the grind - one that serves *them*, not a subscription model, not an analytics dashboard, not a corporate wellness KPI.
Core Cooldown is a single portable `.exe`. No installer, no account, no telemetry, no data leaving your machine. Drop it in a folder and run it. It reminds you to rest. That's it.
---
## π§ Philosophy
Core Cooldown exists because rest is not a luxury. It is a fundamental need that no productivity framework, no employer, and no software platform should gatekeep behind a paywall or a subscription.
This application:
- **Collects nothing.** No analytics, no telemetry, no usage tracking, no crash reports phoned home. Your break habits are your own business.
- **Costs nothing.** Not "free tier with limitations." Not "free for personal use." Free, unconditionally, for everyone.
- **Requires nothing.** No account, no email, no app store, no internet connection after download. It runs on your machine and answers to you alone.
- **Owns nothing.** Released under CC0 - the most complete relinquishment of rights possible under law. There is no owner. There are no restrictions. The code belongs to the commons.
Tools for human wellbeing should never be enclosed, never be scarce, and never serve a master other than the person using them.
---
## πΈ Screenshots
Dashboard - Focus timer with countdown ring, status pill, pomodoro dots, and quick controls
Statistics - Daily summary, compliance rate, streaks, and 7-day history chart
Settings - 18 grouped configuration cards with live preview
Break Screen - Always-on-top break overlay with breathing guide and activity suggestions
Mini Mode - Compact floating timer, click-through until hovered
Core Cooldown targets **WCAG 2.2 Level AAA** conformance - the highest level of the Web Content Accessibility Guidelines. A break timer for preventing repetitive strain injury should be usable by everyone, including those who already live with disabilities.
> **Why AAA?** Most applications stop at AA. We went further because the people who benefit most from a break timer - those with repetitive strain injuries, chronic pain, or vision impairments - are the same people who need the strongest accessibility support. AAA isn't a checkbox. It's the right thing to do.
#### Contrast & Visual Design
| | Feature | Standard | Description |
|:--|:--------|:---------|:------------|
| π¨ | **Enhanced text contrast** | AAA 7:1 | All body text meets 7:1 contrast ratio against dark backgrounds. Secondary text `#a8a8a8` on `#000` = 7.28:1. |
| π€ | **Large text contrast** | AAA 4.5:1 | Headings and large text (18px+) meet 4.5:1 minimum. Timer countdown, break titles validated. |
| π― | **Non-text contrast** | AA 3:1 | UI components (toggles, steppers, rings, chart bars, color swatches) all meet 3:1 against adjacent colors. |
| π₯οΈ | **Windows High Contrast** | AAA | `forced-colors: active` maps all theme tokens to system colors. Full usability in all Windows contrast themes. |
| π’ | **Reduced motion** | AAA | `prefers-reduced-motion` disables all CSS animations, JS Web Animations API effects, and momentum scroll. Zero functionality loss. |
#### Keyboard & Navigation
| | Feature | Standard | Description |
|:--|:--------|:---------|:------------|
| β¨οΈ | **Full keyboard access** | AAA 2.1.3 | Every control operable via keyboard alone - no exceptions. Arrow keys for color pickers, steppers, radio groups. Tab/Shift+Tab cycles all interactive elements. |
| π | **Visible focus indicators** | AAA 2.4.13 | 2px solid white outline with dark shadow fallback on every interactive element. No hidden or suppressed focus rings. |
| βοΈ | **Skip navigation** | AA 2.4.1 | Skip-to-content link bypasses the titlebar on Tab. |
| π | **Focus management** | AA 2.4.3 | View transitions auto-focus the new view's heading. Break screen traps focus. Dropdown focus returns to trigger on close. |
| π·οΈ | **Heading structure** | AAA 2.4.10 | Semantic `h1` > `h2` hierarchy across all views. Settings sections use `h2` with `aria-labelledby`. |
#### Screen Readers & Assistive Technology
| | Feature | Standard | Description |
|:--|:--------|:---------|:------------|
| π£οΈ | **Live regions** | AA 4.1.3 | `aria-live` announces timer state, breathing phase, break activities, status changes, and celebration events. |
| π | **Semantic roles** | AA 4.1.2 | `progressbar` on timer rings, `switch` on toggles, `tablist`/`tab`/`tabpanel` on stats view, `radiogroup`/`radio` on breathing patterns, `alertdialog` on overlays. |
| π | **Data tables** | A 1.3.1 | Screen-reader-only data tables behind the 7-day chart provide the same information non-visually. |
| π·οΈ | **Accessible names** | AA 4.1.2 | Every toggle, stepper, button, swatch, and form control has a descriptive `aria-label` or visible label. Sound presets use `aria-pressed`. |
| π | **Page titles** | AAA 2.4.2 | Dynamic `document.title` updates per view ("Core Cooldown - Dashboard", "- Settings", etc.). |
#### Target Sizes & Interaction
| | Feature | Standard | Description |
|:--|:--------|:---------|:------------|
| π | **44px touch targets** | AAA 2.5.8 | All interactive elements (buttons, toggles, steppers, color swatches, titlebar controls) have minimum 44x44px hit areas. Visual size may be smaller - the clickable area extends invisibly. |
| π― | **Celebration persistence** | - | Milestone/goal popups stay visible on hover or focus, with keyboard-accessible dismiss buttons and Escape key support. |
| β±οΈ | **Hold-to-repeat** | - | Stepper +/- buttons support press-and-hold for continuous increment, with keyboard Enter/Space triggering the same behavior. |
---
## π¦ Portability
Core Cooldown is **fully portable**. The executable carries everything it needs and stores everything it creates right next to itself:
```
anywhere-you-want/
βββ core-cooldown.exe <- the application
βββ config.json <- your settings (auto-created on first run)
βββ stats.json <- your break history (auto-created on first run)
βββ data/ <- WebView2 runtime data (auto-created on first run)
```
- No installer
- No registry entries
- No writes to `%APPDATA%`, `%LOCALAPPDATA%`, or any system directory
- Move the folder anywhere - USB stick, shared drive, different machine
- Nothing to uninstall - delete the folder and it's gone, zero traces
---
## π Installation
```
1. Download core-cooldown.exe from the Releases page
2. Put it in any folder you like
3. Run it
```
That's it. No elevated permissions. No runtime dependencies. The first launch may take a moment while Windows initializes the WebView2 runtime.
**[Download latest release](https://git.lashman.live/lashman/core-cooldown/releases)**
---
## π§ Building from Source
Prerequisites
- **Node.js** (v18+) and **npm**
- **Rust** toolchain (`rustup`) with the `x86_64-pc-windows-gnu` target
- **MinGW-w64** - the GNU toolchain for Windows (provides linker, windres, dlltool)
### Setup
```bash
git clone https://git.lashman.live/lashman/core-cooldown.git
cd core-cooldown
npm install
```
### Linker Configuration
Create or edit `src-tauri/.cargo/config.toml` to point to your MinGW installation:
```toml
[build]
target = "x86_64-pc-windows-gnu"
[target.x86_64-pc-windows-gnu]
linker = "C:/path/to/mingw64/bin/gcc.exe"
ar = "C:/path/to/mingw64/bin/ar.exe"
```
### Development
```bash
# Launch with hot-reload
npm run tauri dev
# Rust check (no full build)
cd src-tauri && cargo check
# Frontend only (no Tauri shell)
npm run dev
```
### Release Build
```bash
npm run tauri build
```
Output: `src-tauri/target/x86_64-pc-windows-gnu/release/core-cooldown.exe`
---
## ποΈ Architecture
A split-architecture desktop app: Rust backend for system integration and timer logic, Svelte frontend rendered in a native WebView.
```
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β System Tray β
β (dynamic icon Β· tooltip Β· menu) β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββ βββββββββββββββ βββββββββββββββ β
β β Main Window β β Break Windowβ β Mini Window β β
β β (WebView) β β (WebView) β β (WebView) β β
β ββββββββ¬βββββββ ββββββββ¬βββββββ ββββββββ¬βββββββ β
β β β β β
β βββββββββββ¬βββββββββ΄βββββββββββββββββββ β
β β Tauri IPC β
β βββββββββββ΄ββββββββββ β
β β Rust Backend β β
β β β β
β β TimerManager β state machine (1 tick/sec) β
β β Config β JSON persistence (portable) β
β β Stats β break history tracking β
β β IdleDetector β GetLastInputInfo polling β
β β GlobalShortcuts β Ctrl+Shift+P/B/S β
β β TrayIcon β RGBA ring rendering β
β β Notifications β Windows toast β
β βββββββββββββββββββββ β
β β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
Backend modules (Rust)
| Module | Responsibility |
|:-------|:---------------|
| `lib.rs` | Tauri app builder, command registration, tray setup, timer tick thread, window management, global shortcuts, screen dim events, microbreak events, presentation mode detection |
| `config.rs` | Config struct (75 fields) with serde serialization, validation (clamping all values to safe ranges), portable file I/O |
| `timer.rs` | Timer state machine (`Running` / `Paused` / `BreakActive`), idle detection via Windows API, working hours enforcement, pomodoro cycle tracking, microbreak scheduling, presentation mode deferral |
| `stats.rs` | Daily break statistics, streak calculation, daily goal tracking, history queries, weekly summaries |
| `main.rs` | Entry point, WebView2 Runtime detection |
| `msvc_compat.rs` | MSVC CRT compatibility stubs for static WebView2Loader linking on MinGW |
Frontend layers (Svelte 5 + TypeScript)
| Layer | Files |
|:------|:------|
| **Views** | `Dashboard`, `BreakScreen`, `Settings`, `StatsView` |
| **Windows** | `BreakWindow` (standalone break modal), `MiniTimer` (floating mini mode) |
| **Overlays** | `BreakOverlay` (break enforcement), `MicrobreakOverlay` (eye break), `DimOverlay` (screen dimming), `Celebration` (confetti) |
| **Components** | `TimerRing`, `Titlebar`, `ToggleSwitch`, `Stepper`, `ColorPicker`, `FontSelector`, `TimeSpinner`, `BackgroundBlobs`, `BreathingGuide`, `ActivityManager` |
| **Stores** | `timer.ts` (reactive timer state from IPC events), `config.ts` (config with debounced auto-save) |
| **Utilities** | `sounds.ts` (Web Audio synthesis), `activities.ts` (71 break activities), `animate.ts` (motion library: fadeIn, scaleIn, inView, pressable, glowHover, dragScroll) |
IPC contract
**Commands** (frontend -> backend):
`get_config` Β· `save_config` Β· `update_pending_config` Β· `reset_config` Β· `toggle_timer` Β· `start_break_now` Β· `cancel_break` Β· `snooze` Β· `get_timer_state` Β· `set_view` Β· `get_stats` Β· `get_daily_history` Β· `get_weekly_summary` Β· `set_auto_start` Β· `get_auto_start_status` Β· `get_cursor_position` Β· `save_window_position`
**Events** (backend -> frontend):
`timer-tick` Β· `break-started` Β· `break-ended` Β· `prebreak-warning` Β· `config-changed` Β· `natural-break-detected` Β· `screen-dim-update` Β· `microbreak-started` Β· `microbreak-ended` Β· `milestone-reached` Β· `daily-goal-met` Β· `break-deferred`
---
## βοΈ Configuration Reference
All settings stored in `config.json` next to the executable. The settings panel exposes every option with live validation, but the file is plain JSON and can be edited by hand.
Full configuration schema (71 keys)
**Timer**
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `break_duration` | `u32` | `5` | Duration of each break (1-60 min) |
| `break_frequency` | `u32` | `25` | Interval between breaks (5-120 min) |
| `auto_start` | `bool` | `true` | Start timer on launch |
**Pomodoro**
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `pomodoro_enabled` | `bool` | `false` | Enable Pomodoro mode |
| `pomodoro_short_breaks` | `u32` | `3` | Short breaks before long (1-10) |
| `pomodoro_long_break_duration` | `u32` | `15` | Long break duration (5-60 min) |
| `pomodoro_long_break_title` | `string` | `"Long break"` | Long break title |
| `pomodoro_long_break_message` | `string` | `"Great work!..."` | Long break message |
| `pomodoro_reset_on_skip` | `bool` | `false` | Reset cycle when skipping |
**Microbreaks**
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `microbreak_enabled` | `bool` | `false` | Enable 20-20-20 eye breaks |
| `microbreak_frequency` | `u32` | `20` | Microbreak interval (5-60 min) |
| `microbreak_duration` | `u32` | `20` | Microbreak duration (10-60 sec) |
| `microbreak_sound_enabled` | `bool` | `true` | Play sound on microbreak |
| `microbreak_show_activity` | `bool` | `true` | Show activity during microbreak |
| `microbreak_pause_during_break` | `bool` | `true` | No microbreaks during main breaks |
**Break Screen**
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `break_title` | `string` | `"Rest your eyes"` | Title shown on break screen |
| `break_message` | `string` | `"Look away..."` | Message shown during breaks |
| `fullscreen_mode` | `bool` | `true` | Use fullscreen break window |
| `multi_monitor_break` | `bool` | `true` | Show overlay on all monitors |
| `show_break_activities` | `bool` | `true` | Show activity suggestions |
**Activities**
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `custom_activities` | `array` | `[]` | User-created activities |
| `disabled_builtin_activities` | `array` | `[]` | Disabled built-in activities |
| `favorite_builtin_activities` | `array` | `[]` | Favorited built-in activities |
| `favorite_weight` | `u32` | `3` | How much more often favorites appear |
**Breathing Guide**
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `breathing_guide_enabled` | `bool` | `true` | Show breathing guide during breaks |
| `breathing_pattern` | `string` | `"box"` | Breathing pattern (box/relaxing/energizing/calm/deep) |
**Behavior**
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `strict_mode` | `bool` | `false` | Remove skip/cancel buttons |
| `allow_end_early` | `bool` | `true` | Allow ending break after 50% |
| `immediately_start_breaks` | `bool` | `false` | Skip pre-break notification |
| `snooze_duration` | `u32` | `5` | Snooze delay (1-30 min) |
| `snooze_limit` | `u32` | `3` | Max snoozes per cycle (0-5) |
**Alerts**
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `notification_enabled` | `bool` | `true` | Enable toast notifications |
| `notification_before_break` | `u32` | `30` | Pre-break warning (0-300 sec) |
| `screen_dim_enabled` | `bool` | `false` | Gradually dim screen before breaks |
| `screen_dim_seconds` | `u32` | `10` | Start dimming N seconds before break |
| `screen_dim_max_opacity` | `f32` | `0.3` | Maximum dim intensity (10-70%) |
**Sound**
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `sound_enabled` | `bool` | `true` | Play notification sounds |
| `sound_volume` | `u32` | `70` | Volume (0-100%) |
| `sound_preset` | `string` | `"bell"` | Sound preset |
**Idle & Smart Breaks**
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `idle_detection_enabled` | `bool` | `true` | Enable idle auto-pause |
| `idle_timeout` | `u32` | `120` | Idle threshold (30-600 sec) |
| `smart_breaks_enabled` | `bool` | `true` | Detect natural breaks |
| `smart_break_threshold` | `u32` | `300` | Natural break threshold (120-900 sec) |
| `smart_break_count_stats` | `bool` | `false` | Count natural breaks in stats |
**Presentation Mode**
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `presentation_mode_enabled` | `bool` | `true` | Defer breaks during fullscreen apps |
| `presentation_mode_defer_microbreaks` | `bool` | `true` | Also defer microbreaks |
| `presentation_mode_notification` | `bool` | `true` | Show toast when break deferred |
**Goals & Streaks**
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `daily_goal_enabled` | `bool` | `true` | Track daily break target |
| `daily_goal_breaks` | `u32` | `8` | Target breaks per day (1-30) |
| `milestone_celebrations` | `bool` | `true` | Confetti on milestones |
| `streak_notifications` | `bool` | `true` | Toast on streak milestones |
**Appearance**
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `ui_zoom` | `u32` | `100` | Interface zoom (50-200%) |
| `accent_color` | `string` | `"#ff4d00"` | Main accent color |
| `break_color` | `string` | `"#7c6aef"` | Break screen ring color |
| `countdown_font` | `string` | `""` | Google Font for countdown |
| `background_blobs_enabled` | `bool` | `false` | Animated background blobs |
**Working Hours**
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `working_hours_enabled` | `bool` | `false` | Restrict timer to schedule |
| `working_hours_schedule` | `array` | Mon-Fri 09-18 | Per-day time ranges |
**Mini Mode**
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `mini_click_through` | `bool` | `true` | Mini mode click-through |
| `mini_hover_threshold` | `f32` | `3.0` | Hover delay before drag (1-10 sec) |
**General**
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `auto_start_on_login` | `bool` | `false` | Launch on Windows startup |
**Window Position (internal)**
| Key | Type | Default | Description |
|:----|:-----|:--------|:------------|
| `main_window_x` | `i32?` | `null` | Main window X position |
| `main_window_y` | `i32?` | `null` | Main window Y position |
| `main_window_width` | `u32?` | `null` | Main window width |
| `main_window_height` | `u32?` | `null` | Main window height |
| `mini_window_x` | `i32?` | `null` | Mini window X position |
| `mini_window_y` | `i32?` | `null` | Mini window Y position |
---
## π Dependencies
Rust crates
| Crate | Purpose |
|:------|:--------|
| `tauri 2` | Application shell, IPC, multi-window, system tray |
| `tauri-plugin-shell 2` | Shell integration |
| `tauri-plugin-notification 2` | Windows toast notifications |
| `tauri-plugin-global-shortcut 2` | System-wide keyboard shortcuts |
| `serde` / `serde_json` | Config and stats serialization |
| `chrono` | Date/time handling for schedules and statistics |
| `anyhow` | Error handling |
| `winapi` | Windows idle detection (`GetLastInputInfo`), WebView2 check dialog |
JavaScript packages
| Package | Purpose |
|:--------|:--------|
| `@tauri-apps/api` | Frontend IPC bindings |
| `svelte 5` | Reactive UI framework (runes: `$state`, `$derived`, `$effect`) |
| `tailwindcss 4` | Utility-first CSS |
| `vite 6` | Build tool and dev server |
| `motion` | Animation library |
| `typescript 5` | Type safety |
---
## π€ Contributing
This project belongs to no one and everyone. If you find it useful and want to make it better, you are welcome.
No contribution agreements to sign. No corporate CLAs. No licensing traps. Everything here is in the public domain. Your contributions will be too - freely given, freely shared, freely built upon by anyone who needs them.
**Some ways to help:**
- Report bugs or rough edges
- Suggest new break activities (especially with physiotherapy or ergonomics knowledge)
- Improve accessibility (WCAG 2.2 AAA foundation is in place - help us maintain it)
- Port idle detection to macOS/Linux
- Translate the interface
- Share it with someone who needs it
The best software is built through mutual aid - people helping people because it's the right thing to do, not because there's a profit motive attached.
---
## π License
CC0 1.0 Universal - Public Domain Dedication
To the extent possible under law, the author has waived all copyright and related or neighboring rights to this work. Published from the commons, for the commons.
Copy, modify, distribute, perform - even commercially - all without asking permission. No attribution required (though always appreciated).
See [`LICENSE`](LICENSE) for the full legal text.
---
Built with care. Shared without conditions. Rest well.