Routing
All routes are defined in src/pages/Skeleton.js inside a single <Routes> block.
Route table
| Path | Component | Notes |
|---|---|---|
/ |
Welcome |
Home dashboard |
/move/:metaGame/:cbits/:gameID |
GameMoveWrapper |
Live game |
/games/:metaGame? |
Explore |
Lazy-loaded |
/player/:userid |
Player |
Lazy-loaded |
/challenges/:metaGame |
StandingChallenges |
|
/listgames/:gameState/:metaGame |
ListGames |
|
/ratings/:metaGame |
Ratings |
|
/tournaments/:metaGame? |
Tournaments |
|
/tournament/:metaGame/:tournamentid |
Tournament |
|
/tournament/:tournamentid |
Tournament |
Legacy path variant |
/tournamenthistory/:metaGame |
TournamentsOld |
|
/events |
Events |
|
/event/:eventid |
Event |
|
/lab |
Lab |
|
/playground |
Navigate → /lab |
Redirect |
/play |
Play |
|
/customize/:metaGame |
Customize |
|
/stats |
Stats |
Lazy-loaded |
/news |
News |
|
/about |
About |
|
/legal |
Legal |
|
/players |
Players |
|
* |
NotFound |
Catch-all |
Lazy loading
Heavy pages use React.lazy() and render inside Suspense (fallback: Spinner):
const Explore = lazy(() => import("../components/Explore"));
GameMoveWrapper
GameMoveWrapper.js uses a key derived from route params to force GameMove to remount when navigating between games. Without this, React would reuse component state across different games.
Token prop
Some routes receive token from Skeleton (Bones):
<Route path="/" element={<Welcome token={token} update={update} />} />
Not all routes need the token; many call getAuthToken() or callAuthApi() directly.
Adding a new route
- Create the component in
src/components/orsrc/pages/. - Import it in
Skeleton.js(uselazy()if the bundle is large). - Add a
<Route>entry. - Add a navbar link in
Navbar.jsif user-facing. - Update this documentation and
nav.jsonif applicable.
SPA deployment
CloudFront serves index.html for unknown paths (via serverless-single-page-app-plugin) so deep links work on refresh.