Best for
- "Show me the in app context."
- "What does this change look like on mobile vs desktop?"
- Previewing a UI change for design review.
matthiasn/lotti/.claude/skills/app-screenshots/SKILL.md
Capture in-app screenshots of a widget or flow at mobile + desktop sizes — offline, deterministic, real fonts and icons — using the reusable screenshot harness. Use when asked to "show me X in the app", "screenshot this screen", or to preview a UI change for review on phone vs desktop.
Decision brief
Produces PNGs of a widget or flow rendered inside the real app shell, at phone and desktop viewports, with real fonts and icons. It runs through flutter test --update-goldens — fully offline and deterministic — so it does not require a display, the GUI app, or driving the device.
Compatibility matrix
| Platform | Status | Evidence | What to check |
|---|---|---|---|
| Codex | Not declared | No explicit evidence | Portability before use |
| Claude Code | Not declared | No explicit evidence | Portability before use |
| Cursor | Not declared | No explicit evidence | Portability before use |
| Gemini CLI | Not declared | No explicit evidence | Portability before use |
Installation
The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.
npx skills add https://github.com/matthiasn/lotti --skill ".claude/skills/app-screenshots"Inspect the Agent Skill "app-screenshots" from https://github.com/matthiasn/lotti/blob/9b41e4d2e01d5d4a83b4aeae7ad68353ae91be50/.claude/skills/app-screenshots/SKILL.md at commit 9b41e4d2e01d5d4a83b4aeae7ad68353ae91be50. List every install step, command, network request, credential, file read/write, external action, and rollback step. Explain whether it fits my task. Do not install or execute anything until I approve.
Workflow
1. Find the surface and how to reach the state. Identify the entry widget (often a tab/page like ProjectsTabPage) and the tap/scroll needed to reach the state to capture (e.g. tapping the FAB to open a modal). Reuse existing widget tests for that surface to learn the required se…
For "is this change actually wired up / does it behave correctly", prefer the verify skill (runs the real app). This skill is about appearance.
test/testutils/screenshotharness.dart provides:
Review the “Example capture test” section in the pinned source before continuing.
Override lives in package:flutterriverpod/misc.dart in this Riverpod
Permission review
No configured static risk pattern was detected
This is not proof of safety. Runtime behavior, indirect dependencies, and hidden external systems are outside the static scan.
Evidence record
| Signal | Value | Evidence type | Meaning |
|---|---|---|---|
| Quality score | 84/100 | Computed | Documentation, specificity, maintenance, and trust rules |
| Repository stars | 1,158 | Source | Repository attention, not individual Skill quality |
| Compatibility | 0 platforms | Source | Declared in the catalog source record |
| Usage guide | automated source guide | Editorial | Generated or reviewed according to the visible evidence level |
Pinned source
Produces PNGs of a widget or flow rendered inside the real app shell, at phone
and desktop viewports, with real fonts and icons. It runs through
flutter test --update-goldens — fully offline and deterministic — so it does
not require a display, the GUI app, or driving the device.
This is a visualization tool, not a golden test: there are no committed reference images. You write a throwaway capture test, emit the PNGs, share them, then delete the test. Nothing screenshot-related gets committed unless the user explicitly asks to keep it.
For "is this change actually wired up / does it behave correctly", prefer the
verify skill (runs the real app). This skill is about appearance.
test/test_utils/screenshot_harness.dart provides:
loadAppFonts() — loads every bundled font (app families + Material/Cupertino
icon fonts + icon-font packages) from FontManifest.json. Call once in
setUpAll. Without it, glyphs and icons render as boxes.screenshotTheme({bool dark = true}) — the production withOverrides theme
with Inter applied to the Material text themes (the bare test theme falls
back to an unbundled font otherwise).captureInApp(tester, {child, name, size, dark, devicePixelRatio, overrides, interaction, outputDir})
— sizes the view, pumps child in the app shell, runs interaction (open a
modal, tap a FAB, focus a field…), then writes <outputDir>/<name>.png
relative to the calling test file's directory.ScreenshotViewport.phone (390×844) and ScreenshotViewport.desktop
(1280×800).Find the surface and how to reach the state. Identify the entry widget
(often a tab/page like ProjectsTabPage) and the tap/scroll needed to reach
the state to capture (e.g. tapping the FAB to open a modal). Reuse existing
widget tests for that surface to learn the required service registrations
and provider overrides — copy their setUp.
Write a throwaway capture test at test/_scratch_capture_test.dart
(the _scratch_ prefix marks it disposable). Use setUpTestGetIt +
additionalSetup for services the surface resolves through getIt, and
pass provider overrides via captureInApp(overrides: ...). Drive the state
in interaction.
Generate the PNGs:
fvm flutter test --update-goldens test/_scratch_capture_test.dart
Images land in test/screenshots/ (the outputDir, next to the test).
View and share. Read the PNGs to inspect them; send them to the user
with SendUserFile.
Clean up — this is mandatory unless the user asks to keep anything:
rm test/_scratch_capture_test.dart && rm -rf test/screenshots
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_riverpod/misc.dart'; // Override
import 'package:flutter_test/flutter_test.dart';
import 'package:lotti/classes/project_data.dart';
import 'package:lotti/features/projects/model/projects_overview_models.dart';
import 'package:lotti/features/projects/state/project_providers.dart';
import 'package:lotti/features/projects/ui/pages/projects_tab_page.dart';
import 'package:lotti/features/user_activity/state/user_activity_service.dart';
import 'package:lotti/get_it.dart';
import 'package:lotti/services/entities_cache_service.dart';
import 'package:lotti/services/nav_service.dart';
import 'package:mocktail/mocktail.dart';
import 'features/categories/test_utils.dart';
import 'features/projects/test_utils.dart';
import 'mocks/mocks.dart';
import 'test_utils/screenshot_harness.dart';
import 'widget_test_utils.dart';
void main() {
setUpAll(loadAppFonts);
final groups = [
ProjectCategoryGroup(
categoryId: 'lotti',
category: CategoryTestUtils.createTestCategory(id: 'lotti', name: 'Lotti'),
projects: [
ProjectListItemData(
project: makeTestProject(id: 'p1', title: 'Daily Operating System'),
category: CategoryTestUtils.createTestCategory(id: 'lotti', name: 'Lotti'),
taskRollup: const ProjectTaskRollupData(totalTaskCount: 25),
),
],
),
];
List<Override> overrides() => [
projectsOverviewProvider.overrideWith(
(ref) => Stream.value(ProjectsOverviewSnapshot(groups: groups)),
),
visibleProjectGroupsProvider.overrideWith((ref) => AsyncValue.data(groups)),
];
setUp(() async {
await setUpTestGetIt(
additionalSetup: () {
final activity = MockUserActivityService();
when(activity.updateActivity).thenReturn(null);
getIt.registerSingleton<UserActivityService>(activity);
final nav = MockNavService();
when(() => nav.isDesktopMode).thenReturn(false);
when(() => nav.desktopSelectedProjectId)
.thenReturn(ValueNotifier<String?>(null));
getIt.registerSingleton<NavService>(nav);
final cache = MockEntitiesCacheService();
when(() => cache.getCategoryById(any())).thenReturn(null);
getIt.registerSingleton<EntitiesCacheService>(cache);
},
);
});
tearDown(tearDownTestGetIt);
Future<void> openCreate(WidgetTester tester) =>
tester.tap(find.bySemanticsLabel('New Project'));
testWidgets('phone', (tester) async {
await captureInApp(
tester,
child: const ProjectsTabPage(),
name: 'create_mobile',
overrides: overrides(),
interaction: openCreate,
);
});
testWidgets('desktop', (tester) async {
await captureInApp(
tester,
child: const ProjectsTabPage(),
name: 'create_desktop',
size: ScreenshotViewport.desktop,
overrides: overrides(),
interaction: openCreate,
);
});
}
Override lives in package:flutter_riverpod/misc.dart in this Riverpod
version — import it for the List<Override> type (separate from
flutter_riverpod.dart, which has AsyncValue).setUpTestGetIt's
additionalSetup, or the widget throws on a missing getIt registration.
Modals pull in their own deps (e.g. the create modal's CategoryField needs
EntitiesCacheService).captureInApp(size: ScreenshotViewport.desktop)
sets both the view physical size and MediaQuery, so width-gated split
views (isDesktopLayout) and the dialog branch (modal page breakpoint)
engage correctly.find.byType(MaterialApp) so overlay content (modals,
dialogs, toasts) is included, not just the page body.test/screenshots/. Delete them when
done. The harness itself is the only permanent artifact.Alternatives
AI-Unified-Process/marketplace
Creates Vaadin Browserless server-side unit tests for Vaadin views covering navigation, component interactions, form validation, grid operations, and notifications. Use when the user asks to "write Browserless tests", "write Vaadin UI unit tests", "unit test a Vaadin view without a browser", "create view tests with the official Vaadin testing framework", or mentions Browserless testing, SpringBrowserlessTest, browserless-test-junit6, UI Unit Testing, or server-side Vaadin testing.
mgiovani/cc-arsenal
Multi-agent review team: architecture, security, performance, testing, style, docs/UX, plus an adversary that cross-examines the other 6, for security-sensitive, architectural, or large PRs (15+ files) where a single-agent pass risks missing cross-cutting issues. Use for auth/payments/PII changes, schema/pattern changes, compliance sign-off, or when asked to 'get the review team on this' / 'multi-agent review' / 'thorough review before merge'. For a standard PR or a quick pre-merge check, use /r
event4u-app/agent-config
Use when writing Playwright E2E tests — browser automation, visual regression testing, Page Objects, fixtures, and reliable test patterns.
JasonColapietro/suede-creator-skills
Design AI evals that catch regressions before users do: rubrics, test cases, failure modes, acceptance gates, and AI-SPEC artifacts.