Ocarina Tabs
I built Ocarina Tabs, a web app for creating and sharing ocarina fingering charts. The idea is simple: visual diagrams showing which holes to cover for each note, so you can learn songs without reading sheet music.
Features
- Tab Editor: Create fingering charts with a visual editor. Click holes to toggle them, add notes, adjust timing
- Multiple Ocarina Types: Supports 12-hole, 6-hole, and inline ocarinas with appropriate hole layouts
- Transposition: Shift songs up or down to match your ocarina's range
- Collections: Group tabs into shareable collections
- User Profiles: Public profiles at
/u/usernameshowing your tabs and collections - Favorites: Save tabs you want to come back to
- Dark Mode: Because of course
Technical Stack
React + TypeScript frontend with Vite and Tailwind. Firebase handles everything else: Authentication, Firestore for the database, Cloud Functions for backend logic, and Firebase Hosting.
Why Firebase over Supabase?
I usually prefer Supabase with Postgres. The SQL interface is nicer for complex queries, and Postgres is just a better database. But Supabase's pricing didn't work for this project. Their free tier is limited and the first paid tier jumps to $25/month. That's fine for a real product, but for a side project that might get 100 users, it's overkill. Firebase's pay-as-you-go pricing scales more gradually than Supabase's tier jump.
The tradeoff is dealing with Firestore's document model and limited querying. No joins, so you denormalize data or make multiple queries. Composite indexes for any non-trivial query. Security rules that are powerful but verbose. It's fine once you get used to it, but I miss SELECT * FROM tabs WHERE user_id = ? ORDER BY created_at DESC.
Firebase Hosting is also convenient. Deploy with firebase deploy and you're done. No Vercel/Netlify config, no separate hosting setup.
Other Notes
Cloud Functions handle things that shouldn't run client-side: aggregating favorite counts, validating data, etc. TypeScript throughout. Firestore security rules lock down access properly.
The CI/CD is GitHub Actions deploying to Firebase on push to main. Deploys functions, Firestore rules/indexes, and the hosting site together.
Try It
If you play ocarina (or want to), check it out at ocarinatabs.com. Create some tabs, make a collection, let me know if anything breaks.