@bovinphang/frontend-craft 2.5.0 → 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 (156) hide show
  1. package/.claude-plugin/marketplace.json +7 -3
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +77 -1
  4. package/CHANGELOG.zh-CN.md +77 -1
  5. package/CONTRIBUTING.md +15 -10
  6. package/CONTRIBUTING.zh-CN.md +15 -10
  7. package/README.md +69 -43
  8. package/README.openclaw.md +11 -9
  9. package/README.openclaw.zh-CN.md +11 -9
  10. package/README.zh-CN.md +69 -43
  11. package/agents/fec-typescript-reviewer.md +1 -1
  12. package/commands/fec-doc-sync.md +7 -6
  13. package/dist/bin/frontend-craft.js +30 -27
  14. package/docs/example-prompts.md +82 -69
  15. package/docs/ja-JP/README.md +110 -84
  16. package/docs/ko-KR/README.md +100 -74
  17. package/docs/project-structure.md +8 -4
  18. package/docs/runtimes/antigravity.md +1 -1
  19. package/docs/runtimes/augment.md +1 -1
  20. package/docs/runtimes/claude.md +16 -10
  21. package/docs/runtimes/claude.zh-CN.md +16 -10
  22. package/docs/runtimes/cline.md +1 -1
  23. package/docs/runtimes/codebuddy.md +1 -1
  24. package/docs/runtimes/codex.md +1 -1
  25. package/docs/runtimes/copilot.md +1 -1
  26. package/docs/runtimes/cursor.md +1 -1
  27. package/docs/runtimes/gemini.md +1 -1
  28. package/docs/runtimes/kilo.md +1 -1
  29. package/docs/runtimes/openclaw.md +1 -1
  30. package/docs/runtimes/opencode.md +1 -1
  31. package/docs/runtimes/qoder.md +1 -1
  32. package/docs/runtimes/trae.md +1 -1
  33. package/docs/runtimes/windsurf.md +1 -1
  34. package/docs/zh-CN/example-prompts.md +82 -69
  35. package/docs/zh-CN/project-structure.md +8 -4
  36. package/docs/zh-TW/README.md +88 -62
  37. package/openclaw.plugin.json +1 -1
  38. package/package.json +3 -3
  39. package/skills/eval_queries.json +179 -56
  40. package/skills/fec-accessibility-check/SKILL.md +1 -1
  41. package/skills/fec-alchemy/SKILL.md +74 -0
  42. package/skills/fec-alchemy/assets/absorption-plan-template.md +47 -0
  43. package/skills/fec-alchemy/assets/intake-template.md +55 -0
  44. package/skills/fec-alchemy/assets/review-checklist.md +31 -0
  45. package/skills/fec-alchemy/references/methodology.md +94 -0
  46. package/skills/fec-alchemy/references/originality-and-licensing.md +57 -0
  47. package/skills/fec-backend-requirements-handoff/SKILL.md +45 -0
  48. package/skills/fec-browser-storage/SKILL.md +1 -1
  49. package/skills/fec-canvas-threejs/SKILL.md +1 -1
  50. package/skills/fec-code-review/SKILL.md +11 -3
  51. package/skills/fec-data-fetching/SKILL.md +15 -15
  52. package/skills/fec-data-fetching/references/query-patterns.md +27 -1
  53. package/skills/fec-debug-framework/SKILL.md +14 -19
  54. package/skills/fec-debug-framework/references/report-template.md +58 -0
  55. package/skills/fec-doc-sync/SKILL.md +19 -17
  56. package/skills/fec-drawio-studio/SKILL.md +69 -0
  57. package/skills/fec-drawio-studio/data/THIRD_PARTY_NOTICES.md +10 -0
  58. package/skills/fec-drawio-studio/data/brand-icons.json +878 -0
  59. package/skills/fec-drawio-studio/data/shape-index.json.gz +0 -0
  60. package/skills/fec-drawio-studio/references/data-residency.md +27 -0
  61. package/skills/fec-drawio-studio/references/diagram-patterns.md +41 -0
  62. package/skills/fec-drawio-studio/references/layout-and-export.md +57 -0
  63. package/skills/fec-drawio-studio/references/troubleshooting.md +29 -0
  64. package/skills/fec-drawio-studio/references/xml-and-mermaid.md +54 -0
  65. package/skills/fec-drawio-studio/scripts/brand-symbols.mjs +99 -0
  66. package/skills/fec-drawio-studio/scripts/diagram-lint.mjs +143 -0
  67. package/skills/fec-drawio-studio/scripts/diagram-url.mjs +102 -0
  68. package/skills/fec-drawio-studio/scripts/layout-graph.mjs +107 -0
  69. package/skills/fec-drawio-studio/scripts/png-embed-fix.mjs +26 -0
  70. package/skills/fec-drawio-studio/scripts/scan-go-packages.mjs +36 -0
  71. package/skills/fec-drawio-studio/scripts/scan-js-modules.mjs +52 -0
  72. package/skills/fec-drawio-studio/scripts/scan-python-classes.mjs +30 -0
  73. package/skills/fec-drawio-studio/scripts/scan-python-modules.mjs +55 -0
  74. package/skills/fec-drawio-studio/scripts/scan-rust-modules.mjs +35 -0
  75. package/skills/fec-drawio-studio/scripts/scan-ts-modules.mjs +7 -0
  76. package/skills/fec-drawio-studio/scripts/shape-query.mjs +81 -0
  77. package/skills/fec-drawio-studio/scripts/studio-core.mjs +139 -0
  78. package/skills/fec-drawio-studio/styles/built-in/corporate.json +49 -0
  79. package/skills/fec-drawio-studio/styles/built-in/default.json +49 -0
  80. package/skills/fec-drawio-studio/styles/built-in/handdrawn.json +49 -0
  81. package/skills/fec-drawio-studio/styles/schema.json +112 -0
  82. package/skills/fec-e2e-testing/SKILL.md +5 -3
  83. package/skills/fec-e2e-testing/references/e2e-ci-reporting.md +62 -0
  84. package/skills/fec-e2e-testing/references/e2e-special-scenarios.md +52 -0
  85. package/skills/fec-e2e-testing/references/e2e-visual-regression.md +60 -0
  86. package/skills/fec-form-handling/SKILL.md +11 -11
  87. package/skills/fec-form-handling/references/advanced-form-patterns.md +34 -5
  88. package/skills/fec-image-generation/SKILL.md +56 -0
  89. package/skills/fec-image-generation/references/artifact-routing.md +80 -0
  90. package/skills/fec-image-generation/references/diagram-workflows.md +43 -0
  91. package/skills/fec-image-generation/references/png-qa-autofix.md +30 -0
  92. package/skills/fec-image-generation/scripts/png-qa.mjs +431 -0
  93. package/skills/fec-implement-from-design/SKILL.md +9 -2
  94. package/skills/fec-legacy-to-modern-migration/SKILL.md +29 -163
  95. package/skills/fec-legacy-to-modern-migration/references/migration-execution-checklist.md +110 -0
  96. package/skills/fec-legacy-to-modern-migration/references/migration-strategy-and-mapping.md +48 -0
  97. package/skills/fec-legacy-web-standard/SKILL.md +1 -1
  98. package/skills/fec-list-virtualization/SKILL.md +3 -3
  99. package/skills/fec-list-virtualization/references/virtualization-patterns.md +32 -4
  100. package/skills/fec-motion-interaction/SKILL.md +7 -0
  101. package/skills/fec-nextjs-project-standard/SKILL.md +7 -1
  102. package/skills/fec-performance-optimization/SKILL.md +9 -1
  103. package/skills/fec-performance-optimization/references/framework-performance-patterns.md +38 -0
  104. package/skills/fec-performance-optimization/references/report-template.md +59 -0
  105. package/skills/fec-pwa-implementation/SKILL.md +3 -4
  106. package/skills/fec-react-project-standard/SKILL.md +12 -4
  107. package/skills/fec-react-project-standard/references/react-performance-patterns.md +35 -0
  108. package/skills/fec-react-project-standard/references/react-project-structure.md +197 -0
  109. package/skills/fec-react-project-standard/references/react-quality-patterns.md +131 -0
  110. package/skills/fec-react-project-standard/references/react-runtime-patterns.md +293 -0
  111. package/skills/fec-refactor-clean/SKILL.md +4 -1
  112. package/skills/fec-refactor-clean/references/report-template.md +42 -0
  113. package/skills/fec-responsive-layout/references/responsive-layout-patterns.md +11 -0
  114. package/skills/fec-security-review/SKILL.md +3 -3
  115. package/skills/fec-source-driven-development/SKILL.md +26 -0
  116. package/skills/fec-state-management/SKILL.md +1 -1
  117. package/skills/fec-storybook-component-doc/SKILL.md +2 -2
  118. package/skills/fec-tailwind-design-system/references/tailwind-system-patterns.md +5 -1
  119. package/skills/fec-typescript-project-standard/SKILL.md +54 -0
  120. package/skills/{fec-typescript-type-safety → fec-typescript-project-standard}/references/type-safety-patterns.md +1 -1
  121. package/skills/{fec-typescript-type-safety/SKILL.md → fec-typescript-project-standard/references/type-safety.md} +1 -10
  122. package/skills/fec-ui-design/SKILL.md +26 -8
  123. package/skills/fec-ui-design/data/style-archetypes.json +40 -0
  124. package/skills/fec-ui-design/data/ux-quality-rules.json +35 -0
  125. package/skills/fec-ui-design/references/design-intelligence.md +66 -6
  126. package/skills/fec-ui-design/references/pre-delivery-checklist.md +6 -0
  127. package/skills/fec-ui-design/scripts/design-system.mjs +119 -1
  128. package/skills/fec-validation-fix/SKILL.md +5 -2
  129. package/skills/fec-validation-fix/references/report-template.md +43 -0
  130. package/skills/fec-vue3-project-standard/SKILL.md +12 -3
  131. package/skills/fec-vue3-project-standard/references/vue3-composables-routing.md +163 -0
  132. package/skills/fec-vue3-project-standard/references/vue3-performance-patterns.md +13 -0
  133. package/skills/fec-vue3-project-standard/references/vue3-project-structure.md +177 -0
  134. package/skills/fec-vue3-project-standard/references/vue3-state-api-quality.md +216 -0
  135. package/skills/fec-web-video-presentation/SKILL.md +61 -0
  136. package/skills/fec-web-video-presentation/data/starter-themes.json +59 -0
  137. package/skills/fec-web-video-presentation/references/chapter-craft.md +37 -0
  138. package/skills/fec-web-video-presentation/references/content-plan.md +38 -0
  139. package/skills/fec-web-video-presentation/references/recording-and-audio.md +33 -0
  140. package/skills/fec-web-video-presentation/references/theme-system.md +36 -0
  141. package/skills/fec-web-video-presentation/scripts/create-video-presentation.mjs +430 -0
  142. package/skills/fec-web-workers/SKILL.md +3 -4
  143. package/skills/metadata.json +381 -168
  144. package/skills/relations.json +136 -25
  145. package/templates/shared/rules/fec-ci-cd.md +20 -108
  146. package/templates/shared/rules/fec-design-system.md +47 -223
  147. package/templates/shared/rules/fec-error-handling.md +35 -179
  148. package/templates/shared/rules/fec-i18n.md +43 -91
  149. package/templates/shared/rules/fec-refactoring.md +4 -0
  150. package/templates/shared/rules/fec-rendering-patterns.md +28 -171
  151. package/templates/shared/rules/fec-responsive-design.md +34 -211
  152. package/templates/shared/rules/fec-state-management.md +41 -144
  153. package/templates/shared/rules/fec-typescript.md +47 -290
  154. package/skills/fec-e2e-testing/references/e2e-advanced.md +0 -176
  155. package/skills/fec-react-project-standard/references/react-project-details.md +0 -642
  156. package/skills/fec-vue3-project-standard/references/vue3-project-details.md +0 -547
@@ -0,0 +1,430 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ const skillDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
7
+ const themesPath = path.join(skillDir, "data", "starter-themes.json");
8
+ const themes = JSON.parse(fs.readFileSync(themesPath, "utf8"));
9
+
10
+ const args = process.argv.slice(2);
11
+ const options = parseArgs(args);
12
+
13
+ if (options.help) {
14
+ printHelp();
15
+ process.exit(0);
16
+ }
17
+
18
+ if (options.listThemes) {
19
+ for (const theme of themes) {
20
+ console.log(`${theme.id}\t${theme.name}\t${theme.bestFor}`);
21
+ }
22
+ process.exit(0);
23
+ }
24
+
25
+ const target = path.resolve(process.cwd(), options.target ?? "presentation");
26
+ const theme = themes.find((candidate) => candidate.id === options.theme);
27
+
28
+ if (!theme) {
29
+ fail(`Unknown theme "${options.theme}". Run with --list-themes to see available themes.`);
30
+ }
31
+
32
+ const files = buildFiles(theme);
33
+
34
+ if (options.dryRun) {
35
+ console.log(`Would create ${files.length} files in ${target}`);
36
+ console.log(`Theme: ${theme.id} (${theme.name})`);
37
+ for (const file of files) console.log(`- ${file.name}`);
38
+ process.exit(0);
39
+ }
40
+
41
+ if (fs.existsSync(target) && fs.readdirSync(target).length > 0) {
42
+ fail(`Target directory is not empty: ${target}`);
43
+ }
44
+
45
+ for (const file of files) {
46
+ const fullPath = path.join(target, file.name);
47
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
48
+ fs.writeFileSync(fullPath, file.body, "utf8");
49
+ }
50
+
51
+ console.log(`Created web video presentation at ${target}`);
52
+ console.log(`Theme: ${theme.id} (${theme.name})`);
53
+ console.log("Next:");
54
+ console.log(" cd " + path.relative(process.cwd(), target));
55
+ console.log(" npm install");
56
+ console.log(" npm run dev");
57
+
58
+ function parseArgs(values) {
59
+ const out = {
60
+ dryRun: false,
61
+ help: false,
62
+ listThemes: false,
63
+ target: undefined,
64
+ theme: themes[0]?.id ?? "editorial-slate",
65
+ };
66
+
67
+ for (let index = 0; index < values.length; index += 1) {
68
+ const value = values[index];
69
+ if (value === "--help" || value === "-h") out.help = true;
70
+ else if (value === "--dry-run") out.dryRun = true;
71
+ else if (value === "--list-themes") out.listThemes = true;
72
+ else if (value.startsWith("--theme=")) out.theme = value.slice("--theme=".length);
73
+ else if (value === "--theme") {
74
+ const next = values[index + 1];
75
+ if (!next || next.startsWith("--")) fail("Missing value for --theme.");
76
+ out.theme = next;
77
+ index += 1;
78
+ }
79
+ else if (value.startsWith("--")) fail(`Unknown option: ${value}`);
80
+ else if (!out.target) out.target = value;
81
+ else fail(`Unexpected argument: ${value}`);
82
+ }
83
+
84
+ return out;
85
+ }
86
+
87
+ function buildFiles(theme) {
88
+ const tokenCss = renderTokens(theme.tokens);
89
+ return [
90
+ {
91
+ name: "package.json",
92
+ body: JSON.stringify(
93
+ {
94
+ scripts: {
95
+ dev: "vite",
96
+ build: "tsc --noEmit && vite build",
97
+ preview: "vite preview",
98
+ },
99
+ dependencies: {
100
+ react: "latest",
101
+ "react-dom": "latest",
102
+ },
103
+ devDependencies: {
104
+ "@types/react": "latest",
105
+ "@types/react-dom": "latest",
106
+ "@vitejs/plugin-react": "latest",
107
+ typescript: "latest",
108
+ vite: "latest",
109
+ },
110
+ },
111
+ null,
112
+ 2,
113
+ ) + "\n",
114
+ },
115
+ {
116
+ name: "index.html",
117
+ body: `<!doctype html>
118
+ <html lang="en">
119
+ <head>
120
+ <meta charset="UTF-8" />
121
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
122
+ <title>Web Video Presentation</title>
123
+ </head>
124
+ <body>
125
+ <div id="root"></div>
126
+ <script type="module" src="/src/main.tsx"></script>
127
+ </body>
128
+ </html>
129
+ `,
130
+ },
131
+ {
132
+ name: "tsconfig.json",
133
+ body: JSON.stringify(
134
+ {
135
+ compilerOptions: {
136
+ target: "ES2022",
137
+ useDefineForClassFields: true,
138
+ lib: ["DOM", "DOM.Iterable", "ES2022"],
139
+ allowJs: false,
140
+ skipLibCheck: true,
141
+ esModuleInterop: true,
142
+ allowSyntheticDefaultImports: true,
143
+ strict: true,
144
+ forceConsistentCasingInFileNames: true,
145
+ module: "ESNext",
146
+ moduleResolution: "Node",
147
+ resolveJsonModule: true,
148
+ isolatedModules: true,
149
+ noEmit: true,
150
+ jsx: "react-jsx",
151
+ },
152
+ include: ["src"],
153
+ },
154
+ null,
155
+ 2,
156
+ ) + "\n",
157
+ },
158
+ {
159
+ name: "vite.config.ts",
160
+ body: `import { defineConfig } from 'vite';
161
+ import react from '@vitejs/plugin-react';
162
+
163
+ export default defineConfig({
164
+ plugins: [react()],
165
+ });
166
+ `,
167
+ },
168
+ {
169
+ name: "src/main.tsx",
170
+ body: `import React, { useEffect, useMemo, useState } from 'react';
171
+ import { createRoot } from 'react-dom/client';
172
+ import './styles.css';
173
+
174
+ type Scene = {
175
+ eyebrow: string;
176
+ title: string;
177
+ body: string;
178
+ detail: string;
179
+ };
180
+
181
+ const scenes: Scene[] = [
182
+ {
183
+ eyebrow: '01 / Hook',
184
+ title: 'Replace this with the first spoken beat',
185
+ body: 'One step equals one idea. Keep it readable in a 1080p recording.',
186
+ detail: 'Use source facts, product states, diagrams, or real assets to make the screen specific.',
187
+ },
188
+ {
189
+ eyebrow: '02 / Proof',
190
+ title: 'Show the evidence, not a generic slide',
191
+ body: 'Turn a claim into a visual: timeline, interface state, metric, map, comparison, or system diagram.',
192
+ detail: 'Advance with Space, ArrowRight, PageDown, or click. Go back with ArrowLeft or PageUp.',
193
+ },
194
+ {
195
+ eyebrow: '03 / Close',
196
+ title: 'End on the idea the viewer should remember',
197
+ body: 'Swap this starter content for your script and outline.',
198
+ detail: 'Controls stay quiet so the stage is clean for recording.',
199
+ },
200
+ ];
201
+
202
+ const storageKey = 'fec-web-video-presentation-step-v1';
203
+
204
+ function App() {
205
+ const [step, setStep] = useState(() => Number(localStorage.getItem(storageKey) ?? 0));
206
+ const current = scenes[Math.min(Math.max(step, 0), scenes.length - 1)];
207
+ const progress = useMemo(() => ((step + 1) / scenes.length) * 100, [step]);
208
+
209
+ useEffect(() => {
210
+ localStorage.setItem(storageKey, String(step));
211
+ }, [step]);
212
+
213
+ useEffect(() => {
214
+ const onKeyDown = (event: KeyboardEvent) => {
215
+ if (event.key === 'ArrowRight' || event.key === 'PageDown' || event.key === ' ') {
216
+ event.preventDefault();
217
+ setStep((value) => Math.min(value + 1, scenes.length - 1));
218
+ }
219
+ if (event.key === 'ArrowLeft' || event.key === 'PageUp') {
220
+ event.preventDefault();
221
+ setStep((value) => Math.max(value - 1, 0));
222
+ }
223
+ if (event.key.toLowerCase() === 'r') {
224
+ setStep(0);
225
+ }
226
+ };
227
+ window.addEventListener('keydown', onKeyDown);
228
+ return () => window.removeEventListener('keydown', onKeyDown);
229
+ }, []);
230
+
231
+ return (
232
+ <main className="viewport" onClick={() => setStep((value) => Math.min(value + 1, scenes.length - 1))}>
233
+ <section className="stage" aria-live="polite">
234
+ <div className="scene-grid">
235
+ <div className="copy">
236
+ <p className="eyebrow">{current.eyebrow}</p>
237
+ <h1>{current.title}</h1>
238
+ <p className="body">{current.body}</p>
239
+ </div>
240
+ <div className="visual" aria-label="Visual evidence placeholder">
241
+ <span>{String(step + 1).padStart(2, '0')}</span>
242
+ <p>{current.detail}</p>
243
+ </div>
244
+ </div>
245
+ <div className="progress" aria-hidden="true">
246
+ <span style={{ width: \`\${progress}%\` }} />
247
+ </div>
248
+ </section>
249
+ </main>
250
+ );
251
+ }
252
+
253
+ createRoot(document.getElementById('root')!).render(<App />);
254
+ `,
255
+ },
256
+ {
257
+ name: "src/styles.css",
258
+ body: `${tokenCss}
259
+
260
+ * {
261
+ box-sizing: border-box;
262
+ }
263
+
264
+ html,
265
+ body,
266
+ #root {
267
+ margin: 0;
268
+ min-height: 100%;
269
+ }
270
+
271
+ body {
272
+ background: #111;
273
+ color: var(--stage-fg);
274
+ font-family: var(--font-body);
275
+ }
276
+
277
+ .viewport {
278
+ min-height: 100vh;
279
+ display: grid;
280
+ place-items: center;
281
+ padding: 24px;
282
+ }
283
+
284
+ .stage {
285
+ width: min(100vw - 48px, calc((100vh - 48px) * 16 / 9));
286
+ aspect-ratio: 16 / 9;
287
+ position: relative;
288
+ overflow: hidden;
289
+ background: var(--stage-bg);
290
+ color: var(--stage-fg);
291
+ box-shadow: var(--shadow);
292
+ }
293
+
294
+ .scene-grid {
295
+ height: 100%;
296
+ display: grid;
297
+ grid-template-columns: 1.12fr 0.88fr;
298
+ gap: 72px;
299
+ align-items: center;
300
+ padding: 96px;
301
+ }
302
+
303
+ .eyebrow {
304
+ color: var(--accent);
305
+ font-size: 24px;
306
+ font-weight: 700;
307
+ margin: 0 0 26px;
308
+ text-transform: uppercase;
309
+ letter-spacing: 0.08em;
310
+ }
311
+
312
+ h1 {
313
+ font-family: var(--font-display);
314
+ font-size: clamp(48px, 6vw, 104px);
315
+ line-height: 0.96;
316
+ letter-spacing: 0;
317
+ margin: 0;
318
+ text-wrap: balance;
319
+ }
320
+
321
+ .body {
322
+ color: var(--muted-fg);
323
+ font-size: 32px;
324
+ line-height: 1.35;
325
+ margin: 36px 0 0;
326
+ max-width: 820px;
327
+ text-wrap: pretty;
328
+ }
329
+
330
+ .visual {
331
+ min-height: 560px;
332
+ border: 1px solid var(--line);
333
+ border-radius: var(--radius);
334
+ background: var(--panel);
335
+ display: grid;
336
+ align-content: space-between;
337
+ padding: 42px;
338
+ }
339
+
340
+ .visual span {
341
+ color: var(--accent-2);
342
+ font-family: var(--font-display);
343
+ font-size: 132px;
344
+ line-height: 1;
345
+ font-variant-numeric: tabular-nums;
346
+ }
347
+
348
+ .visual p {
349
+ margin: 0;
350
+ color: var(--muted-fg);
351
+ font-size: 26px;
352
+ line-height: 1.4;
353
+ }
354
+
355
+ .progress {
356
+ position: absolute;
357
+ left: 32px;
358
+ right: 32px;
359
+ bottom: 28px;
360
+ height: 3px;
361
+ background: color-mix(in srgb, var(--line) 70%, transparent);
362
+ opacity: 0;
363
+ transition: opacity 160ms ease;
364
+ }
365
+
366
+ .stage:hover .progress,
367
+ .stage:focus-within .progress {
368
+ opacity: 1;
369
+ }
370
+
371
+ .progress span {
372
+ display: block;
373
+ height: 100%;
374
+ background: var(--accent);
375
+ transition: width var(--step-duration) ease;
376
+ }
377
+
378
+ @media (prefers-reduced-motion: reduce) {
379
+ .progress,
380
+ .progress span {
381
+ transition: none;
382
+ }
383
+ }
384
+ `,
385
+ },
386
+ {
387
+ name: "README.md",
388
+ body: `# Web Video Presentation
389
+
390
+ Generated with Frontend Craft.
391
+
392
+ - 16:9 browser recording stage
393
+ - Step-driven scenes
394
+ - Keyboard and click navigation
395
+ - Theme tokens in \`src/styles.css\`
396
+
397
+ Replace the starter scenes in \`src/main.tsx\` with your script and outline.
398
+ `,
399
+ },
400
+ ];
401
+ }
402
+
403
+ function renderTokens(tokens) {
404
+ return `:root {
405
+ --stage-bg: ${tokens.stageBg};
406
+ --stage-fg: ${tokens.stageFg};
407
+ --muted-fg: ${tokens.mutedFg};
408
+ --accent: ${tokens.accent};
409
+ --accent-2: ${tokens.accent2};
410
+ --panel: ${tokens.panel};
411
+ --line: ${tokens.line};
412
+ --shadow: ${tokens.shadow};
413
+ --font-display: ${tokens.fontDisplay};
414
+ --font-body: ${tokens.fontBody};
415
+ --radius: ${tokens.radius};
416
+ --step-duration: ${tokens.stepDuration};
417
+ }`;
418
+ }
419
+
420
+ function printHelp() {
421
+ console.log(`Usage:
422
+ node skills/fec-web-video-presentation/scripts/create-video-presentation.mjs [target] [--theme=<id>] [--dry-run]
423
+ node skills/fec-web-video-presentation/scripts/create-video-presentation.mjs --list-themes
424
+ `);
425
+ }
426
+
427
+ function fail(message) {
428
+ console.error(`[create-video-presentation] ${message}`);
429
+ process.exit(1);
430
+ }
@@ -17,10 +17,10 @@ description: Use when moving expensive browser work off the main thread with Web
17
17
  4. 传大对象时优先 Transferable Objects;不要让结构化克隆吞掉 Worker 带来的收益。
18
18
  5. 在组件或页面卸载时 `terminate()`,并通过 Profiler、Performance 面板或 FPS 指标验证主线程改善。
19
19
 
20
- ## Detailed References
20
+ ## 详细参考
21
21
 
22
- - Load [references/basic-worker.md](references/basic-worker.md) for plain Worker files, bundler imports, React lifecycle wrapping, and cleanup.
23
- - Load [references/advanced-workers.md](references/advanced-workers.md) for Transferable Objects, Comlink, Worker pools, SharedWorker, CSP, and SharedArrayBuffer notes.
22
+ - 需要原生 Worker 文件、构建工具导入、React 生命周期封装和清理示例时,加载 [references/basic-worker.md](references/basic-worker.md)。
23
+ - 需要 Transferable Objects、Comlink、Worker pool、SharedWorker、CSP 和 SharedArrayBuffer 注意事项时,加载 [references/advanced-workers.md](references/advanced-workers.md)。
24
24
 
25
25
  ## Constraints
26
26
 
@@ -33,4 +33,3 @@ description: Use when moving expensive browser work off the main thread with Web
33
33
  ## Expected Output
34
34
 
35
35
  计算密集型操作在后台线程执行,主线程输入和滚动恢复流畅,错误与取消路径明确,Worker 在卸载时被终止且无内存泄漏。
36
-