Skip to content

perf: /play shows its dialog at first paint, and the game as soon as you choose - #329

Merged
ashtonanderson merged 6 commits into
mainfrom
claude/perf-round-7
Nov 3, 2026
Merged

ashtonanderson merged 6 commits into
mainfrom
claude/perf-round-7

Conversation

@ashtonanderson

@ashtonanderson ashtonanderson commented Nov 2, 2026 •

Copy link
Copy Markdown
Member

Seventh round: /play shows its setup dialog at first paint, and a game appears the moment you choose a side. Stacked on #328 (claude/perf-round-6); this PR's base is that branch. Details are in LOADING.md ("Round 7").

Changes

  • The setup dialog is in /play's server HTML (b04ed0c).
    • /play used to draw nothing until the app had loaded, the router was ready and the dialog's code (a dynamic import in ModalContext) had arrived. Now /play renders the dialog itself, on the server too.
    • It appears without the fade and slide it has when a button opens it (ModalContainer's animateIn).
    • Until the app has started, the dialog ignores taps (pointer-events). A choice made before then would show on screen but not be used.
    • A URL with settings (a challenge, a position to continue from) hides the server's default dialog until the app has read the URL, as before.
  • The game appears at once (30d4a55).
    • After you choose a side, /play/maia used to show nothing while play/start_game created the game (~0.6 s on the backend).
    • Now it shows the game straight away, with the board at the starting position.
    • Your moves and their logging wait for the game's id (usePlayController, useVsMaiaController). Maia's moves already did, and the clocks start with the first move, as before.
    • A new game (Play again) gets a new PlayMaia (gameKey) instead of PlayControllerContext's key on the id.
  • start_game is sent as you choose (f3d1b7a).
    • With the game drawn at once, the request was only sent after /play/maia had rendered. On the phone the board then took moves ~0.35 s later than before.
    • Now the dialog sends start_game as you choose (startGameEarly), and /play/maia takes that request if its settings match (takeEarlyGame), or starts its own.

Results (round 6 → this branch)

play_flow.mjs opens /play, chooses "Play as white" as soon as the dialog takes taps, and waits for the game. The phone is Chrome's 4x CPU throttling with 4G. 5 runs each, builds alternating.

phone desktop
Setup dialog on screen 1.64 → 0.58 s 0.45 → 0.30 s
Dialog takes taps 1.66 → 1.41 s 0.46 → 0.42 s
After choosing: board with its pieces 1.99 → 1.29 s 1.02 → 0.46 s
After choosing: board takes moves 1.60 → 1.29 s 0.90 → 0.83 s
Main-thread work after choosing 1.50 → 1.36 s 0.51 → 0.58 s

Testing

  • npm test (89, with main's), npx tsc --noEmit and npm run lint pass, rebased on main after Capture PostHog web vitals again #330 and Track what visitors do, and stop losing events #332.
  • Checked in local production builds:
    • Placement: the dialog is in the same place in the server's HTML and once loaded, on a Pixel 7 and at 1440 × 900. No React errors.
    • Settings in the URL: a URL with modalTitle and forcedColor shows nothing until the app has read it, then its own title.
    • A game: it takes e4 once it has its id, and Maia answers ("1. e4 e5"). Both moves are logged under that id.
    • Play again: resigning, then Play again as black, gives a new id, black at the bottom and the starting position.
    • One game per start: two games make two start_game calls, on this branch as on round 6.
  • No Stockfish check: nothing here touches the analysis page.
  • Not tried on real phones or in Safari.

Not done

  • Hand and Brain (/play/hb) still waits for its game as before.
  • The dialog that buttons elsewhere open still loads its code on the first click.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
maia-platform-frontend Ready Ready Preview Nov 3, 2026 6:32am UTC

Request Review

ashtonanderson and others added 4 commits November 2, 2026 23:25
/play showed nothing until the app had loaded, the router was ready and
the dialog's code (a dynamic import in ModalContext) had arrived: ~2.3 s
on the emulated phone. /play now renders the dialog itself, on the server
too, without the fade and slide it has when opened from a button
(ModalContainer's animateIn), and closes it through its new onClose.
Until the app has started the dialog ignores taps (pointer-events), since
a choice made before then would show but not be used. A static page reads
its URL only once the router is ready, so a URL with a query (a
challenge, a position to continue from) hides the server's default dialog
until the dialog with its settings replaces it, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
After choosing a side, /play/maia showed nothing while play/start_game
created the game (~0.6 s on the backend). It now shows the game at once,
its board at the starting position, with moves and logging waiting for
the game's id (usePlayController, useVsMaiaController); Maia's moves
already did. A new game (Play again) gets a new PlayMaia (gameKey)
instead of PlayControllerContext's key on the id.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
/play/maia asked the backend for a game only once it had loaded and
rendered: with the game now drawn at once, on the emulated phone that
rendering pushed the request back and the board took moves ~0.35 s later
than before. The setup dialog now sends start_game as the visitor chooses
(startGameEarly), and /play/maia takes that request if its settings match
(takeEarlyGame), or starts its own; if the early one fails it tries once
more before /401.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ashtonanderson and others added 2 commits November 3, 2026 06:29
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rebase on #330 and #332 gave round 7's commits new IDs, and the
old ones are no longer on any branch. The round 6 build it was measured
against keeps its old ID, marked as from before the rebase.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ashtonanderson
ashtonanderson changed the base branch from claude/perf-round-6 to main November 3, 2026 06:34
@ashtonanderson
ashtonanderson marked this pull request as ready for review November 3, 2026 06:34
@ashtonanderson
ashtonanderson merged commit 4d05861 into main Nov 3, 2026
8 checks passed

This branch was successfully deployed

1 active deployment
Preview — 1eb36c68 Deployed Nov 3, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant