sdd-full 4.6.2 → 4.8.1

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 (29) hide show
  1. package/bin.js +1 -1
  2. package/index.js +18 -12
  3. package/package.json +1 -1
  4. package/skills/VERSION.md +3 -3
  5. package/skills/design-planning/global-overlay-stack-standard/SKILL.md +83 -0
  6. package/skills/design-planning/ui-motion-interaction-standard/SKILL.md +79 -0
  7. package/skills/flutter/skills/flutter-add-integration-test/SKILL.md +165 -0
  8. package/skills/flutter/skills/flutter-add-widget-preview/SKILL.md +147 -0
  9. package/skills/flutter/skills/flutter-add-widget-test/SKILL.md +156 -0
  10. package/skills/flutter/skills/flutter-apply-architecture-best-practices/SKILL.md +164 -0
  11. package/skills/flutter/skills/flutter-build-responsive-layout/SKILL.md +141 -0
  12. package/skills/flutter/skills/flutter-fix-layout-issues/SKILL.md +132 -0
  13. package/skills/flutter/skills/flutter-implement-json-serialization/SKILL.md +155 -0
  14. package/skills/flutter/skills/flutter-setup-declarative-routing/SKILL.md +257 -0
  15. package/skills/flutter/skills/flutter-setup-localization/SKILL.md +212 -0
  16. package/skills/flutter/skills/flutter-use-http-package/SKILL.md +177 -0
  17. package/skills/requirement-analysis/sdd/mock_sdd.md +156 -0
  18. package/skills/writing-skills/SKILL.md +654 -0
  19. package/skills/writing-skills/anthropic-best-practices.md +1149 -0
  20. package/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  21. package/skills/writing-skills/graphviz-conventions.dot +172 -0
  22. package/skills/writing-skills/persuasion-principles.md +187 -0
  23. package/skills/writing-skills/render-graphs.js +168 -0
  24. package/skills/writing-skills/testing-skills-with-subagents.md +384 -0
  25. package/skills/checklist.md +0 -154
  26. package/skills//345/256/214/346/225/264/345/274/200/345/217/221/346/265/201/347/250/213/346/211/213/345/206/214.md +0 -454
  27. package/skills//346/212/200/350/203/275/344/275/223/347/263/273/345/256/214/345/226/204/345/273/272/350/256/256.md +0 -308
  28. package/skills//346/212/200/350/203/275/344/275/277/347/224/250/346/214/207/345/215/227.md +0 -309
  29. package/skills//346/212/200/350/203/275/345/206/263/347/255/226/346/240/221.md +0 -338
package/bin.js CHANGED
@@ -6,7 +6,7 @@ const fs = require('fs');
6
6
  const path = require('path');
7
7
 
8
8
  const SDD = {
9
- version: '4.6.2',
9
+ version: '4.8.1',
10
10
  name: 'sdd-full',
11
11
  description: '完整的软件设计开发技能包'
12
12
  };
package/index.js CHANGED
@@ -17,22 +17,28 @@ const SDD = {
17
17
  const skillsDir = path.join(__dirname, 'skills');
18
18
  const skills = [];
19
19
 
20
- if (fs.existsSync(skillsDir)) {
21
- const items = fs.readdirSync(skillsDir);
22
-
23
- items.forEach(item => {
24
- const itemPath = path.join(skillsDir, item);
25
- const stat = fs.statSync(itemPath);
20
+ function searchSkills(dir, parentPath = '') {
21
+ if (fs.existsSync(dir)) {
22
+ const items = fs.readdirSync(dir);
26
23
 
27
- if (stat.isDirectory() && !item.endsWith('.md')) {
28
- const skillPath = path.join(itemPath, 'SKILL.md');
29
- if (fs.existsSync(skillPath)) {
30
- skills.push(item);
24
+ items.forEach(item => {
25
+ const itemPath = path.join(dir, item);
26
+ const stat = fs.statSync(itemPath);
27
+
28
+ if (stat.isDirectory() && !item.startsWith('.')) {
29
+ const skillPath = path.join(itemPath, 'SKILL.md');
30
+ const skillRelativePath = parentPath ? path.join(parentPath, item) : item;
31
+ if (fs.existsSync(skillPath)) {
32
+ skills.push(skillRelativePath);
33
+ }
34
+ // 继续递归搜索子目录
35
+ searchSkills(itemPath, skillRelativePath);
31
36
  }
32
- }
33
- });
37
+ });
38
+ }
34
39
  }
35
40
 
41
+ searchSkills(skillsDir);
36
42
  return skills;
37
43
  },
38
44
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sdd-full",
3
- "version": "4.6.2",
3
+ "version": "4.8.1",
4
4
  "description": "SDD Full - 完整的软件设计开发技能包",
5
5
  "main": "index.js",
6
6
  "bin": "./bin.js",
package/skills/VERSION.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # SDD Full 技能包版本
2
2
 
3
- **版本**: 4.6.2
4
- **发布日期**: 2026-05-06
5
- **更新时间**: 2026-05-06 21:05:00
3
+ **版本**: 4.8.1
4
+ **发布日期**: 2026-05-08
5
+ **更新时间**: 2026-05-08 22:36:00
6
6
 
7
7
  ---
8
8
 
@@ -0,0 +1,83 @@
1
+ name: global-overlay-stack-standard
2
+ description: 全局浮层栈与层级规范 - 跨技术栈通用浮层管理规则
3
+ author:
4
+ version: 1.0.0
5
+ trigger:
6
+ - 浮层栈
7
+ - 浮层规范
8
+ - 弹窗管理
9
+ - 层级管理
10
+ tags:
11
+ - 浮层管理
12
+ - 工程规范
13
+ - UI规范
14
+ - 跨端通用
15
+
16
+ 【claude code调用标识:global-overlay-stack-standard】【trae调用标识:global-overlay-stack-standard+浮层管理】【流程场景:1.完整3阶段SDD流程、2.从零开始新项目、3.小型功能迭代】
17
+
18
+ ## 功能说明
19
+
20
+ 跨技术栈通用浮层栈与层级规范,不绑定 Flutter / iOS / Android / H5 / 小程序。只管控浮层栈、层级、弹出流程、防重叠、关闭逻辑、交互规则,不涉及UI动画、不限制具体实现语法。
21
+
22
+ ## 核心定位
23
+
24
+ 跨技术栈通用,不绑定任何平台/框架;只管控浮层栈、层级、弹出流程、防重叠、关闭逻辑、交互规则,不涉及UI动画、不限制具体实现语法。
25
+
26
+ ## 强制规范规则
27
+
28
+ ### 1. 浮层栈统一管理
29
+ 所有浮层类型:全局悬浮窗、强拦截弹窗、普通对话框、底部弹层、居中弹窗、Toast 弱提示,全部强制纳入全局统一栈管理,禁止业务私自独立创建、私自挂载根节点。
30
+
31
+ ### 2. 全局固定层级优先级
32
+ 全局固定层级优先级(永久不可随意篡改):
33
+ 全局悬浮窗 > 强拦截权限弹窗 > 普通业务对话框 > 底部弹层 > Toast 轻量提示
34
+
35
+ ### 3. 栈机制严格遵循
36
+ 浮层严格遵循后进先出栈机制,任何操作只允许作用于当前栈顶浮层,禁止跨层操作、跨层关闭。
37
+
38
+ ### 4. 防重叠强制流程
39
+ - 同优先级浮层禁止并行同时弹出,必须串行排队,上一个关闭后才允许弹出下一个;
40
+ - 新浮层弹出前必须校验栈顶同等级浮层,存在则拦截重复弹出或进入等待队列;
41
+ - 限制全局最大浮层嵌套层数,超出层数直接拦截创建,杜绝无限堆叠重叠;
42
+ - 页面路由跳转、退出登录、流程终止时,自动清空当前页面附属所有浮层,避免残留遮挡。
43
+
44
+ ### 5. 遮罩行为统一规范
45
+ - 全局默认固定遮罩可关闭/不可关闭基线规则;
46
+ - 业务页面不准单独改写遮罩点击逻辑、不准私自穿透遮罩事件。
47
+
48
+ ### 6. 系统返回逻辑统一
49
+ - 优先关闭栈顶浮层;
50
+ - 无任何浮层时,才允许执行原生页面回退。
51
+
52
+ ### 7. 标准调用能力
53
+ 全局仅开放三个标准调用能力:展示浮层、关闭栈顶、关闭全部;
54
+ 业务禁止私自销毁浮层、私自移除遮罩、私自修改层级权重。
55
+
56
+ ### 8. 需求变更流程
57
+ 所有浮层相关需求变更、流程改动,必须先更新 SDD 对应规则,再进行开发;
58
+ 代码实现必须对齐本规范与 SDD 定义,不得私自偏离。
59
+
60
+ ## 使用指南
61
+
62
+ ### 调用方式
63
+ - **Claude Code**: 调用 global-overlay-stack-standard
64
+ - **Trae**: trae调用 global-overlay-stack-standard
65
+
66
+ ### 适用场景
67
+ - 新项目浮层架构设计
68
+ - 现有项目浮层问题治理
69
+ - 跨端统一浮层规范制定
70
+ - 浮层重叠、层级混乱问题修复
71
+
72
+ ## AI协作规范
73
+
74
+ | 阶段 | AI职责 | 人工校验要求 |
75
+ |------|--------|-------------|
76
+ | 浮层需求分析 | 梳理浮层类型、优先级、交互规则 | 确认浮层分类合理性 |
77
+ | 规范落地 | 协助生成浮层管理代码框架 | 必须人工二次确认层级优先级 |
78
+ | Bug修复 | 分析浮层重叠、层级混乱原因 | 验证修复方案符合规范 |
79
+
80
+ ---
81
+
82
+ **规范版本**: v1.0.0
83
+ **适用场景**: 跨技术栈通用浮层管理
@@ -0,0 +1,79 @@
1
+ name: ui-motion-interaction-standard
2
+ description: 全局UI动效与交互反馈规范 - 跨端通用交互动效管理
3
+ author:
4
+ version: 1.0.0
5
+ trigger:
6
+ - 动效规范
7
+ - 交互动效
8
+ - 动画规范
9
+ - 交互反馈
10
+ tags:
11
+ - UI动效
12
+ - 交互动画
13
+ - 工程规范
14
+ - 跨端通用
15
+
16
+ 【claude code调用标识:ui-motion-interaction-standard】【trae调用标识:ui-motion-interaction-standard+UI动效】【流程场景:1.完整3阶段SDD流程、2.从零开始新项目、3.小型功能迭代】
17
+
18
+ ## 功能说明
19
+
20
+ 跨端通用UI动效与交互反馈规范,管控所有交互动效、弹窗动画、点击反馈、过渡动效。和浮层栈逻辑解耦,单独归一管理,不侵入层级与栈流程。
21
+
22
+ ## 核心定位
23
+
24
+ 跨端通用,管控所有交互动效、弹窗动画、点击反馈、过渡动效。和浮层栈逻辑解耦,单独归一管理,不侵入层级与栈流程。
25
+
26
+ ## 强制规范规则
27
+
28
+ ### 1. 弹窗标准入场/退场动效统一约束
29
+
30
+ - 居中弹窗:默认淡入淡出 + 轻微缩放;
31
+ - 底部弹层:默认从底部滑入滑出;
32
+ - 强拦截弹窗:淡入遮罩+居中缓慢浮现;
33
+ - Toast:淡入淡出+轻微上浮位移。
34
+
35
+ ### 2. 全局动画统一固化标准
36
+
37
+ 固定动画时长、插值曲线、渐变节奏,业务不得随意改快慢、乱加非主流动效曲线,保持全站体验一致。
38
+
39
+ ### 3. 按钮与可点击控件交互反馈
40
+
41
+ - 全局统一点击涟漪效果、按压缩放、透明度反馈;
42
+ - 禁止各页面各自写一套点击动效,风格碎片化。
43
+
44
+ ### 4. 页面路由与模块过渡
45
+
46
+ 页面路由转场、模块显隐过渡,遵循全局统一动效规范,禁止私自写突兀无过渡、非主流转场方式。
47
+
48
+ ### 5. 动效职责分离
49
+
50
+ 动效只负责视觉表现,不参与浮层层级、栈顺序、关闭逻辑;不准通过动画层级、动画延时来 hack 规避浮层重叠规则。
51
+
52
+ ### 6. 动效变更流程
53
+
54
+ 所有新增动效类型、修改现有动效风格,必须先在 SDD 定义规范,再落地实现,保持全站动效统一口径。
55
+
56
+ ## 使用指南
57
+
58
+ ### 调用方式
59
+ - **Claude Code**: 调用 ui-motion-interaction-standard
60
+ - **Trae**: trae调用 ui-motion-interaction-standard
61
+
62
+ ### 适用场景
63
+ - 新项目动效体系设计
64
+ - 现有项目动效统一规范
65
+ - 跨端动效体验一致性治理
66
+ - 交互动效风格碎片化问题修复
67
+
68
+ ## AI协作规范
69
+
70
+ | 阶段 | AI职责 | 人工校验要求 |
71
+ |------|--------|-------------|
72
+ | 动效需求分析 | 梳理动效类型、时长、曲线标准 | 确认动效风格一致性 |
73
+ | 规范落地 | 协助生成动效实现代码框架 | 必须人工二次确认动效参数 |
74
+ | 体验优化 | 分析动效流畅度、交互反馈合理性 | 验证体验符合规范 |
75
+
76
+ ---
77
+
78
+ **规范版本**: v1.0.0
79
+ **适用场景**: 跨端通用UI动效与交互反馈
@@ -0,0 +1,165 @@
1
+ 【claude code调用标识:flutter-add-integration-test】【trae调用标识:flutter-add-integration-test+Flutter开发】【流程场景:1.完整3阶段SDD流程、3.小型功能迭代】
2
+
3
+ ---
4
+ name: flutter-add-integration-test
5
+ description: Configures Flutter Driver for app interaction and converts MCP actions into permanent integration tests. Use when adding integration testing to a project, exploring UI components via MCP, or automating user flows with the integration_test package.
6
+ metadata:
7
+ model: models/gemini-3.1-pro-preview
8
+ last_modified: Tue, 21 Apr 2026 18:29:20 GMT
9
+ ---
10
+ # Implementing Flutter Integration Tests
11
+
12
+ ## Contents
13
+ - [Project Setup and Dependencies](#project-setup-and-dependencies)
14
+ - [Interactive Exploration via MCP](#interactive-exploration-via-mcp)
15
+ - [Test Authoring Guidelines](#test-authoring-guidelines)
16
+ - [Execution and Profiling](#execution-and-profiling)
17
+ - [Workflow: End-to-End Integration Testing](#workflow-end-to-end-integration-testing)
18
+ - [Examples](#examples)
19
+
20
+ ## Project Setup and Dependencies
21
+
22
+ Configure the project to support integration testing and Flutter Driver extensions.
23
+
24
+ 1. Add required development dependencies to `pubspec.yaml`:
25
+ ```bash
26
+ flutter pub add 'dev:integration_test:{"sdk":"flutter"}'
27
+ flutter pub add 'dev:flutter_test:{"sdk":"flutter"}'
28
+ ```
29
+ 2. Enable the Flutter Driver extension in your application entry point (typically `lib/main.dart` or a dedicated `lib/main_test.dart`):
30
+ - Import `package:flutter_driver/driver_extension.dart`.
31
+ - Call `enableFlutterDriverExtension();` before `runApp()`.
32
+ 3. Add `Key` parameters (e.g., `ValueKey('login_button')`) to critical widgets in the application code to ensure reliable targeting during tests.
33
+
34
+ ## Interactive Exploration via MCP
35
+
36
+ Use the Dart/Flutter MCP server tools to interactively explore and manipulate the application state before writing static tests.
37
+
38
+ - **Launch**: Execute `launch_app` with `target: "lib/main_test.dart"` to start the application and acquire the DTD URI.
39
+ - **Inspect**: Execute `get_widget_tree` to discover available `Key`s, `Text` nodes, and widget `Type`s.
40
+ - **Interact**: Execute `tap`, `enter_text`, and `scroll` to simulate user flows.
41
+ - **Wait**: Always execute `waitFor` or verify state with `get_health` when navigating or triggering animations.
42
+ - **Troubleshoot Unmounted Widgets**: If a widget is not found in the tree, it may be lazily loaded in a `SliverList` or `ListView`. Execute `scroll` or `scrollIntoView` to force the widget to mount before interacting with it.
43
+
44
+ ## Test Authoring Guidelines
45
+
46
+ Structure integration tests using the `flutter_test` API paradigm.
47
+
48
+ - Create a dedicated `integration_test/` directory at the project root.
49
+ - Name all test files using the `<name>_test.dart` convention.
50
+ - Initialize the binding by calling `IntegrationTestWidgetsFlutterBinding.ensureInitialized();` at the start of `main()`.
51
+ - Load the application UI using `await tester.pumpWidget(MyApp());`.
52
+ - Trigger frames and wait for animations to complete using `await tester.pumpAndSettle();` after interactions like `tester.tap()`.
53
+ - Assert widget visibility using `expect(find.byKey(ValueKey('foo')), findsOneWidget);` or `findsNothing`.
54
+ - Scroll to specific off-screen widgets using `await tester.scrollUntilVisible(itemFinder, 500.0, scrollable: listFinder);`.
55
+
56
+ **Conditional Logic for Legacy `flutter_driver`:**
57
+ - If maintaining or migrating legacy `flutter_driver` tests, use `driver.waitFor()`, `driver.waitForAbsent()`, `driver.tap()`, and `driver.scroll()` instead of the `WidgetTester` APIs.
58
+
59
+ ## Execution and Profiling
60
+
61
+ Execute tests using the `flutter drive` command. Require a host driver script located in `test_driver/integration_test.dart` that calls `integrationDriver()`.
62
+
63
+ **Conditional Execution Targets:**
64
+ - **If testing on Chrome:** Launch `chromedriver --port=4444` in a separate terminal, then run:
65
+ `flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart -d chrome`
66
+ - **If testing headless web:** Run with `-d web-server`.
67
+ - **If testing on Android (Local):** Run `flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart`.
68
+ - **If testing on Firebase Test Lab (Android):**
69
+ 1. Build debug APK: `flutter build apk --debug`
70
+ 2. Build test APK: `./gradlew app:assembleAndroidTest`
71
+ 3. Upload both APKs to the Firebase Test Lab console.
72
+
73
+ ## Workflow: End-to-End Integration Testing
74
+
75
+ Copy and follow this checklist to implement and verify integration tests.
76
+
77
+ - [ ] **Task Progress: Setup**
78
+ - [ ] Add `integration_test` and `flutter_test` to `pubspec.yaml`.
79
+ - [ ] Inject `enableFlutterDriverExtension()` into the app entry point.
80
+ - [ ] Assign `ValueKey`s to target widgets.
81
+ - [ ] **Task Progress: Exploration**
82
+ - [ ] Run `launch_app` via MCP.
83
+ - [ ] Map the widget tree using `get_widget_tree`.
84
+ - [ ] Validate interaction paths using MCP tools (`tap`, `enter_text`).
85
+ - [ ] **Task Progress: Authoring**
86
+ - [ ] Create `integration_test/app_test.dart`.
87
+ - [ ] Write test cases using `WidgetTester` APIs.
88
+ - [ ] Create `test_driver/integration_test.dart` with `integrationDriver()`.
89
+ - [ ] **Task Progress: Execution & Feedback Loop**
90
+ - [ ] Run `flutter drive --driver=test_driver/integration_test.dart --target=integration_test/app_test.dart`.
91
+ - [ ] **Feedback Loop**: Review test output -> If `PumpAndSettleTimedOutException` occurs, check for infinite animations -> If widget not found, add `scrollUntilVisible` -> Re-run test until passing.
92
+
93
+ ## Examples
94
+
95
+ ### Standard Integration Test (`integration_test/app_test.dart`)
96
+
97
+ ```dart
98
+ import 'package:flutter/material.dart';
99
+ import 'package:flutter_test/flutter_test.dart';
100
+ import 'package:integration_test/integration_test.dart';
101
+ import 'package:my_app/main.dart';
102
+
103
+ void main() {
104
+ IntegrationTestWidgetsFlutterBinding.ensureInitialized();
105
+
106
+ group('End-to-end test', () {
107
+ testWidgets('tap on the floating action button, verify counter', (tester) async {
108
+ // Load app widget.
109
+ await tester.pumpWidget(const MyApp());
110
+
111
+ // Verify the counter starts at 0.
112
+ expect(find.text('0'), findsOneWidget);
113
+
114
+ // Find the floating action button to tap on.
115
+ final fab = find.byKey(const ValueKey('increment'));
116
+
117
+ // Emulate a tap on the floating action button.
118
+ await tester.tap(fab);
119
+
120
+ // Trigger a frame and wait for animations.
121
+ await tester.pumpAndSettle();
122
+
123
+ // Verify the counter increments by 1.
124
+ expect(find.text('1'), findsOneWidget);
125
+ });
126
+ });
127
+ }
128
+ ```
129
+
130
+ ### Host Driver Script (`test_driver/integration_test.dart`)
131
+
132
+ ```dart
133
+ import 'package:integration_test/integration_test_driver.dart';
134
+
135
+ Future<void> main() => integrationDriver();
136
+ ```
137
+
138
+ ### Performance Profiling Driver Script (`test_driver/perf_driver.dart`)
139
+
140
+ Use this driver script if you wrap your test actions in `binding.traceAction()` to capture performance metrics.
141
+
142
+ ```dart
143
+ import 'package:flutter_driver/flutter_driver.dart' as driver;
144
+ import 'package:integration_test/integration_test_driver.dart';
145
+
146
+ Future<void> main() {
147
+ return integrationDriver(
148
+ responseDataCallback: (data) async {
149
+ if (data != null) {
150
+ final timeline = driver.Timeline.fromJson(
151
+ data['scrolling_timeline'] as Map<String, dynamic>,
152
+ );
153
+
154
+ final summary = driver.TimelineSummary.summarize(timeline);
155
+
156
+ await summary.writeTimelineToFile(
157
+ 'scrolling_timeline',
158
+ pretty: true,
159
+ includeSummary: true,
160
+ );
161
+ }
162
+ },
163
+ );
164
+ }
165
+ ```
@@ -0,0 +1,147 @@
1
+ 【claude code调用标识:flutter-add-widget-preview】【trae调用标识:flutter-add-widget-preview+Flutter开发】【流程场景:1.完整3阶段SDD流程、3.小型功能迭代】
2
+
3
+ ---
4
+ name: flutter-add-widget-preview
5
+ description: Adds interactive widget previews to the project using the previews.dart system. Use when creating new UI components or updating existing screens to ensure consistent design and interactive testing.
6
+ metadata:
7
+ model: models/gemini-3.1-pro-preview
8
+ last_modified: Tue, 21 Apr 2026 20:05:23 GMT
9
+ ---
10
+ # Previewing Flutter Widgets
11
+
12
+ ## Contents
13
+ - [Preview Guidelines](#preview-guidelines)
14
+ - [Handling Limitations](#handling-limitations)
15
+ - [Workflows](#workflows)
16
+ - [Examples](#examples)
17
+
18
+ ## Preview Guidelines
19
+
20
+ Use the Flutter Widget Previewer to render widgets in real-time, isolated from the full application context.
21
+
22
+ - **Target Elements:** Apply the `@Preview` annotation to top-level functions, static methods within a class, or public widget constructors/factories that have no required arguments and return a `Widget` or `WidgetBuilder`.
23
+ - **Imports:** Always import `package:flutter/widget_previews.dart` to access the preview annotations.
24
+ - **Custom Annotations:** Extend the `Preview` class to create custom annotations that inject common properties (e.g., themes, wrappers) across multiple widgets.
25
+ - **Multiple Configurations:** Apply multiple `@Preview` annotations to a single target to generate multiple preview instances. Alternatively, extend `MultiPreview` to encapsulate common multi-preview configurations.
26
+ - **Runtime Transformations:** Override the `transform()` method in custom `Preview` or `MultiPreview` classes to modify preview configurations dynamically at runtime (e.g., generating names based on dynamic values, which is impossible in a `const` context).
27
+
28
+ ## Handling Limitations
29
+
30
+ Adhere to the following constraints when authoring previewable widgets, as the Widget Previewer runs in a web environment:
31
+
32
+ - **No Native APIs:** Do not use native plugins or APIs from `dart:io` or `dart:ffi`. Widgets with transitive dependencies on `dart:io` or `dart:ffi` will throw exceptions upon invocation. Use conditional imports to mock or bypass these in preview mode.
33
+ - **Asset Paths:** Use package-based paths for assets loaded via `dart:ui` `fromAsset` APIs (e.g., `packages/my_package_name/assets/my_image.png` instead of `assets/my_image.png`).
34
+ - **Public Callbacks:** Ensure all callback arguments provided to preview annotations are public and constant to satisfy code generation requirements.
35
+ - **Constraints:** Apply explicit constraints using the `size` parameter in the `@Preview` annotation if your widget is unconstrained, as the previewer defaults to constraining them to approximately half the viewport.
36
+
37
+ ## Workflows
38
+
39
+ ### Creating a Widget Preview
40
+ Copy and track this checklist when implementing a new widget preview:
41
+
42
+ - [ ] Import `package:flutter/widget_previews.dart`.
43
+ - [ ] Identify a valid target (top-level function, static method, or parameter-less public constructor).
44
+ - [ ] Apply the `@Preview` annotation to the target.
45
+ - [ ] Configure preview parameters (`name`, `group`, `size`, `theme`, `brightness`, etc.) as needed.
46
+ - [ ] If applying the same configuration to multiple widgets, extract the configuration into a custom class extending `Preview`.
47
+
48
+ ### Interacting with Previews
49
+ Follow the appropriate conditional workflow to launch and interact with the Widget Previewer:
50
+
51
+ **If using a supported IDE (Android Studio, IntelliJ, VS Code with Flutter 3.38+):**
52
+ 1. Launch the IDE. The Widget Previewer starts automatically.
53
+ 2. Open the "Flutter Widget Preview" tab in the sidebar.
54
+ 3. Toggle "Filter previews by selected file" at the bottom left if you want to view previews outside the currently active file.
55
+
56
+ **If using the Command Line:**
57
+ 1. Navigate to the Flutter project's root directory.
58
+ 2. Run `flutter widget-preview start`.
59
+ 3. View the automatically opened Chrome environment.
60
+
61
+ **Feedback Loop: Preview Iteration**
62
+ 1. Modify the widget code or preview configuration.
63
+ 2. Observe the automatic update in the Widget Previewer.
64
+ 3. If global state (e.g., static initializers) was modified: Click the global hot restart button at the bottom right.
65
+ 4. If only the local widget state needs resetting: Click the individual hot restart button on the specific preview card.
66
+ 5. Review errors in the IDE/CLI console -> fix -> repeat.
67
+
68
+ ## Examples
69
+
70
+ ### Basic Preview
71
+ ```dart
72
+ import 'package:flutter/widget_previews.dart';
73
+ import 'package:flutter/material.dart';
74
+
75
+ @Preview(name: 'My Sample Text', group: 'Typography')
76
+ Widget mySampleText() {
77
+ return const Text('Hello, World!');
78
+ }
79
+ ```
80
+
81
+ ### Custom Preview with Runtime Transformation
82
+ ```dart
83
+ import 'package:flutter/widget_previews.dart';
84
+ import 'package:flutter/material.dart';
85
+
86
+ final class TransformativePreview extends Preview {
87
+ const TransformativePreview({
88
+ super.name,
89
+ super.group,
90
+ });
91
+
92
+ PreviewThemeData _themeBuilder() {
93
+ return PreviewThemeData(
94
+ materialLight: ThemeData.light(),
95
+ materialDark: ThemeData.dark(),
96
+ );
97
+ }
98
+
99
+ @override
100
+ Preview transform() {
101
+ final originalPreview = super.transform();
102
+ final builder = originalPreview.toBuilder();
103
+
104
+ builder
105
+ ..name = 'Transformed - ${originalPreview.name}'
106
+ ..theme = _themeBuilder;
107
+
108
+ return builder.toPreview();
109
+ }
110
+ }
111
+
112
+ @TransformativePreview(name: 'Custom Themed Button')
113
+ Widget myButton() => const ElevatedButton(onPressed: null, child: Text('Click'));
114
+ ```
115
+
116
+ ### MultiPreview Implementation
117
+ ```dart
118
+ import 'package:flutter/widget_previews.dart';
119
+ import 'package:flutter/material.dart';
120
+
121
+ /// Creates light and dark mode previews automatically.
122
+ final class MultiBrightnessPreview extends MultiPreview {
123
+ const MultiBrightnessPreview({required this.name});
124
+
125
+ final String name;
126
+
127
+ @override
128
+ List<Preview> get previews => const [
129
+ Preview(brightness: Brightness.light),
130
+ Preview(brightness: Brightness.dark),
131
+ ];
132
+
133
+ @override
134
+ List<Preview> transform() {
135
+ final previews = super.transform();
136
+ return previews.map((preview) {
137
+ final builder = preview.toBuilder()
138
+ ..group = 'Brightness'
139
+ ..name = '$name - ${preview.brightness!.name}';
140
+ return builder.toPreview();
141
+ }).toList();
142
+ }
143
+ }
144
+
145
+ @MultiBrightnessPreview(name: 'Primary Card')
146
+ Widget cardPreview() => const Card(child: Padding(padding: EdgeInsets.all(8.0), child: Text('Content')));
147
+ ```