← All projects

BhajanTabs

A chord-sheet app for learning bhajans on guitar — tap chords straight onto the lyrics, transpose to any key, play along to backing tracks.

Tappable-editor GIF (hero) — tap lyric → chord picker → chord drops in

The problem

Personal-first (my own guitar learning), shareable with musicians in my circle — not a community tool.

Learning bhajans on guitar: devotional songs need transposing into the player's key. (The Clerk auth + pending→active approval flow is real but incidental to the personal framing.)

What I built

  • Tappable chord editor (the creativity hero) — instead of typing [C] bracket markers, tap a spot in the lyric and pick a chord. A mobile-guitarist UX call: phone on a stand, guitar in hand, typing brackets is miserable.
  • Multiple arrangements per song at varying difficulty — one bhajan, several tabs (the isTemplate/multi-tab feature).
  • Transposition as a first-class, persisted feature.
  • Backing-track play-along for practice.
  • Printable PDF / Markdown export for offline use.

How it works

Frontend — React 19 · Vite 7 · TS · Tailwind 4 + shadcn/ui · wouter (patched) · TanStack Query · React Hook Form + Zod · Framer Motion. Backend — Express 4 · tRPC 11 · Clerk auth (JWT). Data — Drizzle ORM over MySQL. Storage — AWS S3 (Railway bucket) via presigned URLs. Export — jsPDF + html2canvas. Deploy — Railway (single-port prod serving).

Schema — users (clerkId, role, status pending|active) · songs (title, originalKey, tempo, language, tags, backingTrackUrl) · tabs (songId FK, label, key, isTemplate, content as a plain-text chord sheet).

Rendered chord sheet — chords above lyrics + transpose control
Multiple tabs of one bhajan at varying difficulty
Backing-track play-along bar (static)
Architecture diagram — React/tRPC → Express → Drizzle/MySQL → S3 + Clerk (gated parse/transpose + caret engine boxed off)
Owned now — product sense + creativity

The tappable chord editor decision (the creativity hero); multiple arrangements per song at varying difficulty; transposition as a first-class persisted feature; backing-track play-along; PDF/Markdown export; plus conception, deploy, daily personal use, and sharing.

Under the hood

Under the hood, two pieces do the heavy lifting:

Chord-sheet parse + transposition engine

client/src/lib/chordEngine.ts — parses 3 chord-sheet formats without mis-tagging lyric lines as chords, with enharmonic sharp/flat handling, slash chords, and modulo-12 chromatic math.

Tappable-editor internals

TappableChordEditor.tsx — caret-from-tap resolution, cross-browser caretRangeFromPoint, and string-offset arithmetic.