ginskill-init 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/.wrangler/cache/pages.json +4 -0
  2. package/.wrangler/cache/wrangler-account.json +6 -0
  3. package/DEVELOPMENT.md +510 -0
  4. package/README.md +104 -0
  5. package/agents/developer.md +56 -0
  6. package/agents/frontend-design.md +69 -0
  7. package/agents/mobile-reviewer.md +36 -0
  8. package/agents/review-code.md +49 -0
  9. package/agents/security-scanner.md +50 -0
  10. package/agents/tester.md +72 -0
  11. package/bin/cli.js +461 -0
  12. package/landing/ai-build-ai.png +0 -0
  13. package/landing/index.html +1495 -0
  14. package/landing/logo.png +0 -0
  15. package/package.json +37 -0
  16. package/skills/active-life-dev/SKILL.md +157 -0
  17. package/skills/active-life-dev/docs/auth.md +187 -0
  18. package/skills/active-life-dev/docs/customers.md +216 -0
  19. package/skills/active-life-dev/docs/integrations.md +209 -0
  20. package/skills/active-life-dev/docs/inventory.md +192 -0
  21. package/skills/active-life-dev/docs/modules.md +181 -0
  22. package/skills/active-life-dev/docs/orders.md +180 -0
  23. package/skills/active-life-dev/docs/patterns.md +319 -0
  24. package/skills/active-life-dev/docs/products.md +216 -0
  25. package/skills/active-life-dev/docs/schema.md +502 -0
  26. package/skills/active-life-dev/docs/setup.md +169 -0
  27. package/skills/active-life-dev/docs/vouchers.md +144 -0
  28. package/skills/ai-asset-generator/SKILL.md +247 -0
  29. package/skills/ai-asset-generator/docs/gen-image.md +274 -0
  30. package/skills/ai-asset-generator/docs/genvideo.md +341 -0
  31. package/skills/ai-asset-generator/docs/remove-background.md +19 -0
  32. package/skills/ai-asset-generator/lib/bg-remove.mjs +34 -0
  33. package/skills/ai-asset-generator/lib/env.mjs +48 -0
  34. package/skills/ai-asset-generator/lib/kie-client.mjs +100 -0
  35. package/skills/ai-build-ai/SKILL.md +127 -0
  36. package/skills/ai-build-ai/docs/agent-teams.md +293 -0
  37. package/skills/ai-build-ai/docs/checkpointing.md +161 -0
  38. package/skills/ai-build-ai/docs/create-agent.md +399 -0
  39. package/skills/ai-build-ai/docs/create-mcp.md +395 -0
  40. package/skills/ai-build-ai/docs/create-skill.md +299 -0
  41. package/skills/ai-build-ai/docs/headless-mode.md +614 -0
  42. package/skills/ai-build-ai/docs/hooks.md +578 -0
  43. package/skills/ai-build-ai/docs/memory-claude-md.md +375 -0
  44. package/skills/ai-build-ai/docs/output-styles.md +208 -0
  45. package/skills/ai-build-ai/docs/overview.md +162 -0
  46. package/skills/ai-build-ai/docs/permissions.md +391 -0
  47. package/skills/ai-build-ai/docs/plugins.md +396 -0
  48. package/skills/ai-build-ai/docs/sandbox.md +262 -0
  49. package/skills/ai-build-ai/docs/team-lead-workflow.md +648 -0
  50. package/skills/ant-design/SKILL.md +323 -0
  51. package/skills/ant-design/docs/components.md +160 -0
  52. package/skills/ant-design/docs/data-entry.md +406 -0
  53. package/skills/ant-design/docs/display.md +594 -0
  54. package/skills/ant-design/docs/feedback.md +451 -0
  55. package/skills/ant-design/docs/key-components.md +414 -0
  56. package/skills/ant-design/docs/navigation.md +310 -0
  57. package/skills/ant-design/docs/pro-components.md +543 -0
  58. package/skills/ant-design/docs/setup.md +213 -0
  59. package/skills/ant-design/docs/theme.md +265 -0
  60. package/skills/flutter-performance/SKILL.md +803 -0
  61. package/skills/flutter-performance/references/flutter-patterns.md +595 -0
  62. package/skills/icon-generator/SKILL.md +270 -0
  63. package/skills/mobile-app-review/SKILL.md +321 -0
  64. package/skills/mobile-app-review/references/apple-review.md +132 -0
  65. package/skills/mobile-app-review/references/google-play-review.md +203 -0
  66. package/skills/mongodb/SKILL.md +667 -0
  67. package/skills/mongodb/references/mongoose-patterns.md +368 -0
  68. package/skills/nestjs-architecture/SKILL.md +1086 -0
  69. package/skills/nestjs-architecture/references/advanced-patterns.md +590 -0
  70. package/skills/performance/SKILL.md +509 -0
  71. package/skills/react-fsd-architecture/SKILL.md +693 -0
  72. package/skills/react-fsd-architecture/references/fsd-patterns.md +747 -0
  73. package/skills/react-native-expo/SKILL.md +128 -0
  74. package/skills/react-native-expo/references/data-layer.md +252 -0
  75. package/skills/react-native-expo/references/design-system.md +252 -0
  76. package/skills/react-native-expo/references/navigation.md +199 -0
  77. package/skills/react-native-expo/references/performance.md +229 -0
  78. package/skills/react-native-expo/references/platform-services.md +179 -0
  79. package/skills/react-native-expo/references/state-management.md +209 -0
  80. package/skills/react-native-expo/references/ui-patterns.md +301 -0
  81. package/skills/react-query/SKILL.md +685 -0
  82. package/skills/react-query/references/query-patterns.md +365 -0
  83. package/skills/review-code/SKILL.md +374 -0
  84. package/skills/review-code/references/clean-code-principles.md +395 -0
  85. package/skills/review-code/references/frontend-patterns.md +136 -0
  86. package/skills/review-code/references/nestjs-patterns.md +184 -0
  87. package/skills/security-scanner/SKILL.md +366 -0
  88. package/skills/security-scanner/references/nestjs-security.md +260 -0
  89. package/skills/security-scanner/references/nextjs-security.md +201 -0
  90. package/skills/security-scanner/references/react-native-security.md +199 -0
  91. package/skills/traefik/SKILL.md +105 -0
  92. package/skills/traefik/docs/advanced-routing.md +186 -0
  93. package/skills/traefik/docs/auth-providers.md +137 -0
  94. package/skills/traefik/docs/cicd-devops.md +396 -0
  95. package/skills/traefik/docs/core-config.md +171 -0
  96. package/skills/traefik/docs/distributed-config.md +96 -0
  97. package/skills/traefik/docs/docker-compose.md +182 -0
  98. package/skills/traefik/docs/ha-performance.md +177 -0
  99. package/skills/traefik/docs/kubernetes.md +278 -0
  100. package/skills/traefik/docs/middleware.md +205 -0
  101. package/skills/traefik/docs/monitoring.md +357 -0
  102. package/skills/traefik/docs/security.md +391 -0
  103. package/skills/traefik/docs/tls-acme.md +155 -0
  104. package/skills/ui-ux-pro-max/SKILL.md +377 -0
  105. package/skills/ui-ux-pro-max/data/charts.csv +26 -0
  106. package/skills/ui-ux-pro-max/data/colors.csv +97 -0
  107. package/skills/ui-ux-pro-max/data/icons.csv +101 -0
  108. package/skills/ui-ux-pro-max/data/landing.csv +31 -0
  109. package/skills/ui-ux-pro-max/data/products.csv +97 -0
  110. package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  111. package/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  112. package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  113. package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  114. package/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  115. package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  116. package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  117. package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  118. package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  119. package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  120. package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  121. package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  122. package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  123. package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  124. package/skills/ui-ux-pro-max/data/styles.csv +68 -0
  125. package/skills/ui-ux-pro-max/data/typography.csv +58 -0
  126. package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  127. package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  128. package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
@@ -0,0 +1,803 @@
1
+ ---
2
+ name: flutter-performance
3
+ description: |
4
+ **Flutter Performance Optimization**: Comprehensive guide for optimizing Flutter app performance — widget rebuilds, jank reduction, memory leaks, Dart isolates, image caching, state management perf, Impeller rendering, DevTools profiling. Targets 60/120fps production apps.
5
+ - MANDATORY TRIGGERS: flutter performance, flutter optimization, flutter jank, flutter fps, flutter rebuild, flutter memory leak, flutter isolate, flutter image cache, flutter profiling, flutter devtools, flutter impeller, flutter shader, flutter widget rebuild, flutter slow, flutter laggy, flutter frame drop, flutter startup time, flutter app size, flutter tree shaking, flutter repaint boundary, flutter const constructor, flutter state management performance, flutter listview performance, flutter animation performance, dart isolate, flutter scroll jank, flutter build method, flutter dispose
6
+ - Use this skill whenever the user is optimizing Flutter app performance, debugging jank or frame drops, profiling with DevTools, fixing memory leaks, or reviewing Flutter code for performance anti-patterns. Also trigger when discussing widget rebuild optimization, Impeller rendering, Dart isolate usage, or app size reduction — even casual mentions like "my Flutter app is slow" or "how do I improve FPS?".
7
+ ---
8
+
9
+ # Flutter Performance Optimization
10
+
11
+ Analyze and optimize Flutter apps for consistent 60/120fps rendering. Covers widget rebuilds, jank elimination, memory management, Dart isolates, image optimization, Impeller rendering, and DevTools profiling. Targets production apps on both iOS and Android.
12
+
13
+ ## Core Mental Model
14
+
15
+ **Flutter renders at 60fps (16ms per frame) or 120fps (8ms per frame).** Every frame goes through Build → Layout → Paint → Composite. If any phase exceeds the frame budget, you get jank — visible stuttering. The goal: keep the main isolate free for UI work, minimize widget rebuilds, and let Impeller handle GPU rendering efficiently.
16
+
17
+ Key principles:
18
+ - **Measure first** — use DevTools before optimizing blindly
19
+ - **Rebuild less** — const constructors, selective state, RepaintBoundary
20
+ - **Offload heavy work** — Dart isolates for CPU-intensive tasks
21
+ - **Cache aggressively** — images, computed values, widget subtrees
22
+ - **Let Impeller work** — avoid patterns that defeat its optimizations
23
+
24
+ ## 1. Widget Rebuild Optimization
25
+
26
+ ### const Constructors (Up to 70% Fewer Rebuilds)
27
+
28
+ ```dart
29
+ // BAD — rebuilds every time parent rebuilds
30
+ Widget build(BuildContext context) {
31
+ return Column(
32
+ children: [
33
+ Text('Static Title'), // rebuilt unnecessarily
34
+ Icon(Icons.star), // rebuilt unnecessarily
35
+ MyDynamicWidget(data: _data),
36
+ ],
37
+ );
38
+ }
39
+
40
+ // GOOD — const widgets are skipped during rebuild
41
+ Widget build(BuildContext context) {
42
+ return Column(
43
+ children: [
44
+ const Text('Static Title'), // skipped — same instance
45
+ const Icon(Icons.star), // skipped — same instance
46
+ MyDynamicWidget(data: _data), // only this rebuilds
47
+ ],
48
+ );
49
+ }
50
+ ```
51
+
52
+ Enable the `prefer_const_constructors` lint:
53
+ ```yaml
54
+ # analysis_options.yaml
55
+ linter:
56
+ rules:
57
+ prefer_const_constructors: true
58
+ prefer_const_declarations: true
59
+ prefer_const_literals_to_create_immutables: true
60
+ ```
61
+
62
+ ### Decompose Large build() Methods
63
+
64
+ ```dart
65
+ // BAD — 200+ line build method, entire tree rebuilds on any setState
66
+ Widget build(BuildContext context) {
67
+ return Scaffold(
68
+ appBar: AppBar(title: Text(widget.title)),
69
+ body: Column(children: [
70
+ // ...hundreds of lines of widgets...
71
+ ]),
72
+ );
73
+ }
74
+
75
+ // GOOD — extracted const/stateless sub-widgets
76
+ Widget build(BuildContext context) {
77
+ return Scaffold(
78
+ appBar: AppBar(title: Text(widget.title)),
79
+ body: Column(children: [
80
+ const HeaderSection(), // separate StatelessWidget
81
+ ContentSection(data: _data), // only rebuilds when _data changes
82
+ const FooterSection(), // separate StatelessWidget
83
+ ]),
84
+ );
85
+ }
86
+ ```
87
+
88
+ ### Avoid Inline Closures That Cause Rebuilds
89
+
90
+ ```dart
91
+ // BAD — new function instance every build → child always rebuilds
92
+ ListView.builder(
93
+ itemBuilder: (context, index) => ItemTile(
94
+ onTap: () => _handleTap(items[index]), // new closure each build
95
+ ),
96
+ )
97
+
98
+ // GOOD — stable callback reference
99
+ ListView.builder(
100
+ itemBuilder: (context, index) => ItemTile(
101
+ item: items[index],
102
+ onTap: _handleTap, // stable reference, pass item via widget
103
+ ),
104
+ )
105
+ ```
106
+
107
+ ### Selective setState — Minimize Rebuild Scope
108
+
109
+ ```dart
110
+ // BAD — setState at root rebuilds EVERYTHING
111
+ class _HomePageState extends State<HomePage> {
112
+ int _counter = 0;
113
+ void _increment() => setState(() => _counter++);
114
+
115
+ Widget build(BuildContext context) {
116
+ return Column(children: [
117
+ const HeavyHeader(), // rebuilds unnecessarily!
118
+ Text('$_counter'),
119
+ const HeavyFooter(), // rebuilds unnecessarily!
120
+ ]);
121
+ }
122
+ }
123
+
124
+ // GOOD — isolate changing widget with a dedicated StatefulWidget or Builder
125
+ class _HomePageState extends State<HomePage> {
126
+ Widget build(BuildContext context) {
127
+ return Column(children: [
128
+ const HeavyHeader(),
129
+ const CounterWidget(), // only this subtree rebuilds
130
+ const HeavyFooter(),
131
+ ]);
132
+ }
133
+ }
134
+ ```
135
+
136
+ ### RepaintBoundary — Isolate Expensive Paints
137
+
138
+ ```dart
139
+ // Wrap frequently-animating or complex widgets
140
+ RepaintBoundary(
141
+ child: CustomPaint(
142
+ painter: ComplexChartPainter(data),
143
+ size: const Size(300, 200),
144
+ ),
145
+ )
146
+ ```
147
+
148
+ Use when: animations, custom painters, frequently-updating regions. Don't overuse — each boundary has memory overhead for its own layer.
149
+
150
+ ## 2. List & Scroll Performance
151
+
152
+ ### ListView.builder (Lazy Construction)
153
+
154
+ ```dart
155
+ // BAD — builds ALL items upfront, even offscreen
156
+ ListView(
157
+ children: items.map((item) => ItemTile(item: item)).toList(),
158
+ )
159
+
160
+ // GOOD — only builds visible items + cacheExtent
161
+ ListView.builder(
162
+ itemCount: items.length,
163
+ itemExtent: 72, // skip measurement pass — major win for fixed-height items
164
+ itemBuilder: (context, index) => ItemTile(item: items[index]),
165
+ )
166
+ ```
167
+
168
+ ### cacheExtent Tuning
169
+
170
+ ```dart
171
+ ListView.builder(
172
+ cacheExtent: 500, // pixels to pre-build offscreen (default: 250)
173
+ // Higher = smoother fast scrolling, but more memory
174
+ // Lower = less memory, but may show blank frames during fast scroll
175
+ )
176
+ ```
177
+
178
+ ### SliverList for Mixed Scroll Content
179
+
180
+ ```dart
181
+ // Instead of nesting ListView inside ScrollView:
182
+ CustomScrollView(
183
+ slivers: [
184
+ const SliverToBoxAdapter(child: HeaderWidget()),
185
+ SliverList.builder(
186
+ itemCount: items.length,
187
+ itemBuilder: (context, index) => ItemTile(item: items[index]),
188
+ ),
189
+ const SliverToBoxAdapter(child: FooterWidget()),
190
+ ],
191
+ )
192
+ ```
193
+
194
+ ### Keys for Stateful List Items
195
+
196
+ ```dart
197
+ // BAD — index keys cause state mismatch on reorder/insert
198
+ ListView.builder(
199
+ itemBuilder: (context, index) => ItemTile(key: ValueKey(index)),
200
+ )
201
+
202
+ // GOOD — stable unique key preserves widget state
203
+ ListView.builder(
204
+ itemBuilder: (context, index) => ItemTile(key: ValueKey(items[index].id)),
205
+ )
206
+ ```
207
+
208
+ ## 3. Image Optimization
209
+
210
+ ### CachedNetworkImage (Disk + Memory Cache)
211
+
212
+ ```dart
213
+ import 'package:cached_network_image/cached_network_image.dart';
214
+
215
+ CachedNetworkImage(
216
+ imageUrl: '$cdnBaseUrl/product/${product.id}.webp?w=400&q=75',
217
+ placeholder: (context, url) => const ShimmerPlaceholder(),
218
+ errorWidget: (context, url, error) => const Icon(Icons.error),
219
+ memCacheWidth: 400, // decode at display size, not full resolution
220
+ memCacheHeight: 400,
221
+ fadeInDuration: const Duration(milliseconds: 200),
222
+ )
223
+ ```
224
+
225
+ ### Precache Critical Images
226
+
227
+ ```dart
228
+ @override
229
+ void didChangeDependencies() {
230
+ super.didChangeDependencies();
231
+ // Precache hero images before they're needed
232
+ precacheImage(
233
+ const AssetImage('assets/images/hero.webp'),
234
+ context,
235
+ );
236
+ precacheImage(
237
+ NetworkImage('$cdnUrl/banner.webp'),
238
+ context,
239
+ );
240
+ }
241
+ ```
242
+
243
+ ### Resolution-Aware Loading
244
+
245
+ ```dart
246
+ // Request appropriately-sized images from CDN
247
+ final pixelRatio = MediaQuery.devicePixelRatioOf(context);
248
+ final width = (containerWidth * pixelRatio).toInt();
249
+ final imageUrl = '$cdnUrl/image.webp?w=$width&q=80&fm=webp';
250
+ ```
251
+
252
+ ### Image Memory Budget
253
+
254
+ | Device RAM | ImageCache Size | ImageCache Size Bytes |
255
+ |---|---|---|
256
+ | 1-2 GB | 50 images | 50 MB |
257
+ | 3-4 GB | 100 images | 100 MB |
258
+ | 6+ GB | 200 images | 200 MB |
259
+
260
+ ```dart
261
+ // Tune ImageCache in main()
262
+ PaintingBinding.instance.imageCache.maximumSize = 100;
263
+ PaintingBinding.instance.imageCache.maximumSizeBytes = 100 << 20; // 100 MB
264
+ ```
265
+
266
+ ## 4. Memory Management
267
+
268
+ ### Top Memory Leak Sources (90% of Leaks)
269
+
270
+ **1. Undisposed Controllers:**
271
+ ```dart
272
+ // BAD — controller leaks
273
+ class _MyState extends State<MyWidget> {
274
+ final _controller = TextEditingController();
275
+ final _scrollController = ScrollController();
276
+ // ... no dispose()
277
+ }
278
+
279
+ // GOOD — always dispose
280
+ @override
281
+ void dispose() {
282
+ _controller.dispose();
283
+ _scrollController.dispose();
284
+ super.dispose();
285
+ }
286
+ ```
287
+
288
+ **2. Uncancelled Stream Subscriptions:**
289
+ ```dart
290
+ // BAD — subscription leaks after widget unmounts
291
+ late StreamSubscription _sub;
292
+
293
+ @override
294
+ void initState() {
295
+ super.initState();
296
+ _sub = myStream.listen((data) => setState(() => _data = data));
297
+ }
298
+
299
+ // GOOD — cancel in dispose
300
+ @override
301
+ void dispose() {
302
+ _sub.cancel();
303
+ super.dispose();
304
+ }
305
+ ```
306
+
307
+ **3. AnimationController Leaks:**
308
+ ```dart
309
+ // GOOD — dispose animation controllers
310
+ class _AnimState extends State<AnimWidget> with SingleTickerProviderStateMixin {
311
+ late final AnimationController _controller;
312
+
313
+ @override
314
+ void initState() {
315
+ super.initState();
316
+ _controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 300));
317
+ }
318
+
319
+ @override
320
+ void dispose() {
321
+ _controller.dispose();
322
+ super.dispose();
323
+ }
324
+ }
325
+ ```
326
+
327
+ **4. Timer Leaks:**
328
+ ```dart
329
+ Timer? _timer;
330
+
331
+ @override
332
+ void initState() {
333
+ super.initState();
334
+ _timer = Timer.periodic(const Duration(seconds: 5), (_) => _refresh());
335
+ }
336
+
337
+ @override
338
+ void dispose() {
339
+ _timer?.cancel();
340
+ super.dispose();
341
+ }
342
+ ```
343
+
344
+ ## 5. Dart Isolates — Offload Heavy Work
345
+
346
+ ### When to Use Isolates
347
+
348
+ Any operation that takes > 16ms on the main isolate should be offloaded:
349
+ - JSON parsing of large payloads (> 50KB)
350
+ - Image processing / compression
351
+ - Encryption / hashing
352
+ - Complex data transformations
353
+ - Database-heavy operations
354
+ - File I/O on large files
355
+
356
+ ### Isolate.run() (Dart 2.19+ / Dart 3.x)
357
+
358
+ ```dart
359
+ // Simple one-shot computation
360
+ final result = await Isolate.run(() {
361
+ // Runs in a separate isolate — won't block UI
362
+ return heavyJsonParse(largeJsonString);
363
+ });
364
+ ```
365
+
366
+ ### compute() Function
367
+
368
+ ```dart
369
+ // Flutter's convenience wrapper — serializes input/output automatically
370
+ final parsed = await compute(parseProducts, jsonString);
371
+
372
+ // Top-level or static function (required for compute)
373
+ List<Product> parseProducts(String json) {
374
+ final decoded = jsonDecode(json) as List;
375
+ return decoded.map((e) => Product.fromJson(e)).toList();
376
+ }
377
+ ```
378
+
379
+ ### Long-Running Isolate with Ports
380
+
381
+ ```dart
382
+ // For continuous background work (e.g., real-time data processing)
383
+ final receivePort = ReceivePort();
384
+ await Isolate.spawn(_backgroundWorker, receivePort.sendPort);
385
+
386
+ final sendPort = await receivePort.first as SendPort;
387
+ // Send work to the isolate
388
+ sendPort.send(workPayload);
389
+ ```
390
+
391
+ **Rule of thumb:** Use `Isolate.run()` for one-shot tasks, `compute()` for simple transformations, and `Isolate.spawn()` for long-running workers.
392
+
393
+ ## 6. State Management Performance
394
+
395
+ ### Performance Characteristics
396
+
397
+ | Library | Rebuild Granularity | Bundle Impact | Best For |
398
+ |---|---|---|---|
399
+ | **Riverpod 2.x** | select() per-field | ~15 KB | Enterprise, compile-time safe |
400
+ | **Provider** | Consumer/Selector | ~10 KB | Simple apps, official recommendation |
401
+ | **Bloc/Cubit** | BlocSelector | ~20 KB | Complex async, event-driven |
402
+ | **GetX** | Obx() per-observable | ~25 KB | Rapid prototyping (not recommended for prod) |
403
+ | setState | Widget-level | 0 KB | Ephemeral UI state only |
404
+
405
+ ### Selective Rebuilds (Critical Pattern)
406
+
407
+ ```dart
408
+ // BAD — entire widget rebuilds when ANY field in UserState changes
409
+ Widget build(BuildContext context) {
410
+ final user = ref.watch(userProvider);
411
+ return Text(user.name);
412
+ }
413
+
414
+ // GOOD — only rebuilds when name changes (Riverpod)
415
+ Widget build(BuildContext context) {
416
+ final name = ref.watch(userProvider.select((u) => u.name));
417
+ return Text(name);
418
+ }
419
+
420
+ // GOOD — Bloc equivalent
421
+ BlocSelector<UserCubit, UserState, String>(
422
+ selector: (state) => state.name,
423
+ builder: (context, name) => Text(name),
424
+ )
425
+ ```
426
+
427
+ ### Avoid Context.watch at Widget Root
428
+
429
+ ```dart
430
+ // BAD — Provider: watching at Scaffold level rebuilds everything
431
+ Widget build(BuildContext context) {
432
+ final cart = context.watch<CartModel>();
433
+ return Scaffold(
434
+ appBar: AppBar(title: Text('Cart (${cart.itemCount})')),
435
+ body: /* expensive subtree */,
436
+ );
437
+ }
438
+
439
+ // GOOD — isolate the watch with Consumer
440
+ Widget build(BuildContext context) {
441
+ return Scaffold(
442
+ appBar: AppBar(
443
+ title: Consumer<CartModel>(
444
+ builder: (context, cart, _) => Text('Cart (${cart.itemCount})'),
445
+ ),
446
+ ),
447
+ body: /* expensive subtree — NOT rebuilt */,
448
+ );
449
+ }
450
+ ```
451
+
452
+ ## 7. Impeller Rendering Engine
453
+
454
+ ### Status (Flutter 3.27+)
455
+
456
+ - **iOS**: Default since Flutter 3.16 — stable, production-ready
457
+ - **Android**: Default on API 29+ (Vulkan) since Flutter 3.27
458
+ - **Fallback**: OpenGL on older Android devices without Vulkan
459
+
460
+ ### What Impeller Solves
461
+
462
+ | Problem (Skia) | Solution (Impeller) |
463
+ |---|---|
464
+ | First-frame shader compilation jank | All shaders pre-compiled at build time |
465
+ | Runtime shader compilation stalls | Zero runtime shader compilation |
466
+ | Inconsistent frame times | Predictable frame rendering |
467
+ | GPU cache misses on new visuals | Tile-based rendering (256x256 tiles) |
468
+
469
+ ### SkSL Warmup (Legacy — Only for Skia Fallback)
470
+
471
+ ```bash
472
+ # Only needed if targeting Skia (Android API < 29)
473
+ # 1. Capture shaders
474
+ flutter run --profile --cache-sksl
475
+
476
+ # 2. Export shader bundle
477
+ flutter build apk --bundle-sksl-path flutter_01.sksl.json
478
+ ```
479
+
480
+ **With Impeller (default), SkSL warmup is unnecessary.**
481
+
482
+ ### Impeller-Specific Optimizations
483
+
484
+ ```dart
485
+ // AVOID — complex clipping paths increase draw calls in Impeller
486
+ ClipPath(
487
+ clipper: ComplexCustomClipper(), // expensive with Impeller
488
+ child: /* ... */,
489
+ )
490
+
491
+ // PREFER — simple clip shapes
492
+ ClipRRect(
493
+ borderRadius: BorderRadius.circular(16),
494
+ child: /* ... */,
495
+ )
496
+
497
+ // AVOID — multiple overlapping opacity layers
498
+ Opacity(opacity: 0.5, child: /* ... */) // creates extra layer
499
+
500
+ // PREFER — use color opacity or AnimatedOpacity
501
+ Container(color: Colors.black.withOpacity(0.5))
502
+ AnimatedOpacity(opacity: 0.5, child: /* ... */)
503
+ ```
504
+
505
+ ## 8. Animation Performance
506
+
507
+ ### Prefer Implicit Animations for Simple Cases
508
+
509
+ ```dart
510
+ // GOOD — Flutter handles optimization automatically
511
+ AnimatedContainer(
512
+ duration: const Duration(milliseconds: 300),
513
+ curve: Curves.easeOut,
514
+ width: _expanded ? 200 : 100,
515
+ height: _expanded ? 200 : 100,
516
+ color: _expanded ? Colors.blue : Colors.red,
517
+ )
518
+ ```
519
+
520
+ ### AnimatedBuilder for Complex Animations
521
+
522
+ ```dart
523
+ // GOOD — only the builder subtree rebuilds, not the entire widget
524
+ AnimatedBuilder(
525
+ animation: _controller,
526
+ builder: (context, child) {
527
+ return Transform.rotate(
528
+ angle: _controller.value * 2 * pi,
529
+ child: child, // child is cached — NOT rebuilt
530
+ );
531
+ },
532
+ child: const ExpensiveWidget(), // built once, reused
533
+ )
534
+ ```
535
+
536
+ ### Avoid Layout-Triggering Animations
537
+
538
+ ```dart
539
+ // BAD — changes size → triggers layout every frame
540
+ AnimatedBuilder(
541
+ animation: _controller,
542
+ builder: (context, child) {
543
+ return SizedBox(
544
+ width: 100 * _controller.value, // layout change every frame!
545
+ child: child,
546
+ );
547
+ },
548
+ )
549
+
550
+ // GOOD — Transform doesn't trigger layout
551
+ AnimatedBuilder(
552
+ animation: _controller,
553
+ builder: (context, child) {
554
+ return Transform.scale(
555
+ scale: _controller.value, // paint-only — no layout
556
+ child: child,
557
+ );
558
+ },
559
+ )
560
+ ```
561
+
562
+ ## 9. Startup Optimization
563
+
564
+ ### Cold Start Targets
565
+
566
+ | Platform | Target | Warning | Fail |
567
+ |---|---|---|---|
568
+ | iOS flagship | ≤ 1.0s | ≤ 1.5s | > 2.0s |
569
+ | Mid-tier Android | ≤ 1.5s | ≤ 2.5s | > 3.0s |
570
+ | Low-end Android | ≤ 2.0s | ≤ 3.0s | > 4.0s |
571
+
572
+ ### Quick Wins
573
+
574
+ 1. **Deferred initialization** — lazy-load services not needed at startup
575
+ 2. **Deferred imports** — split rarely-used features into deferred loads
576
+ 3. **Native splash** — use `flutter_native_splash` for instant visual
577
+ 4. **Reduce main() work** — defer analytics, crash reporting, remote config
578
+
579
+ ```dart
580
+ void main() async {
581
+ WidgetsFlutterBinding.ensureInitialized();
582
+ // Only essential init here
583
+ await _initCriticalServices(); // auth, storage
584
+ runApp(const MyApp());
585
+ // Defer non-critical init
586
+ _initDeferredServices(); // analytics, crash reporting, remote config
587
+ }
588
+
589
+ Future<void> _initDeferredServices() async {
590
+ await Future.delayed(const Duration(seconds: 1)); // after first frame
591
+ await Firebase.initializeApp();
592
+ await CrashReporting.init();
593
+ }
594
+ ```
595
+
596
+ ### Deferred Imports (Code Splitting)
597
+
598
+ ```dart
599
+ // Only load heavy feature when accessed
600
+ import 'package:my_app/features/reports/reports.dart' deferred as reports;
601
+
602
+ Future<void> openReports() async {
603
+ await reports.loadLibrary();
604
+ navigator.push(reports.ReportsPage());
605
+ }
606
+ ```
607
+
608
+ ## 10. App Size Optimization
609
+
610
+ ### Targets
611
+
612
+ | Metric | Good | Warning | Fail |
613
+ |---|---|---|---|
614
+ | APK (arm64) | ≤ 15 MB | ≤ 30 MB | > 50 MB |
615
+ | App Bundle (AAB) | ≤ 20 MB | ≤ 40 MB | > 60 MB |
616
+ | IPA | ≤ 30 MB | ≤ 50 MB | > 80 MB |
617
+
618
+ ### Size Analysis
619
+
620
+ ```bash
621
+ # Analyze app size
622
+ flutter build apk --analyze-size
623
+ flutter build appbundle --analyze-size
624
+ flutter build ios --analyze-size
625
+
626
+ # Compare two builds
627
+ flutter build apk --analyze-size --code-size-directory=v1
628
+ # ... make changes ...
629
+ flutter build apk --analyze-size --code-size-directory=v2
630
+ ```
631
+
632
+ ### Reduction Techniques
633
+
634
+ ```bash
635
+ # Split APK per ABI (~40% reduction)
636
+ flutter build apk --split-per-abi
637
+
638
+ # Enable obfuscation + tree shaking
639
+ flutter build apk --obfuscate --split-debug-info=debug-info/
640
+
641
+ # Use App Bundle for Play Store (automatic per-device optimization)
642
+ flutter build appbundle
643
+ ```
644
+
645
+ ```dart
646
+ // Use WebP/AVIF instead of PNG for assets (50-70% smaller)
647
+ // Compress with: cwebp -q 80 input.png -o output.webp
648
+
649
+ // Remove unused packages from pubspec.yaml
650
+ // Run: flutter pub deps --no-dev | grep -c "^" // count dependencies
651
+ ```
652
+
653
+ ## 11. Anti-Patterns Quick Reference
654
+
655
+ | Anti-Pattern | Impact | Fix |
656
+ |---|---|---|
657
+ | No `const` on static widgets | Unnecessary rebuilds | Add `const` keyword |
658
+ | `setState` at widget root | Entire tree rebuilds | Extract StatefulWidget or use Builder |
659
+ | `Opacity` widget for fading | Creates extra render layer | Use `AnimatedOpacity` or color opacity |
660
+ | `ListView(children: [...])` for large lists | All items built upfront | Use `ListView.builder` |
661
+ | No `itemExtent` on fixed-height lists | Layout measurement each item | Add `itemExtent` |
662
+ | Full-res images for thumbnails | ~8MB RAM per image on Android | Request sized images from CDN |
663
+ | Heavy work in `build()` | Blocks frame rendering | Move to `initState` or isolate |
664
+ | Undisposed controllers/subs | Memory leaks | `dispose()` everything |
665
+ | Synchronous file I/O on main isolate | UI jank during I/O | Use `Isolate.run()` or `compute()` |
666
+ | Deep widget nesting (10+ levels) | Slow layout pass | Extract into separate widgets |
667
+ | `Column` + `SingleChildScrollView` for lists | No lazy loading | Use `ListView.builder` |
668
+ | Complex `ClipPath` with Impeller | Increased draw calls | Use simple `ClipRRect` |
669
+ | `context.watch` at root widget | Broadcast rebuilds | Use `Consumer` / `select()` |
670
+ | `setState` inside `StreamBuilder` | Double rebuild | Let StreamBuilder manage state |
671
+ | No `key` on dynamic list items | State mismatch on reorder | Use `ValueKey(item.id)` |
672
+
673
+ ## 12. Performance Budgets
674
+
675
+ | Metric | Good | Warning | Fail |
676
+ |---|---|---|---|
677
+ | Frame Render Time (60fps) | ≤ 16ms | ≤ 24ms | > 32ms |
678
+ | Frame Render Time (120fps) | ≤ 8ms | ≤ 12ms | > 16ms |
679
+ | Cold Start TTI | ≤ 1.5s iOS / ≤ 2.0s Android | ≤ 2.5s | > 3.5s |
680
+ | Widget Rebuild Count/Frame | ≤ 5 | ≤ 15 | > 30 |
681
+ | Memory Peak (3GB device) | ≤ 150 MB | ≤ 250 MB | > 350 MB |
682
+ | APK Size (arm64) | ≤ 15 MB | ≤ 30 MB | > 50 MB |
683
+ | Scroll FPS | 60/120 FPS | 50-55 FPS | < 45 FPS |
684
+ | Image Decode Time | ≤ 5ms | ≤ 15ms | > 30ms |
685
+
686
+ ## 13. DevTools Profiling
687
+
688
+ | Need | Tool |
689
+ |---|---|
690
+ | Frame rendering analysis | Performance Overlay (`showPerformanceOverlay: true`) |
691
+ | Build/Layout/Paint timing | DevTools → Performance tab |
692
+ | Widget rebuild tracking | DevTools → Performance → Track Widget Rebuilds |
693
+ | Memory leaks | DevTools → Memory tab → Heap Snapshots |
694
+ | CPU hotspots | DevTools → CPU Profiler |
695
+ | App size analysis | `flutter build --analyze-size` |
696
+ | Widget tree inspection | DevTools → Widget Inspector |
697
+ | Network requests | DevTools → Network tab |
698
+ | Jank detection | DevTools → Performance → Jank Flags |
699
+
700
+ ### Profile Mode (Required for Accurate Benchmarks)
701
+
702
+ ```bash
703
+ # ALWAYS profile in profile mode — debug mode is 10x slower
704
+ flutter run --profile
705
+
706
+ # On device (not emulator) for realistic numbers
707
+ flutter run --profile -d <device-id>
708
+ ```
709
+
710
+ ### Performance Overlay
711
+
712
+ ```dart
713
+ MaterialApp(
714
+ showPerformanceOverlay: true, // shows GPU/UI thread frame times
715
+ )
716
+ ```
717
+
718
+ ## 14. Optimization Checklist by Effort
719
+
720
+ ### Level 1 — Quick Wins (< 1 day)
721
+ - [ ] Add `const` to all static widgets (enable lint rules)
722
+ - [ ] Replace `ListView(children)` with `ListView.builder`
723
+ - [ ] Add `itemExtent` to fixed-height lists
724
+ - [ ] Dispose all controllers and subscriptions
725
+ - [ ] Move heavy computation out of `build()`
726
+ - [ ] Use `CachedNetworkImage` for network images
727
+ - [ ] Request appropriately-sized images from CDN
728
+ - [ ] Enable `--split-per-abi` for APK builds
729
+ - [ ] Profile in profile mode on real device
730
+
731
+ ### Level 2 — Standard (1-3 days)
732
+ - [ ] Extract large build methods into separate widgets
733
+ - [ ] Add `RepaintBoundary` for animations/custom painters
734
+ - [ ] Use `select()` in state management (Riverpod/Provider/Bloc)
735
+ - [ ] Offload JSON parsing to isolates (`compute()`)
736
+ - [ ] Implement deferred imports for heavy features
737
+ - [ ] Tune `cacheExtent` on scroll views
738
+ - [ ] Add `precacheImage` for critical images
739
+ - [ ] Configure `ImageCache` size limits
740
+ - [ ] Defer non-critical service initialization
741
+
742
+ ### Level 3 — Advanced (1-2 weeks)
743
+ - [ ] Migrate to Impeller (verify on Android API 29+)
744
+ - [ ] Replace `Opacity` with `AnimatedOpacity` / color opacity
745
+ - [ ] Use `Transform` instead of layout-changing animations
746
+ - [ ] Implement `AutomaticKeepAliveClientMixin` for tab preservation
747
+ - [ ] Set up CI performance benchmarks
748
+ - [ ] Analyze and reduce app size (`--analyze-size`)
749
+ - [ ] Implement cursor-based pagination for large lists
750
+ - [ ] Profile and optimize startup time
751
+
752
+ ### Level 4 — Expert (> 2 weeks)
753
+ - [ ] Custom `RenderObject` for performance-critical layouts
754
+ - [ ] Long-running isolates for background processing
755
+ - [ ] Platform channel optimization (reduce serialization)
756
+ - [ ] Custom Impeller-aware painting strategies
757
+ - [ ] Automated performance regression testing in CI
758
+
759
+ ## Scan Process
760
+
761
+ When asked to analyze a Flutter project for performance issues:
762
+
763
+ ### 1. Determine Scope
764
+ Ask (or infer): full audit, specific screen, startup, memory, rendering, or app size.
765
+
766
+ ### 2. Run Automated Checks
767
+
768
+ ```bash
769
+ # Anti-pattern scan
770
+ ./scripts/flutter-perf-scan.sh <project-path>
771
+ ```
772
+
773
+ ### 3. Manual Review
774
+ Follow the anti-patterns table above and check each category.
775
+
776
+ ### 4. Report Findings
777
+
778
+ Structure by severity:
779
+ ```
780
+ CRITICAL — Causes visible jank or crashes
781
+ HIGH — Significant perf impact, fix before release
782
+ MEDIUM — Defense-in-depth improvement
783
+ LOW — Best practice recommendation
784
+ ```
785
+
786
+ For each finding:
787
+ ```
788
+ **[SEVERITY] Title**
789
+ Location: file:line
790
+ Impact: Frame time / memory / size impact
791
+ Before: The anti-pattern code
792
+ After: The optimized code
793
+ ```
794
+
795
+ ### 5. Prioritize Fixes
796
+ 1. Critical fixes (visible jank, memory leaks)
797
+ 2. High fixes (rebuild storms, missing lazy loading)
798
+ 3. Medium fixes (missing const, suboptimal caching)
799
+ 4. Low fixes (style improvements)
800
+
801
+ ## References
802
+
803
+ - `references/flutter-patterns.md` — Advanced patterns: custom RenderObjects, platform channels, Impeller internals, CI benchmarking