Repository navigation
Replay: stop the map at its edges instead of panning forever - #312
Conversation
The replay canvas panned without limit, so a drag could push the map and its dot grid off screen into empty space. The camera now holds the world box over the part of the canvas the roster leaves clear, as the editor's canvas does, and the follow camera goes through the same clamp, so a player at the map edge stays in view, as centred as the edge allows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
…unds stay off Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In the replay viewer you could drag the map off the screen and keep going. The dot grid stopped at a hard line and past it there was nothing. Dara's note: "the half way method at which we are doing this sucks". This PR stops the map at its edges, the way the strategy editor's canvas does, so the replay feels like the editor people already know.
What changed
The canvas camera now holds the box the dot grid and map are drawn in (the 16:9 "world" box, the same one the editor uses) over the part of the canvas the roster leaves clear. Along each axis the box either covers that area, or sits centred in it when it is smaller, as on a very wide window. Nothing past the dot grid is reachable at any zoom.
The clamp lives in the camera itself (
_MapCamera, aTransformationControllerwhose setter runsreplayCameraClamped). Pans, wheel and pinch zoom, pan fling and the watch-a-player camera all write through that one setter, so none of them can get around it. The InteractiveViewer keeps its infiniteboundaryMarginon purpose. Its own bounds would treat the space under the roster as room, and its minimum-scale rule would force a zoom past 1 whenever the canvas is wider than the world box.Watching a player still centres them, as far as the map's edge allows. Near an edge the camera stops at the edge and the player sits off-centre but on screen. The camera slides between the two with no jump.
The infinite margin came in with the first viewer commit (a784cce), before the watch camera existed, so nothing depended on it.
Seen in the release build
Windows release build, real replays from the 13.00 corpus, real mouse and keyboard.
Panning at zoom 1, then about 2x, pushing into every edge:
Watching Sova (key 9), who starts at Split's top edge, while the round plays, then Cypher (key 2) at the bottom edge:
Same moment, before and after. Before, the camera centred Sova and showed the blank band above the dot grid. After, the map's top edge stops at the top of the view.
Window sizes:
A call you might want to undo
The clamp holds the world box, not the map art inside it. That matches the editor, and the dot grid always fills the view. It also means that zoomed in to 3x you can pan into a corner of the world box that is mostly empty dot grid with a sliver of map, like this:
Clamping to the map art's own box instead would stop at the map's outline. That's a small change to
replayCameraClamped(the map box instead of the world box), but the replay would then behave differently from the editor.One place the replay and editor differ: on a canvas wider than 16:9, InteractiveViewer's own bounds should make the editor jump past zoom 1 on the first scroll. I read that in Flutter's source and didn't check it in the app. The replay keeps the map centred there instead. I left the editor alone.
Tests
test/replay_watch_test.dart:replayCameraClampedwith hand-worked numbers: edge to edge, zoomed in, and a world box narrower than the view.The last two fail on main and pass here.
flutter teston all replay tests passes (183), andflutter analyzeis clean on the touched files.ci: analyze test
🤖 Generated with Claude Code