A social platform for the ballroom dance community built around the ISTD syllabus. Browse figures, explore transitions as interactive graphs, build competition routines, organize and score competitions with the skating system, share technique articles, and connect with dancers and teams.
The Imperial Society of Teachers of Dancing (ISTD) publishes "The Ballroom Technique," the definitive reference for standard ballroom dancing. It defines figures (named sequences of steps) for five dances and specifies which figures can precede or follow each other, forming a directed graph of transitions.
| Dance | Time Signature | Character |
|---|---|---|
| Waltz | 3/4 | Rise-and-fall movement in triple time |
| Foxtrot | 4/4 | Smooth, progressive movement across the floor |
| Quickstep | 4/4 | Light, fast-moving dance with hops and runs |
| Tango | 2/4 | Sharp, staccato movements with dramatic character |
| Viennese Waltz | 3/4 | Fast, continuous turning |
Figures are introduced at progressively higher examination levels. Higher levels unlock additional figures and transitions:
- Student Teacher / Associate (Bronze) — Foundation figures
- Licentiate (Silver) — Intermediate figures and additional transitions
- Fellow (Gold) — Advanced figures and the full transition set
- Browse figures for each dance with search and level filtering
- Interactive directed graph visualization (React Flow + Dagre layout)
- Full dance graphs and local figure neighborhood graphs
- Figure detail pages with leader/follower step charts, footwork, CBM, sway, timing
- Build competition routines by selecting figures with transition validation
- Level ceiling filtering (Bronze/Silver/Gold/Fellow)
- Publish routines to your profile or share as feed posts
- Share routines with captions and write technique articles (WYSIWYG markdown editor)
- Follow other dancers, like/comment/save posts
- Organize saved posts into folders
- User profiles with competition level badges
- Following + Explore feed tabs
- Create or join teams (university ballroom teams, clubs, etc.)
- Configurable membership: open, invite-only, or request-to-join
- Org profile pages with posts, members, and settings
- Org-scoped content visibility
- Direct messages, group chats, and org channels
- Real-time delivery via Ably
- Typing indicators and presence
Full competition lifecycle management with real-time scoring using the skating system.
- Setup — Create competitions with multi-step wizard, schedule builder with drag-and-drop, event management with default groupings, staff/judge assignments
- Registration — Couple registration, per-event or flat-fee pricing, Stripe Connect payments, competitor number assignment, TBA partner finder, team match submissions
- Pre-comp — Add/drop request management, automatic round generation with heat assignments, schedule estimation, statistics dashboard, award calculator
- Scoring — Full skating system engine (Rules 5–11), callback tally, single and multi-dance placement, tabulation tables, results workflow (compute → review → publish)
- Judge UI — Standalone tablet interface with separate JWT auth (no platform account required), tap-to-toggle callback marking, tap-to-rank finals, real-time submission via Ably
- Comp Day — Scrutineer dashboard, registration table, deck captain check-in grid, emcee schedule with announcements, projector display, competitor live view
- Post-comp — Public results with Summary + Marks tabs, competitor search and history, competition calendar with filters, organizer feedback forms with analytics, financial analytics, record removal requests
- Org Views — Per-organization schedule, entries, and results for team coaches and admins
38 frontend pages, 26 tRPC routers, 230+ integration tests. See docs/comp-organizer/ for full documentation.
| Layer | Technology | Purpose |
|---|---|---|
| Framework | Next.js 15 (App Router) | Server components, file-based routing |
| Language | TypeScript | End-to-end type safety |
| Styling | Tailwind CSS v4 | Utility-first CSS |
| UI Components | shadcn/ui | Accessible components on Radix UI primitives |
| Database | PostgreSQL via Neon | Serverless PostgreSQL |
| ORM | Drizzle | TypeScript-first SQL ORM |
| API | tRPC v11 | End-to-end typesafe API layer |
| Auth | Clerk | Authentication with OAuth providers |
| Real-time | Ably | WebSocket messaging and live competition updates |
| Editor | Tiptap | WYSIWYG markdown editor for posts |
| Payments | Stripe | Competition registration payments via Connect |
| Judge Auth | jose | Edge-compatible JWT for judge tablet sessions |
| Drag & Drop | @dnd-kit/react | Schedule builder reordering |
| Hosting | Vercel | Deployment platform |
| Package Manager | pnpm | Fast, disk-efficient package manager |
| Dev Environment | Nix flake | Reproducible development environment |
The codebase follows a modular monolith pattern organized by domain:
src/
domains/
syllabus/ # Figure graph, dance browsing, visualization
routines/ # Routine builder and management
social/ # Feed, posts, comments, likes, follows, saves
messaging/ # DMs, group chats, org channels
orgs/ # Organizations, membership, org profiles
competitions/ # Competition organizer, scoring, judge UI, comp-day ops
shared/
auth/ # Clerk helpers, protected procedures
db/ # Database connection, shared enums
ui/ # shadcn/ui components
components/ # App shell (nav, layout)
lib/ # tRPC client, utilities
schema.ts # Users table (shared across domains)
Each domain owns its schema, routers, components, and routes. Cross-domain access uses explicit query/type exports. See docs/ for detailed architecture documentation.
dances 1 ──── * figures Figures belong to a dance
figures 1 ──── * figure_edges Edges connect two figures (directed)
users 1 ──── * routines Users own routines
routines 1 ──── * routine_entries Routines contain ordered figures
users 1 ──── * posts Users author posts
posts 1 ──── * comments Posts have threaded comments
users 1 ──── * saved_posts Users bookmark posts into folders
users * ──── * follows Follow relationships (with pending state)
users * ──── * organizations Org membership (via memberships table)
organizations 1 ──── * conversations Org channels
users * ──── * conversations DMs and group chats (via conversation_members)
organizations 1 ──── * competitions Competitions owned by orgs
competitions 1 ──── * competition_days Multi-day schedule structure
competition_days 1 ──── * schedule_blocks Sessions within a day
competitions 1 ──── * competition_events Events (e.g. "Novice Waltz")
competitions * ──── * judges Judge assignments (global directory)
competitions 1 ──── * registrations Per-person registration
entries * ──── 1 event Couple entries (leader + follower)
entries 1 ──── * callback_marks Preliminary round marks
entries 1 ──── * final_marks Final round placements
rounds 1 ──── * heats Heat assignments per round
competitions 1 ──── * feedback_forms Post-comp feedback collection
Dark theme with accent colors mapped to examination levels:
- Bronze
#CD7F32— Student Teacher / Associate - Silver
#C0C0C0— Licentiate - Gold
#FFD700— Fellow
Available as Tailwind utilities: text-bronze, border-silver, bg-gold, etc.
# Enter dev environment (if using Nix)
direnv allow
# or: nix develop
# Install dependencies
pnpm install
# Set up environment variables
cp .env.example .env.local
# Add DATABASE_URL from Neon dashboard
# Add NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY and CLERK_SECRET_KEY from Clerk
# Push schema to database
pnpm db:push
# Seed syllabus data
pnpm db:seed
# Start dev server
pnpm devFigures are extracted from scanned pages of "The Ballroom Technique" using Claude's vision API:
# 1. Extract figures from PDF page images
python scripts/extract_figures.py
# 2. Seed the database from extracted YAML
pnpm db:seed| Command | Description |
|---|---|
pnpm dev |
Start development server |
pnpm build |
Production build |
pnpm lint |
Run ESLint |
pnpm db:generate |
Generate Drizzle migrations |
pnpm db:push |
Push schema directly to database |
pnpm db:studio |
Open Drizzle Studio (database GUI) |
pnpm db:seed |
Seed database from extracted YAML |
pnpm test |
Run integration tests (requires nix develop on NixOS) |
- Syllabus browsing with search and level filters
- React Flow graph visualization (Dagre layout, edge-on-demand)
- Figure detail pages with leader/follower step data
- Routine builder with figure picker and transition validation
- Social feed with shared routines and technique articles (Tiptap editor)
- Follow system, likes, comments, notifications
- Save/bookmark system with folders
- User profiles with competition level badges
- Organizations with configurable membership (open, invite-only, request-to-join)
- Real-time messaging via Ably (DMs, group chats, org channels)
- Competition organizer — full lifecycle from creation to post-comp analytics
- Skating system scoring engine (Rules 5–11) with tabulation
- Judge tablet UI with standalone JWT auth
- Comp-day dashboards (scrutineer, registration table, deck captain, emcee)
- Real-time competition views (projector display, competitor live view)
- Results browsing, competitor history, competition calendar
- Feedback forms with analytics, payment analytics
- Clerk authentication with route protection
- Dark theme with ISTD level accent colors
- PDF extraction and database seed pipeline
375 integration tests across 52 test files.
- Photo/video media support
- Email/push notifications
- AI choreography assistant
- Viennese Waltz syllabus data
docs/comp-organizer/— Competition organizer technical docs, schema, routers, and user guidesdocs/superpowers/specs/— Design specificationsdocs/testing.md— Test infrastructure documentation
LGPL-3.0 — see LICENSE.