Files
guitar-practice-tool/README.md
T
2026-07-23 10:48:06 +02:00

162 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Guitar Practice Helper
A static web app that turns the drill codes from my Obsidian practice wiki (R1, F2,
T3, …) into interactive helper pages: click tracks, pattern grids, chord & fretboard
diagrams, and a drone. Open a drill link from the wiki on phone or desktop, press
play, practise for ~5 minutes. No accounts, no backend, no analytics.
Built with **Svelte 5 + Vite** as a fully static SPA. Music theory is powered by
[`tonal`](https://github.com/tonaljs/tonal). Timing uses a Web Audio lookahead
scheduler so the metronome never drifts.
## Where this routine comes from
The drill set began with the YouTube video
[**“How to get SO GOOD at guitar it feels ILLEGAL (Using Neuroscience)”**](https://www.youtube.com/watch?v=7SNcy_GprQU).
Its practice principles were turned into a concrete, coded routine — the R/F/T/L/E
drills kept in my Obsidian wiki — in [this conversation](https://claude.ai/share/dfded9f7-5a26-4ea7-b265-fab118e32ed7).
This app then gives each of those drill codes an interactive helper so the routine
is actually runnable next to the guitar.
The routine is built on a handful of evidence-based practice ideas from the video:
- **Interleaving + active recall** — mix skills within a session and test yourself
cold, instead of mindless blocked repetition of the same lick.
- **A practice journal** as the engine that makes the rest work.
- **Short, frequent sessions** over long grinds.
- **The additive approach** — build a passage up in tiny increments.
- **Deep practice / myelin** — effortful reps right at the edge of your ability.
- **Mental practice** away from the instrument.
Several of these are baked into the app: the “clean? +2” tempo bump enforces
additive, edge-of-ability progression (only speed up once a rep is clean);
per-drill BPM persistence supports short daily sessions and a journal-like record
of where you left off; and the mixed drill categories on the index page nudge you
toward interleaving rather than grinding one skill.
## Develop
```bash
pnpm install
pnpm dev # local dev server
pnpm check # svelte-check (typecheck)
pnpm test # vitest (scheduler timing + music-theory correctness)
pnpm build # typecheck + production build to dist/
pnpm preview # serve the built dist/ locally
```
## Deploy
The build is fully static (`dist/`). Because the app uses **path routing**
(clean URLs like `/drill/R3`), the host must serve `index.html` for unknown paths
(SPA fallback), and the base path is baked in at build time.
### Base path
- Dedicated domain / served at the root: default, `base = '/'`.
- Subpath (e.g. `https://example.com/practice/`): build with
`VITE_BASE=/practice/ pnpm build`.
### Cloudflare Pages
Framework preset: none. Build command `pnpm build`, output directory `dist`.
`public/_redirects` (already included) provides the SPA fallback:
```
/* /index.html 200
```
For a subpath, set the `VITE_BASE` environment variable in the Pages build settings.
### Docker + nginx
A multi-stage `Dockerfile` (Node build → `nginx:alpine`) with the correct config
(`nginx/default.conf`: SPA fallback via `try_files`, immutable caching for hashed
assets, `no-cache` for the HTML shell, gzip):
```bash
docker build -t guitar-practice . # root deploy
docker build --build-arg VITE_BASE=/practice/ -t guitar-practice . # subpath
docker run -p 8080:80 guitar-practice # http://localhost:8080
```
### Existing nginx server
Serve `dist/` and add the SPA fallback to your location block:
```nginx
location / {
try_files $uri $uri/ /index.html;
}
```
## Deep-link URL format
The whole point — link to any drill directly from the wiki:
```
https://<host>/<base>drill/<CODE>
```
Optional query parameters override the stored/default settings:
| Param | Applies to | Example |
|------------|-----------------------|----------------|
| `bpm` | click-track drills | `?bpm=66` |
| `variant` | drills with variants | `?variant=2-3-2` |
| `key` | T2, T4 | `?key=D` |
| `root` | T3, T5, T6, L4 | `?root=A` |
| `interval` | T5 | `?interval=P5` |
| `mode` | T6 | `?mode=dorian` |
| `pair` | R4 | `?pair=g-c` |
Examples:
```
https://example.com/practice/drill/R3?bpm=66&variant=2-3-2
https://example.com/practice/drill/T6?root=A&mode=dorian
https://example.com/practice/drill/R4?pair=f-bm
```
Unknown codes resolve to a friendly “unknown drill” page linking back to the index
(`/` shows all drills grouped by category).
## Drills
| Code | Name | Helper |
|------|------|--------|
| R1 | 16th-note strum, mute the off-beats | metronome + strum grid |
| R2 | Accent patterns | metronome + strum grid |
| R3 | 7/8 loop (drop to 4/4 live) | metronome + strum grid |
| R4 | One-minute chord changes | countdown + tap counter + chord diagrams |
| R5 | Palm-mute chugging | metronome + strum grid |
| F1 | Travis picking | metronome + picking lane + chords |
| F2 | PIMA arpeggio over IVviIV | metronome + picking lane + chords |
| F3 | Thumb-independent bass + melody | metronome + picking lane |
| T1 | Name every note on one string | metronome prompter + fretboard |
| T2 | CAGED shapes | fretboard, prev/next |
| T3 | Triads on a 3-string set | chord diagrams, inversions |
| T4 | Diatonic chords of a key | chord diagram row |
| T5 | Intervals from a root | fretboard |
| T6 | Mode over a drone | drone + fretboard |
| L1 | Alternate picking builder | metronome + picking lane |
| L2 | Legato runs (triplets) | metronome + picking lane |
| L3 | String skipping | metronome + picking lane |
| L4 | Bends and vibrato | reference tone |
| E1 | Interval recognition | info |
| E2 | Chord quality recognition | info |
| E3 | Play along by ear | info + drone |
## Keyboard (desktop)
- **Space** — play / pause
- **↑ / ↓** — BPM ±2
## Notes
- Audio unlocks on the first tap/keypress (mobile autoplay policy).
- Per-drill settings (BPM, variant, key, best scores) persist to `localStorage`
under the `gph:` namespace.
- Screen Wake Lock keeps the phone awake while a click or drone is playing.
- Respects `prefers-reduced-motion`: the beat still advances, without the glow/swing.