Skip to content

Repository files navigation

Elon Esports Smash PR

Super Smash Bros. Ultimate tournament tracker & power rankings
Built for Elon University's esports club

Next.js Supabase Vercel


Power Rankings — animated hero with floating Smash character renders, podium, and leaderboard

How Scoring Works

Players compete in tournaments — Elon-only weeklies and open regionals alike. The system uses a weighted average placement formula where better finishes in harder, bigger fields produce lower (better) scores:

weight  = elon_participants / total_participants
score   = (placement / total_participants) × weight
average = sum(scores) / tournaments_played

Placement is normalized by field size so that finishing 14th of 30 (top half) correctly beats finishing 7th of 7 (dead last) — raw placement alone would reward the smaller, worse finish.

Tournament Type Example Weight Effect
Elon weekly (10/11) 0.91 Placements count a lot
Mixed local (5/35) 0.14 Rewards beating non-Elon opponents
Major regional (5/500) 0.01 Even mid-pack finishes are impressive

Lower average = higher rank. A minimum tournament threshold (default 3) filters out one-time participants.


Features

Public

  • Leaderboard — Animated hero with floating Smash character renders, podium with trophy/medal icons, fireworks, semester selector, min-tournament slider, recent tournaments
  • Player Directory — Search, scatter plot, paginated card/table views (50/page), stats bar
  • Player Profiles — Stat cards, performance waveform, placement timeline, career journey, head-to-head records, tournament history
  • Tournaments — Paginated list of all start.gg tournaments, filterable by semester with grouped subheaders
  • SEO — OpenGraph, Twitter cards, dynamic metadata per player profile

Admin

  • start.gg Import — Paste a URL, auto-detect singles events, preview standings, flag Elon students, confirm — scores recalculate automatically
  • Manual Entry — Bracket format selector, virtualized player picker, drag-and-drop placements
  • Player Management — Elon status toggle per semester, atomic player merge/unmerge (keeps best placement, migrates sets, records history), start.gg account linking
  • Semester Management — Auto-create from academic calendar (Spring Jan–Jul, Fall Aug–Dec), overlap validation, tournament reassignment on date changes

Under the Hood

  • 3-batch parallel DB fetches for player profiles, SSR with unstable_cache (60s TTL)
  • Advisory locks prevent concurrent semester recalculations
  • Deferred set imports via after() — response returns in ~2s instead of ~15s
  • Idempotency guards on all create operations (duplicate name, tag, event ID, date range)
  • No player deletion — merge only, preserving tournament history integrity
  • Atomic merge/unmerge — Postgres RPC functions wrap all mutations in a single transaction
  • Source tracking — source_startgg_id on results and sets enables clean unmerge by start.gg identity

Stack

Technology Purpose
Framework Next.js 16 App Router, Server Actions, RSC
Database Supabase Postgres, Auth, RLS
Styling Tailwind CSS + shadcn/ui Dark esports theme
Animation Framer Motion LazyMotion + domAnimation (~5KB gzipped)
Virtualization @tanstack/react-virtual Large list performance
Deployment Vercel Edge caching, preview deploys

Getting Started

Prerequisites

Setup

git clone https://github.com/drewfoos/ElonEsports-Supabase.git
cd ElonEsports-Supabase
npm install

Create .env.local:

NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key
ADMIN_EMAIL=admin@elonesports.gg
STARTGG_API_TOKEN=your-startgg-token

Apply docs/schema.sql in Supabase SQL Editor, create the admin user in Authentication > Users, then:

npm run dev
URL Page
localhost:3000 Public leaderboard
localhost:3000/players Player directory
localhost:3000/tournaments Tournament list
localhost:3000/login Admin login

Deploy

Push to GitHub, import in Vercel, add env vars, deploy.


Project Structure

src/
├── app/
│   ├── page.tsx                    # Leaderboard (SSR, parallel fetch)
│   ├── leaderboard-client.tsx      # Fireworks, podium, semester picker
│   ├── players/
│   │   ├── page.tsx                # Player directory
│   │   └── [playerId]/page.tsx     # Player profile (dynamic metadata)
│   ├── tournaments/page.tsx        # Public tournaments (paginated, semester filter)
│   ├── admin/                      # Dashboard, players, tournaments, semesters
│   └── api/
│       ├── leaderboard/route.ts    # Public leaderboard API
│       └── tournaments/route.ts    # Public tournaments API
├── lib/
│   ├── scoring.ts                  # Scoring engine (parallel, batched, guarded)
│   ├── startgg.ts                  # start.gg GraphQL client
│   ├── supabase/                   # 4 clients: browser, server, admin, static
│   └── actions/                    # Server actions (players, tournaments, semesters)
├── components/ui/
│   └── shape-landing-hero.tsx      # Animated hero with character renders
└── proxy.ts                        # Admin route protection

Docs

Document Description
docs/architecture.md System design, request flows, performance
docs/schema.sql Database schema with RLS policies
docs/startgg-api.md start.gg GraphQL API reference
docs/changelog.md Development history
SPEC.md Product requirements
SCORING_SYSTEM.md Original scoring analysis

Not affiliated with Nintendo

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages