Sumo App
Real-time sumo tournament tracker — live SSE updates, command-palette navigation, hand-prompted sumi-e illustrations
Live basho standings, wrestler profiles, and a build-time pipeline of sumi-e ink illustrations — because if you're going to learn about sumo, you might as well do it properly.
- statuslive
- modelside project
- since2026
- > solo, weekends
Sumo App started as “I want to follow a basho and the official sites are kind of awful,” and quickly turned into “what if the entire visual identity were generated from prompts.” It tracks live tournament standings (via sumo-api.com), wrestler rankings, day-by-day matches, and the 86 finishing techniques (kimarite) that decide them.
Stack is Next.js 16 + React 19 with TanStack Query doing the server-state caching and a thin SSE layer pushing webhook updates from the upstream API straight into the query cache (with HMAC signature verification, because that’s table stakes).
$ python scripts/stats.py
- sumi-e illustrations generated 126
- wrestlers indexed 191
- lines of typescript 14 177

The AI bit (the actual reason this exists)
There’s no LLM call at runtime — every visual asset is pre-generated at build time by a small Python pipeline in /scripts. Two pipelines, both producing sumi-e ink-brush illustrations because that’s the only style that wouldn’t look ridiculous next to centuries-old sumo terminology.
Kimarite illustrations (86 techniques):
- A 291-line hand-written prompt file, one entry per technique, describing the pose, contact point, and intent
- A unified style suffix appended to all 86 prompts so the set holds together visually
- Generated through FLUX.1 Dev locally (28 inference steps) or OpenAI gpt-image-1 as the cloud option
- White background → transparent post-process so they composite cleanly into the UI






Rikishi portraits (191 wrestlers):
- Source photo from sumo.or.jp, watermark cropped
- IP-Adapter v2 extracts facial identity from the source
- Rank-conditional prompting: yokozuna get the tsuna rope and a katana; everyone else gets a kesho-mawashi (ceremonial apron)
- Kanji ring-name rendered in calligraphy in the corner
--ip-scaleknob trades likeness for artistic freedom — settled around 0.65 after a lot of A/B testing


The result is a growing custom illustration set that would have cost real money to commission, generated for the price of a few GPU hours and a lot of prompt iteration.
Other bits
- Hybrid SSR + client-side TanStack Query — server fetches, hydrates
initialData, client takes over with stale-while-revalidate - A
cmdkcommand palette for jumping between tournaments, wrestlers, and techniques (because everything is named in romanized Japanese and nobody can spell anything correctly on the first try) - Real-time webhooks that invalidate exactly the right queries —
matchResultsinvalidates["matches", bashoId]and["banzuke", bashoId], not the world