Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ caffeine version # Print version
- `src/digital_caffeine/__main__.py` - Enables `python -m digital_caffeine`
- `src/digital_caffeine/engine.py` - Core keep-awake logic (CaffeineEngine), thread-safe with pause/resume
- `src/digital_caffeine/cli.py` - Click CLI group with `start`, `config`, `version` subcommands
- `src/digital_caffeine/animations.py` - Animated coffee cup display, procedural steam, quips, progress bar
- `src/digital_caffeine/animations.py` - Minimal single-line status display via `run_display` (spinner + mode phrase + elapsed + optional duration suffix), rotating quip pool, TTY vs non-TTY split
- `src/digital_caffeine/tray.py` - pystray system tray mode (TrayApp class)
- `src/digital_caffeine/config.py` - TOML config at `~/.digital-caffeine/config.toml`
- `src/digital_caffeine/icons.py` - Programmatic icon generation with Pillow (active/paused/stopped states)
Expand All @@ -61,5 +61,6 @@ Defaults: `mode = "all"`, `interval = 60`, `duration = None`, `simulate = false`
- **Windows-only**: Engine uses `ctypes.windll.kernel32.SetThreadExecutionState`. Use `--simulate` on the CLI, but note the engine itself will still call the API. Tests mock it automatically.
- **`--simulate` is NOT a dry run**: It enables a 1px mouse jiggle (right then left) via `SendInput` to fool presence detection in Teams/Slack/Zoom. The engine still calls `SetThreadExecutionState` either way.
- **Python 3.10 needs `tomli`**: `config.py` falls back from `tomllib` (3.11+) to `tomli`. Not in `dependencies` - users on 3.10 must install it manually or config loading will fail.
- **Animation at 8 FPS**: `animations.py` drives `Rich.Live` at 8 FPS. The `FPS` constant controls refresh rate.
- **Animation at 10 FPS**: `animations.py` drives `rich.live.Live` at 10 FPS. The `FPS` constant controls refresh rate.
- **TTY vs non-TTY in `run_display`**: On a TTY it runs a Rich `Live` redraw loop with `q`-to-quit (via `msvcrt`). When stdout is piped/redirected it prints one status line and sleeps until the engine stops, so log output stays clean.
- **Duration expiry in tray mode**: Engine fires an `on_stop` callback on a separate daemon thread to avoid self-join deadlock.
35 changes: 13 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Digital Caffeine tells your PC to knock it off. It uses the Windows `SetThreadEx

## What you get

The CLI mode gives you a live dashboard running at 8fps with procedurally generated steam wisps rising from a color-gradient coffee cup, a rippling liquid surface, a border that breathes through cyan shades, and coffee puns that type themselves out with a blinking cursor. Timed sessions get a progress bar. Is any of this necessary? No. Did we do it anyway? Obviously.
The CLI mode gives you a single-line status: a braille spinner, what it's doing, how long it's been doing it, and a rotating coffee quip underneath. No dashboards, no ASCII art, no breathing borders. It reflows on narrow terminals, drops styling when `NO_COLOR` is set, and quits on `q` or Ctrl+C.

There's also a system tray mode if you'd rather it just sit in the corner and do its job quietly. Coffee cup icon, right-click menu, notifications when a timed session ends.

Expand Down Expand Up @@ -76,29 +76,20 @@ caffeine start --simulate --duration 8h --mode all
When you run `caffeine start`, you get this:

```
+-----------------------------------------------+
| Digital Caffeine |
| |
| . . |
| . . · |
| ' '· Status: Active |
| ' ~' Mode: Display |
| ) ~ ) Uptime: 00:05:23 |
| +-----------+ Time remaining: 01:54:37 |
| | ~.~.~.~.~ |--\ Interval: 60s |
| | ......... | | Simulate: On |
| | ......... | | |
| | ......... |--/ ####............... 25% |
| +-----------+ |
| ================= |
| |
| Brewing producti_ |
| |
| Press Ctrl+C to stop |
+-----------------------------------------------+
⠋ caffeine · keeping display + system awake · 1m 23s · q to quit

Brewing productivity...
```

For a timed session (`caffeine start --duration 1h`), the status line picks up a remaining/total suffix:

```
⠙ caffeine · keeping display + system awake · 1m 23s · 58m / 1h left · q to quit

Espresso yourself freely
```

The steam is procedurally generated - 10 wisps rising with sine-wave drift, fading from `)` near the cup to `·` at the top. The coffee has a three-tone brown gradient. The liquid surface ripples. The quips type themselves out letter by letter with a blinking cursor. If you set a duration, a progress bar fills up next to the cup. The border breathes through cyan shades at 2Hz. All of it runs at 8fps and the entire animation state is a pure function of the frame counter. Nobody asked for this.
The spinner is a 10-frame braille cycle ticking at 10 FPS. The quip is held back for the first 5 seconds so startup isn't noisy, then rotates every 90 seconds from a pool of ~120 puns seeded per-session so each run feels different. Narrow terminals (under 50 columns) drop the "left" suffix and quit hint. `NO_COLOR` disables the cyan accent and dim styling. Piped or redirected output skips the live redraw and prints one line.

### Options

Expand Down
Loading
Loading