shutter 1.2.0
shutter: ^1.2.0 copied to clipboard
Renders a Flutter project's widget previews to PNG, reusing the ones it already has, and diffs two runs pixel by pixel into before and after images of a change.
Changelog #
1.2.0 #
Shots drawn as iOS, a --widget at its own size, and a way to clear old runs.
shutter shot --platform ios(andsemantics) draws every preview as iOS instead of Android, the platformflutter testruns as:defaultTargetPlatformisiOSwhile each preview is shot, so a theme without its ownplatform, the back button, page transitions, adaptive widgets, and the app's owndefaultTargetPlatformchecks draw as on an iPhone.shotprints it,manifest.jsonrecords it, anddiffprints both runs' when they differ. It is not part of shot ids.shutter shot --widget <expression> --size unboundedlays the widget out with neither dimension bounded and shoots it at its own size, however wide; without--size, its width still stops at the viewport's 800.shutter prune --keep <n>deletes every run under.dart_tool/shutter/runs/but the newest n, and prints the run directories it removed and kept. A run still being shot is left as it is.
1.1.1 #
Host fallback fonts for any script the host has a font for, and in text whose style keeps them out.
- CJK and emoji in a
CupertinoAlertDialog, and in a style with its ownfontFamilyFallbacksuch as google_fonts', rendered as boxes in a shot reportedok; they now fall back to the host fonts. - Scripts beyond CJK and emoji rendered as boxes too. Every run now loads the host's UI font and its fonts for Simplified Chinese, Hangul, Thai, Arabic, Hebrew, and Devanagari, and a character none of those draw falls back to a host font that draws it.
- The manual and the agent playbook say where the host fonts do not reach: text a widget paints itself, such as a
Slider's value indicator, under aThemebuilt in awrapperor the preview function.
1.1.0 #
The semantics tree as an image.
shutter semanticstakes the same preview files,--widget, and options asshot(except--keyboard-tint) and draws each shot's semantics tree instead of what the app paints, as Flutter'sSemanticsDebuggerdraws it: a box per node with its label and what it is or does. The PNG has the size of theshotPNG, anddiffcompares two such runs as any others, so a change to what TalkBack and VoiceOver read shows when the pixels do not change.- A
semanticsrun recordsimage: semanticsinmanifest.json;semanticsprints it, anddiffprints both runs'imagewhen they differ. It is not part of shot ids. - The
shutter-visual-checkskill also covers changes to what assistive technology reads.
1.0.0 #
Network images, from files fetched beforehand, and the on-screen keyboard's area in a color.
shutter shot --network-image <url>=<file>(repeatable) serves the file to aNetworkImagethat requests the URL, whichflutter testotherwise answers with 400. A URL that is not served still fails, so a missed image stays anerrorshot. Only whatNetworkImagefetches is served; other HTTP clients such aspackage:httpare not.shotprints each URL with its file and sha256,manifest.jsonrecords them, anddiffprints both runs' when they differ. They are not part of shot ids.shutter shot --keyboard-tint <color>(experimental, with--keyboard) paints the keyboard's area in the color, given asRRGGBBorAARRGGBB: over what the app paints there in either capture, and over menus and dialogs with--capture screen. It only paints; actions reach the app under it.shotprints it,manifest.jsonrecords it, anddiffprints both runs' when they differ.
0.2.2 #
One image per change: before, diff and after on a single sheet.
shutter diff --compositewrites<id>-composite.pngper entry into.dart_tool/shutter/diffs/<diff-id>/, next to what--imageswrites: the before, diff and after panels on the union canvas of the two shots, each under a caption naming it and, when the two sides differ in size, its own size. The entry points at it ascomposite.--direction horizontalputs the three panels side by side,verticalstacks them, and the defaultautoputs a portrait shot side by side and a landscape one stacked, so that all three stay in one view whatever the subject's shape. The panels are never scaled;--imagesstays the 1:1 view of the marked diff.- An entry with an image on one side only gets a sheet too, its absent panel left as background and its diff panel all red: a widget the edit broke, or one whose id the edit changed, is shown rather than left out. An entry whose two PNGs are identical gets none.
--title <text>draws a line of text above the panels. It is rendered through the engine rather than drawn from a bundled bitmap font, so any script the host has a font for works, and it is laid out in exactly the room each size of sheet leaves between its gutters, at the size of that sheet's captions. A title that did not fit one line is reported on stderr with the width of the sheets it did not fit.--titleis the only part ofdiffthat needs a Flutter SDK, and costs oneflutter testrun per distinct sheet size. Without it,diffstays pure Dart.- The diff directory is created, and reported as
diff, for either--imagesor--composite.
0.2.1 #
The layout of a screen while its on-screen keyboard is up.
shutter shot --keyboard <height>(experimental) lays every preview out as a device does while its on-screen keyboard is up: the view reports a bottom inset of that many logical pixels (MediaQuery.viewInsets) from the first frame. AScaffold, or any layout reading the inset, makes room for the keyboard; the keyboard itself is not drawn. There is no default height.shotprints the height,manifest.jsonrecords it, anddiffprints both runs' when they differ. It is not part of shot ids.
0.2.0 #
States that come from a gesture or typing, and what opens above a preview.
shutter shot --tapand--enter <target>=<text>(repeatable, run in the order given), then one of--press,--hover, or--focus, act on every preview before the capture. A target iskey:<value>,text:<string>,label:<semantics label>(a text field's label or hint, a button's text), ortype:<Widget>; a target that matches no widget, several, or cannot be reached makes the shot an error. Each action is followed by--settlemilliseconds drawn in 16 ms frames;shutter agentsuggests--settle 700for the state after a tap, once its ink is over, and another--settlefor another point of an animation.shutter shot --capture screencaptures the whole viewport, with the shell's surface and the menus, dialogs, bottom sheets, and tooltips the app draws above the preview;--viewport <width>x<height>sets the viewport, the preview at its top left.shotprints the run's actions and capture,manifest.jsonrecords them, anddiffprints both runs' when they differ. They are not part of shot ids.- The
shutter-visual-checkskill also covers pressed, hovered, focused, opened, and typed states.
0.1.1 #
Documentation and package metadata; the tool behaves as in 0.1.0.
- The package description, the README, and
shutter --helpopen on what shutter produces, a change to a widget expressed as before and after images, instead of on the agent that drives it. - The
aitopic is replaced bycli: shutter is a command-line tool an agent can drive, not an AI package. - README lists when to reach for shutter: a change going up for review, a refactor that should change nothing on screen, a widget that might break on screen, a dependency just added or upgraded.
shutter agentsays whatshot --widgetanswers, a look at a widget before the call site exists, names the commands that upload an image to a pull or merge request, and states that--importreaches only what the project'spubspec.yamlresolves.- Flutter's previewer is called by its name, the Flutter Widget Previewer.
0.1.0 #
Initial release: a CLI, shaped for AI agents, that renders Flutter widgets to PNG and compares two runs.
shutter shotrenders the@Previewfunctions of the named files, or one--widgetexpression, to PNG throughflutter test. The target project gains no dependency.shutter diffcompares two runs by shot id aschanged,added,removed, orunchanged;--imagesmarks the differing pixels.shutter initwrites the shell that wraps every shot, andshutter doctorchecks the setup.shutter agentandshutter manualprint the playbook and the reference; theshutter-visual-checkskill points agents at them.- Requires Flutter 3.47+ (Dart 3.13+) in the target project.
Experimental (specification not settled):
- The default shell generated for the design library the project uses.
- A preview's
theme, through Flutter's unstablePreviewThemeDatainterface. - google_fonts, downloaded once into
.dart_tool/shutter/fonts/google_fonts/and served as bundled assets.