frameguard 0.6.0 copy "frameguard: ^0.6.0" to clipboard
frameguard: ^0.6.0 copied to clipboard

FrameGuard — performance regressions, testable. Capture Flutter frame timings, classify jank, enforce budgets, compare baselines, and fail CI on measurable UI regressions. Local by default. No telemetry.

FrameGuard logo

FrameGuard

Performance regressions, testable.
Automated Flutter UI performance regression detection — budgets, baselines, and evidence-backed reports you can enforce in CI.

pub package pub points likes CI Pages license

stars issues PRs Flutter Dart docs thanks.dev Sponsor

Docs · pub.dev · CLI · Changelog · Sponsor

FrameGuard banner


Status #

Version 0.6.0
Repository github.com/theworker02/frameguard
Package pub.dev/packages/frameguard
Docs site theworker02.github.io/frameguard
License MIT
Telemetry None — local by default

Why FrameGuard? #

Flutter already has excellent profilers. DevTools answers:

What happened during this profiling session?

FrameGuard answers:

Did performance regress, where, why is that likely, and should this build fail?

DevTools FrameGuard
Goal Interactive exploration Automation & regression gates
Output Timelines you interpret Budgets, baselines, matchers, CI exit codes
Audience Humans in a profiling session Humans and pipelines
Telemetry N/A None — local by default

FrameGuard is not a thin DevTools wrapper. It turns documented Flutter frame timings into reproducible explanations.


Features #

  • Session capture via SchedulerBinding.addTimingsCallback / FrameTiming
  • Refresh-rate-aware budgets (60 / 90 / 120 / 144 Hz — no hardcoded 16.67 ms dogma)
  • Jank severity (healthy / minor / major / severe)
  • Percentiles — p50 / p90 / p95 / p99, histograms, streaks
  • Build vs raster classification (derived, never claimed as certainty)
  • Regions & rebuild counts (FrameGuardRegion)
  • Traces, markers, sync tasks
  • Explainability + recommendations tied to evidence (FG001FG010)
  • JSON / text / HTML reports (versioned schema)
  • CSV · JUnit · SARIF · Markdown exporters for CI / PR comments
  • Baselines & golden files (never silently overwritten)
  • Multi-run statistics (median, MAD, CI; outliers flagged, not deleted)
  • Test matchers + FrameGuardTest.measure
  • CLI for compare / check / export / summary / doctor / baseline / history / suggest-budget
  • Local history (JSONL) for gradual drift without a backend
  • Reusable GitHub Action (.github/actions/frameguard-check)
  • Optional overlay & runtime budget watcher
  • Capability model — Unavailable beats fake zeros

Install #

# pubspec.yaml
dependencies:
  frameguard: ^0.6.0

For tests-only usage you can keep it under dev_dependencies. Test helpers live in a separate library:

import 'package:frameguard/frameguard.dart';
import 'package:frameguard/frameguard_test.dart';
flutter pub get

Quick start #

import 'package:flutter/material.dart';
import 'package:frameguard/frameguard.dart';

void main() {
  FrameGuard.initialize(
    config: FrameGuardConfig(
      samplingMode: SamplingMode.balanced,
      defaultBudget: FrameBudget.forRefreshRate(60, maxJankRate: 0.02),
    ),
  );

  runApp(
    const FrameGuardScope(
      child: FrameGuardOverlay(
        compact: true,
        child: MyApp(),
      ),
    ),
  );
}

Capture a session #

final session = FrameGuard.startSession(name: 'home_scroll');
// …interact with the app…
final report = await session.stop();

debugPrint(report.summary());
await report.writeJson(File('reports/home_scroll.json'));
await report.writeHtml(File('reports/home_scroll.html'));

Assert in tests #

testWidgets('product list stays within budget', (tester) async {
  await tester.pumpWidget(const App());

  final report = await FrameGuardTest.measure(
    tester,
    name: 'product_list',
    action: () async {
      await tester.fling(find.byType(ListView), const Offset(0, -1000), 1000);
      await tester.pumpAndSettle();
    },
  );

  expect(
    report,
    meetsFrameBudget(
      FrameBudget.forRefreshRate(
        60,
        maxJankFrames: 2,
        maxJankRate: 0.01,
      ),
    ),
  );
});

Example FrameGuard report


Budgets & baselines #

final budget = FrameBudget(
  maxJankFrames: 2,
  maxJankRate: 0.01,
  maxP95FrameTime: const Duration(milliseconds: 16),
  maxP99FrameTime: const Duration(milliseconds: 24),
);

final evaluation = report.evaluate(budget);
if (!evaluation.passed) {
  fail(evaluation.summary());
}

Optional project YAML (Dart config remains primary):

cp frameguard.yaml.example frameguard.yaml
dart run frameguard config validate

Update baselines deliberately:

dart run frameguard baseline update reports/catalog.json --out baselines/catalog.json
dart run frameguard check reports/current.json --baseline baselines/catalog.json

Exit codes: 0 pass · 1 regression · 2 invalid config/report.


CLI #

dart run frameguard help
dart run frameguard init
dart run frameguard doctor
dart run frameguard list
dart run frameguard explain report.json
dart run frameguard frames report.json --janky-only
dart run frameguard top report.json
dart run frameguard check reports/ --baseline baselines/ --profile mid_range --require-profile
dart run frameguard suggest-budget reports/home.json --format dart
dart run frameguard history append reports/home.json
dart run frameguard summary report.json --format markdown
dart run frameguard batch reports/ --format junit --out-dir reports/exports
dart run frameguard watch reports/ --once
dart run frameguard completions --shell bash

Full command map: doc/cli.md · docs/cli.html.


CI #

Gate performance reports in GitHub Actions:

- uses: theworker02/frameguard/.github/actions/frameguard-check@main
  with:
    report: reports/
    baseline: baselines/
    profile: mid_range
    require-profile: 'true'

Or call the CLI directly:

dart run frameguard check reports/ --baseline baselines/ --require-profile --profile mid_range
dart run frameguard summary reports/catalog.json --format markdown >> "$GITHUB_STEP_SUMMARY"

More: doc/ci.md.


Regions, traces, markers #

FrameGuardRegion(
  name: 'product_grid',
  child: ProductGrid(),
);

await FrameGuard.trace('open_product', () async {
  await Navigator.of(context).push(...);
});

FrameGuard.mark('products_loaded', metadata: {'count': 42});

await FrameGuard.measureTask('parse_catalog', () => parseCatalog(data));

Scenarios & statistics #

final result = await FrameScenarioRunner(
  scenario: const FrameScenario(name: 'catalog_scroll', warmupFrames: 30),
  runs: 5,
  budget: FrameBudget.forRefreshRate(120),
).runAggregated((i) async {
  await scrollCatalog();
});

debugPrint(result.summary());

Details: doc/scenarios.md.


Platform support #

Platform Frame timings Image cache Overlay Notes
Android / iOS Yes Yes Yes Prefer profile for gates
Desktop Yes Yes Yes
Web Best-effort Best-effort Yes Absolute ms budgets vary by browser

Native extras (JankStats, signposts, GPU counters) are Unavailable until real adapters ship — we will not invent zeros. See FrameGuard.capabilities and platform adapters.


Privacy #

  • No analytics
  • No telemetry
  • No accounts
  • No required dashboard
  • Reports stay on disk under your control

Documentation #

Product site Guide, CLI, diagnostics, brand
Brand kit Voice, color, logo
Docs index Package guides
API cookbook Common workflows
CI integration Pipelines & Action
Diagnostics FG001–FG010 What each finding means
Contributing Dev workflow
Changelog SemVer history
Security Vulnerability reporting
Code of Conduct Community norms
Sponsor thanks.dev / GitHub Sponsors

API reference (after publish): pub.dev/documentation/frameguard


Example & benchmarks #

cd example && flutter run --profile
flutter test
flutter test benchmark/overhead_benchmark.dart

The example app includes intentional jank scenarios (rebuild storm, CPU stall, raster stress, …) so you can validate FrameGuard against known behavior.


Roadmap (honest) #

Shipped foundations: sessions, budgets, baselines, CI, explainability, exporters, scenario stats, local history, budget suggestions.

Next (when evidence exists — never as fake features):

  • Deeper GC / memory correlation where public APIs allow
  • Android JankStats / iOS signpost adapters
  • DevTools extension
  • Historical trend dashboards (still local-first)

Contributing #

PRs welcome. Please read CONTRIBUTING.md and the Code of Conduct.

dart format .
flutter analyze
flutter test

Bug reports & ideas: Issues


License #

MIT — see LICENSE.

Support development #


FrameGuard — make performance regressions testable the way functional regressions already are.

0
likes
140
points
0
downloads
screenshot

Documentation

Documentation
API reference

Publisher

unverified uploader

Weekly Downloads

FrameGuard — performance regressions, testable. Capture Flutter frame timings, classify jank, enforce budgets, compare baselines, and fail CI on measurable UI regressions. Local by default. No telemetry.

Homepage
Repository (GitHub)
View/report issues
Contributing

Topics

#flutter #performance #jank #testing #ci

License

MIT (license)

Dependencies

args, collection, flutter, flutter_test, meta, path

More

Packages that depend on frameguard