# Interval Timer A mobile-first interval training timer that installs as a Progressive Web App. No build step, no dependencies, no network calls — just static files. ## The cycle For every set, each exercise gets a **pause** followed by a **training** block: ``` for each set: for each exercise: pause (default 15s) text is grey training (default 45s) text turns red ``` - **Start** rings a bell, shows the first exercise in grey and runs the pause. - When the pause ends a beep plays and the text turns **red** for the training block. - When training ends another beep plays, the next exercise appears and its pause begins. - After the last exercise of the last set, a triple bell rings and the screen shows *Workout complete*. `Pause` / `Resume` freezes the clock; `Reset` returns to the start. The screen is kept awake during a session via the Screen Wake Lock API. ## Files | Path | Purpose | | --- | --- | | `index.html` | Markup: stage, controls, settings | | `styles.css` | Dark theme; grey/red phase colours | | `app.js` | Timer state machine, Web Audio bell/beep, exercise list | | `manifest.webmanifest` | PWA metadata and icons | | `sw.js` | Service worker — app shell cached for offline use | | `icons/` | Generated app icons | | `tools/make_icons.py` | Regenerates the icons (needs Pillow) | | `tools/smoke_test.mjs` | Headless-Chrome test of the whole cycle | | `start` | Your local live-server launcher (port 8080) | Settings and the exercise list are stored in `localStorage`, so they survive a reload. ## Running it on your phone PWA installation and offline caching require a **secure context** (HTTPS, or `localhost`). A plain `http://:8080` URL works as a normal web page but will not be installable and will not cache offline. ### 1. Serve the files ```sh cd timer python3 -m http.server 8080 # or, using the ./start script (Node + live-server, auto-reload) ./start ``` ### 2. Give your phone an HTTPS URL Either expose the local server through a tunnel, for example: ```sh cloudflared tunnel --url http://localhost:8080 # or: npx localtunnel --port 8080 ``` or upload the folder as-is to any static host (GitHub Pages, Netlify, Cloudflare Pages, Vercel). There is nothing to compile. ### 3. Install Open the HTTPS URL on the phone and use **Add to Home Screen** (Safari: Share menu; Chrome: banner or the ⋮ menu → *Install app*). It then launches fullscreen and works offline. ### Audio notes - The bell and beeps are synthesised with the Web Audio API, so there are no sound files to download and they work offline. - Audio is unlocked by the first tap on **Start**, as mobile browsers require. - On iOS the ringer/silent switch still mutes Web Audio playback — turn silent mode off for a workout. ## Tests With a server on `127.0.0.1:8765` and Chrome running with `--remote-debugging-port=9222`: ```sh cd timer node tools/smoke_test.mjs ``` The test drives the real page and asserts the exact pause/training sequence for 2 sets × 3 exercises, the grey→red colour switch, phase durations, the frozen clock while paused, reset/restart behaviour and settings persistence.