Roll a random tennis season every day and score its real results.
Translation pending
Sports & fitnessTypeScript · PLpgSQLGitHub @JamesKLaddOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗A daily tennis roll game inspired by RNGdle. Roll a random season (1990–2026) and a random year-end top-100 player from it. Their real stats earn badges, and the badges add up to your score: around 50k for a typical roll, and up to ~100 million for an all-time great season.
See SPEC.md for the product and technical spec, and docs/balance-report.md for the current score distribution.
npm install
npm run dev # http://localhost:3000 (daily roll) and /sandbox (unlimited)
npm test # unit + data regression tests
npm run balance # regenerate docs/balance-report.md after badge changes
The built season data (data/seasons/) is committed, so the app runs without
the raw CSVs. To rebuild it from source:
npm run data:fetch # sparse clone of the source CSVs into data/raw/, plus the live season
npm run data:build # writes data/seasons/*.json
The 2026 season is live: a GitHub Actions workflow
(.github/workflows/refresh-data.yml) runs those two commands every day and
commits the result, and the push redeploys the app. See "Live season" in
SPEC.md for how the sources are merged.
The daily roll, guests and sign-in need a Supabase project. /sandbox works
without one.
.env.example to .env.local and fill in the project URL and keys.supabase/migrations/, oldest file first. Either paste
each file into the dashboard's SQL Editor and run it, or use the CLI (stick
to one of the two, since the CLI keeps its own record of applied migrations):
npx supabase db push --db-url "$SUPABASE_DB_URL"
npm run data:build):
npm run db:seed
http://localhost:3000/auth/callback (and the production
https://<domain>/auth/callback) to the redirect URLs.Production branch. Vercel deploys the repository's default branch, and
GitHub only runs scheduled workflows there. Make the branch with the latest
code the default (or merge it into main and make that the default).
Import the project. In Vercel, go to Add New → Project and import the repository. The framework (Next.js) is detected automatically. Add these environment variables for Production and Preview:
NEXT_PUBLIC_SUPABASE_URLNEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEYSUPABASE_SERVICE_ROLE_KEY (the sb_secret_… key)NEXT_PUBLIC_SITE_URL (optional): your custom domain, for link previewsThen deploy.
Supabase URLs. In Authentication → URL Configuration, set the Site URL
to the production URL and add https://<domain>/auth/callback to the
redirect URLs. Add https://*-<team>.vercel.app/auth/callback too if you
want sign-in on preview deployments.
Guest cleanup. Apply supabase/migrations/20261025000000_guest_cleanup.sql
if you haven't already. Integrations → Cron should then list
acedle-delete-stale-guests.
Daily refresh. On GitHub, under Settings → Secrets and variables →
Actions, add NEXT_PUBLIC_SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY so the
workflow can reseed Supabase. These are optional: rolls add missing players
by themselves. Then run "Refresh live data" once from the Actions tab.
ATP match and ranking data was collected and compiled by Jeff Sackmann
(originally github.com/JeffSackmann/tennis_atp, now preserved at
Aneeshers/tennis-sackmann-archive).
It's licensed under CC BY-NC-SA 4.0,
and so is the derived data in data/seasons/. The live 2026 season adds
results from Tennis My Life
and the current ranking list from Tennis Abstract.
Acedle is a non-commercial fan project and isn't affiliated with the ATP Tour.
The link preview images (opengraph-image.tsx files, styled in src/lib/og.tsx)
use Alfa Slab One and Courier Prime from assets/fonts/, under the SIL Open
Font License (assets/fonts/OFL-*.txt).
Player photos come from Wikimedia Commons
(npm run data:photos, also run monthly by .github/workflows/photos.yml);
each card credits its photo's author and license. Players without one get
illustrated art in their country's colors. Signed-in players can suggest a
Commons photo for any card (/photos/suggest/<player>/<year>); suggestions
wait in /admin/photos until an admin approves them. Admins are the user ids
in the admins table (insert into public.admins (user_id) values ('…')).