Source profileQuality 84/100

matthiasn/lotti/.claude/skills/app-screenshots/SKILL.md

app-screenshots

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.

Source repository stars
1,158
Declared platforms
0
Static risk flags
0
Last source update
2026-08-04
Source checked
2026-08-04

Decision brief

What it does—and where it fits

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.

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.

Not for

  • Tasks that require unconfirmed production actions or broad system permissions.
  • Environments where the pinned source and install steps cannot be inspected.

Compatibility matrix

Platform support, with evidence labels

PlatformStatusEvidenceWhat to check
CodexNot declaredNo explicit evidencePortability before use
Claude CodeNot declaredNo explicit evidencePortability before use
CursorNot declaredNo explicit evidencePortability before use
Gemini CLINot declaredNo explicit evidencePortability before use
Open the compatibility checker

Installation

Inspect first. Install second.

The source command is displayed only when detected. A safe inspection prompt is always available so your agent can explain every action before execution.

Source-detected install commandSource
npx skills add https://github.com/matthiasn/lotti --skill ".claude/skills/app-screenshots"
Safe inspection promptEditorial

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

What the source asks the agent to do

  1. 01

    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…

    Find the surface and how to reach the state. Identify the entry widgetWrite a throwaway capture test at test/scratchcapturetest.dartGenerate the PNGs:
  2. 02

    When to use

    For "is this change actually wired up / does it behave correctly", prefer the verify skill (runs the real app). This skill is about appearance.

    "Show me the in app context.""What does this change look like on mobile vs desktop?"Previewing a UI change for design review.
  3. 03

    The harness

    test/testutils/screenshotharness.dart provides:

    loadAppFonts() — loads every bundled font (app families + Material/CupertinoscreenshotTheme({bool dark = true}) — the production withOverrides themecaptureInApp(tester, {child, name, size, dark, devicePixelRatio, overrides, interaction, outputDir})
  4. 04

    Example capture test

    Review the “Example capture test” section in the pinned source before continuing.

    Review and apply the “Example capture test” source section.
  5. 05

    Gotchas

    Override lives in package:flutterriverpod/misc.dart in this Riverpod

    Override lives in package:flutterriverpod/misc.dart in this RiverpodRegister every service the surface touches via setUpTestGetIt'sDesktop layout is width-driven. captureInApp(size: ScreenshotViewport.desktop)

Permission review

Static risk signals and limitations

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

Why each signal appears

EvidenceSourceComputedTestedEditorial
SignalValueEvidence typeMeaning
Quality score84/100ComputedDocumentation, specificity, maintenance, and trust rules
Repository stars1,158SourceRepository attention, not individual Skill quality
Compatibility0 platformsSourceDeclared in the catalog source record
Usage guideautomated source guideEditorialGenerated or reviewed according to the visible evidence level

Pinned source

Provenance and original SKILL.md

Repository
matthiasn/lotti
Skill path
.claude/skills/app-screenshots/SKILL.md
Commit
9b41e4d2e01d5d4a83b4aeae7ad68353ae91be50
License
GPL-3.0
Collected
2026-08-04
Default branch
main
View the original SKILL.md

In-App Screenshots

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.

When to use

  • "Show me the <screen/modal/dialog> in app context."
  • "What does this change look like on mobile vs desktop?"
  • Previewing a UI change for design review.

For "is this change actually wired up / does it behave correctly", prefer the verify skill (runs the real app). This skill is about appearance.

The harness

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).

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 service registrations and provider overrides — copy their setUp.

  2. 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.

  3. Generate the PNGs:

    fvm flutter test --update-goldens test/_scratch_capture_test.dart
    

    Images land in test/screenshots/ (the outputDir, next to the test).

  4. View and share. Read the PNGs to inspect them; send them to the user with SendUserFile.

  5. Clean up — this is mandatory unless the user asks to keep anything:

    rm test/_scratch_capture_test.dart && rm -rf test/screenshots
    

Example capture test

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,
    );
  });
}

Gotchas

  • 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).
  • Register every service the surface touches via 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).
  • Desktop layout is width-driven. 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.
  • Capture target is find.byType(MaterialApp) so overlay content (modals, dialogs, toasts) is included, not just the page body.
  • Don't commit the scratch test or test/screenshots/. Delete them when done. The harness itself is the only permanent artifact.

Alternatives

Compare before choosing

Computed 97106

AI-Unified-Process/marketplace

browserless-test

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.

Computed 976

mgiovani/cc-arsenal

team-review

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

Computed 957

event4u-app/agent-config

playwright-testing

Use when writing Playwright E2E tests — browser automation, visual regression testing, Page Objects, fixtures, and reliable test patterns.

Computed 94165

JasonColapietro/suede-creator-skills

suede-ai-eval

Design AI evals that catch regressions before users do: rubrics, test cases, failure modes, acceptance gates, and AI-SPEC artifacts.