3b487bdef4
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
162 lines
6.2 KiB
Markdown
162 lines
6.2 KiB
Markdown
# 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 I–V–vi–IV | 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.
|