vantage 0.2.0
vantage: ^0.2.0 copied to clipboard
An in-app QA & developer-tools HUD for Flutter — device simulation, widget inspection, and an extensible plugin architecture for building QA tooling.
Vantage
The QA & developer-tools HUD that lives inside your Flutter app.
Simulate any device · inspect any widget · watch every request ·
and turn “it broke on my phone” into a zip a developer can act on.
Two lines of code. One floating bubble. Every tool your QA loop was missing.
No native setup. No build flavors. No wrapper around every screen. And zero cost in
release — enabled defaults to !kReleaseMode, so the whole thing tree-shakes away.
✨ Features #
- 🫧 One bubble, every tool. Tap it from any screen. Nothing else changes about your app.
- 📱 Real device simulation, not a picture of one. ~40 devices with true safe-area insets and pixel ratios — your app genuinely resizes, so a layout that collides with the home indicator fails in preview the way it fails on the phone.
- 🔍 Tap any widget. Type, size, constraints, padding, ancestor chain. Measure mode: tap two elements, get the gap, with off-grid warnings against your 8pt system.
- 🌐 Every request, with the truth about it. Status, timing, size, pretty JSON, copy as cURL — and
4xxis not lumped in with5xx, because a QA tool that cries wolf gets ignored. - 🔐 Redaction that actually holds.
accessToken,access_tokenandAccess-Tokenare one rule, plus JWTs, bearer tokens, card numbers and SSNs matched on shape alone. A shared corpus of secret-bearing payloads runs against it on every single build. - 🎬 The one-tap bug report. Breadcrumbs, errors, screenshot, network log, route stack and a real device block — zipped and handed to the share sheet. This is the feature that pays for the package.
- 🖍️ Redact before you send. An opaque mask, not a blur — because blurred PINs and card digits are recoverable, and we'd rather say so than pretend otherwise.
- ♿ Accessibility you can see. Semantics overlay, 48dp/44pt tap-target auditor, WCAG contrast maths, and pseudo-localization — strings that don't turn into
Ẽẋpãñdẽdare hardcoded, by construction. - 🧭 Deep-link launcher built in. Fire any route from inside the app. No more
adb shell am start. - ⚡ Frame-time HUD + jank journal, keyed to the route you were on when it stuttered.
- 🚩 Flip feature flags without a rebuild, and edit
SharedPreferenceslive. - 🧩 A plugin host, not a monolith. Every tool above is a plugin on a small, stable contract — and yours can be too.
- 🪶 Core depends on the Flutter SDK. Only.
dio,riverpod,shared_preferencesare separate packages. You never inherit a dependency for a feature you don't use.
🚀 Install #
# Regular dependencies, not dev_dependencies: `Vantage` is imported from
# lib/main.dart. It costs nothing in release — see above.
dependencies:
vantage: ^0.1.1
vantage_device_preview: ^0.1.0 # add only the tools you want
vantage_inspector: ^0.1.0
vantage_flight_recorder: ^0.1.0
🔌 Two lines to wire it #
void main() => runApp(
Vantage(
plugins: [
VantageDevicePreviewPlugin.withFrames(),
VantageInspectorPlugin(),
VantageFlightRecorderPlugin(),
],
builder: (context) => const MyApp(),
),
);
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) => MaterialApp(
builder: Vantage.appBuilder, // ← the only change inside your app
home: const HomeScreen(),
);
}
Vantage wraps your app; Vantage.appBuilder re-applies the simulated
MediaQuery / locale / theme inside it. Forget the second line and Vantage tells
you with an on-screen banner rather than failing silently.
🧰 The toolbox #
vantage is the host and the contract. The tools ship separately, so you take
only what you use:
| Package | What it adds |
|---|---|
📱 vantage_device_preview |
Device frames, real safe areas, locale, text scale, RTL |
🔍 vantage_inspector |
Tap-to-inspect + measure mode |
🌐 vantage_network_core |
Request inspector, redaction, cURL export |
🔌 vantage_dio · vantage_http |
Transport adapters |
🎬 vantage_flight_recorder |
Breadcrumbs, screenshot, annotate, one-tap bundle |
🧭 vantage_routing |
Route stack + deep-link launcher |
⚡ vantage_performance |
Frame-time HUD + jank journal |
🚩 vantage_flags |
Feature-flag overrides |
♿ vantage_a11y |
Semantics, tap targets, contrast, pseudo-localization |
🎨 vantage_design |
Grid, rulers, guides, mockup overlay |
💾 vantage_prefs |
Live SharedPreferences editor |
🔄 vantage_state_core · vantage_riverpod |
State history + diffs |
🛠️ Write your own plugin #
The same contract the built-in tools use:
class MyPlugin extends VantagePlugin with PanelPlugin, QuickActionsPlugin {
@override String get id => 'my_plugin';
@override String get title => 'My Tool';
@override IconData get icon => Icons.build;
@override
Widget buildPanel(BuildContext context, VantageScope scope) => const MyPanel();
@override
List<VantageQuickAction> get quickActions => [
VantageQuickAction(
id: 'seed_cart',
label: 'Seed 100 cart items',
onPressed: () => cart.seed(100), // ← your code, one tap, from any screen
),
];
}
Mix in only what you need — PanelPlugin, OverlayPlugin, AppWrapperPlugin,
QuickActionsPlugin, EventSource, ExportContributor. Adding a capability later
never breaks existing plugins, and VantageScope.of(context) is the only way a
plugin reaches the host. No singletons.
Then prove it works with the shared contract kit:
import 'package:vantage/testing.dart';
void main() => runVantagePluginContractTests('MyPlugin', MyPlugin.new);
It checks the things that are easy to get subtly wrong — stable ids, unique quick actions, panels that build unattached, broadcast event streams, and export artifacts that are safe to put in a bundle.
🎛️ Simulation, applied once #
Plugins never insert their own MediaQuery. They contribute a
VantageSimulationData and the host applies it exactly once, so two plugins can
never fight over your app's constraints:
VantageScope.of(context).updateSimulation(
const VantageSimulationData(
size: Size(320, 568),
textDirection: TextDirection.rtl,
viewInsets: EdgeInsets.only(bottom: 336), // simulate the keyboard
),
);
padding is derived from viewPadding - viewInsets, so a simulated keyboard eats
the home indicator exactly as a real one does.
🛡️ What we promise, and what we don't #
- Off in release by default.
enabledis!kReleaseMode; when off, Vantage is a pass-through — no scope, no overlay, no capture. - Redaction is a requirement, not a setting. Text artifacts are always redacted on the way into a bundle.
- We document what redaction can't catch rather than claiming a bundle is secret-free. It is pattern matching, not classification — a safety net over data your plugin already redacted, never the only line of defence.
- We don't over-claim. Where something is cooperative (dark mode) or unfinished (durable flag persistence), the docs say so. Where a tool can't work — a screenshot over a platform view, a bundle on the web — it tells you why instead of failing quietly.
📄 License #
MIT © Natesh Bhat · github.com/nateshmbhat/vantage