Repository navigation
Conversation
spydon
added this pull request to stack #4135
October 24, 2026 09:50
spydon
removed this pull request from stack #4135
October 24, 2026 10:30
spydon
added this pull request to stack #4140
October 24, 2026 10:30
spydon
force-pushed
the
feat/cli-annotated-snapshot
branch
from
October 25, 2026 09:47
f1479a7 to
ef8c3f9
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds three options to
flame snapshot, so that AI models can match what they see in a snapshot with the component tree and get images that stay within their size limits:--annotate(-a) draws the outline of every visiblePositionComponenton the image, labeled with its id (the same id thatflame treeprints) and its type, and prints the annotated components asPlayer (id: 220731871) box 368,268,64,64, with the box in the pixel coordinates of the image, before the path of the image. Text only consumers get the same mapping that way.--filter(-f) is a case insensitive regular expression on the type, likeflame tree --filter, so that only the matching components are annotated. It needs--annotate.--max-size(-m) limits the longest side of the image to that many pixels. The game lowers the pixel ratio before rendering instead of resizing the image afterwards, so the aspect ratio is kept, nothing is cropped and the image stays sharp. When the ratio was lowered the command prints the size and the pixel ratio that was used, so that pixel coordinates can be converted back to canvas coordinates for the input commands.All three work for the whole game,
--world,--rectand--component, at any--pixel-ratio.Drawing on the game side
The annotations are computed and drawn on the game side, while the snapshot is rendered, in the new
packages/flame/lib/src/devtools/snapshot_annotations.dart. ThegetGameSnapshotandgetComponentSnapshotextensions take the newannotate,annotationFilterandmaxSizeparameters, and returnpixelRatioand, when annotating,annotationswith theid,nameandboxof each component.The game is the only place that knows all the transforms involved: the transforms of every position component up the tree, the viewfinder (position, zoom, angle), the viewport (position, anchor and the scale of a
FixedResolutionViewport), and the snapshot mode itself (canvas, world rect or component bounds, and the pixel ratio). Doing it on the CLI side would mean sending all of that over and duplicating the camera math in a second place that has to be kept in sync. On the game side the outline of a component is found by mapping its four corners up the tree withpositionOf,Viewport.localToGlobalandCameraComponent.localToGlobal, which are the same functions that the camera uses, so the outlines line up with the rendering by construction. A world is mapped through the camera that renders it, the backdrop of a camera through its viewport, and the box of a world, viewport or backdrop component is checked against that viewport, so components that the viewport clips away are left out. Components that are hidden withHasVisibility, that have no area or that are outside of the image are left out too, and the outlines are drawn as the rotated quad of the component, while the printed box is its axis aligned bounding box.The annotations are drawn in image pixels after the game is rendered, so the labels have the same legible size at every pixel ratio. Every outline has a dark border under a colored line, every label has a solid colored background with dark text, and a label is placed at the first of a few positions around its box that doesn't cover the labels placed before it, or at the one that covers them the least.
Older Flame versions
An older game ignores the unknown parameters, so the CLI checks that the response has
annotationswhen--annotatewas passed andpixelRatiowhen--max-sizewas passed. Otherwise it fails withThe running game does not support --annotate, update Flame to the latest version.and exit code 69, like a missing extension, before anything is written.Testing
The geometry is tested directly instead of through goldens, so the tests don't depend on font rendering: through a zoomed and moved camera, a rotated camera (compared against the pixels of the rendered snapshot), a
FixedResolutionViewport, viewport components, a camera backdrop (compared against the rendered pixels), nested and scaled components, viewport clipping,--worldwith a rect and a pixel ratio, single components, and the filtering rules. The maximum size is tested to never be exceeded through rounding. On the CLI side the options that are sent to the game, the output, the usage errors and the error for an older game are tested with a fake connection.I also verified it end to end with a small game on
flutter run -d flutter-testerwith a rotated and zoomed camera, a fixed resolution viewport, a nested child and a viewport component, and checked that the outlines in the produced PNGs line up for the whole game,--max-size,--worldand--rect --pixel-ratio 2.The options are documented in the CLI docs, the service extensions in the debug docs, and there is an example in the readme.
Checklist
docsand added dartdoc comments with///.examplesordocs.Breaking Change?
Related Issues
Part of #4131