- Entered
- 2026-09-29
- First commit
- 2026-09-30
Séance
App · training · installable, offline
A training manual that works offline and remembers everything, on the device alone.
A bodyweight training programme drawn as a gymnastics manual, one plate per movement. It guides a thirty-minute session, keeps a journal and draws the progress curves — installable, offline, with reminders, and with every number kept on the device.
- TypeScript
- React
- PWA
- Workbox
- IndexedDB
- Vitest
- Entered
- 2026-09-29Shipped
- First commit
- 2026-09-30Séance, a bodyweight training PWA drawn as a gymnastics manual
- Commits
- 4on main, read 2026-10-02
- Coverage
- 14%lines run by the app’s unit tests, read 2026-10-02
- House packages
- 10 of 11installed from npm
What shipped
- Installable and fully offline: a hand-written Workbox service worker precaches the whole shell, and every route is served with the network cut, mid-session included.
- Reminders without a server: an in-app clock, Notification Triggers where they exist, and Periodic Background Sync reading the schedule from IndexedDB in the worker — and the settings screen says plainly what this browser can do.
- Progress charts drawn by hand in SVG and HTML: regularity counted in weeks, volume per week, waist and weight never on a shared axis, each walkable with an invisible native range input and backed by a table.
- Every number stays on the device: a JSON backup carries it elsewhere, and a seeded specimen profile shows the charts full without ever touching the reader’s own data.
- Thirty-seven animated figures drawn from joints, not paths: interpolation is polar and chained from the hip, so no bone stretches mid-movement.
How it works
zero server, everything cached on the device
As the compiler reads it
Set the way an editor shows it: a wavy line is a build that refuses, a violet line is what the compiler works out on its own.
export const isReminderOwed = ({ lastSessionDay, lastShownDay, now, schedule, today }) => schedule.isEnabled && schedule.days.some((day) => day === now.getDay()) && now.getTime() >= reminderOn(now, schedule.time).getTime() && lastShownDay !== today && lastSessionDay !== today
History
Straight from the git log, abridged: 4 of 4 commits, newest first.
- Deploy the public demo from CI on every push to main
- Deploy the public demo to Cloudflare Pages from a clean clone
- Deploy the private build to Netlify on push to main, drop Cloudflare Pages
- Séance, a bodyweight training PWA drawn as a gymnastics manualFirst commit
Installs
10 of the 11 house packages, from npm, down to the compiler and linter settings.
- @adrienlcp/react-routerThe router provider every app takes.0.1.1
- @adrienlcp/i18nTranslates, and knows at compile time what each message asks for.0.3.0
- @adrienlcp/theme-preferenceKeeps the chosen theme from flashing, down to the phone’s toolbar.0.3.0
- @adrienlcp/browserCopies to the clipboard even over plain HTTP, where the Clipboard API does not exist.0.1.1
- @adrienlcp/reactThe context helpers every React app starts from.0.3.0
- @adrienlcp/stylesThe reset and shared styles every project starts from.0.5.0
- @adrienlcp/resultSays whether something worked, without throwing and without null.0.1.0
- @adrienlcp/safe-storageTakes the throw out of localStorage and returns a Result instead.0.1.0
- @adrienlcp/tsconfigThe compiler settings every project extends.0.1.0
- @adrienlcp/biome-configThe linter and formatter settings every project extends.0.1.0