@caddis/cli 0.0.0 → 0.1.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 (153) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +150 -1
  3. package/bundles/antigravity-plugin/agents/code-reviewer.md +47 -0
  4. package/bundles/antigravity-plugin/agents/preflight.md +53 -0
  5. package/bundles/antigravity-plugin/guard_agy.py +338 -0
  6. package/bundles/antigravity-plugin/hooks.json +36 -0
  7. package/bundles/antigravity-plugin/mcp_config.json +8 -0
  8. package/bundles/antigravity-plugin/mcp_ping_server.py +55 -0
  9. package/bundles/antigravity-plugin/plugin.json +5 -0
  10. package/bundles/antigravity-plugin/session_end_agy.py +57 -0
  11. package/bundles/antigravity-plugin/skills/_registry.md +115 -0
  12. package/bundles/antigravity-plugin/skills/add-rules/SKILL.md +45 -0
  13. package/bundles/antigravity-plugin/skills/api-design/SKILL.md +249 -0
  14. package/bundles/antigravity-plugin/skills/backend-development/SKILL.md +305 -0
  15. package/bundles/antigravity-plugin/skills/best-practices/SKILL.md +500 -0
  16. package/bundles/antigravity-plugin/skills/best-practices/agents/best-practices-referencer.md +263 -0
  17. package/bundles/antigravity-plugin/skills/best-practices/agents/codebase-context-builder.md +326 -0
  18. package/bundles/antigravity-plugin/skills/best-practices/agents/task-intent-analyzer.md +245 -0
  19. package/bundles/antigravity-plugin/skills/best-practices/references/anti-patterns.md +571 -0
  20. package/bundles/antigravity-plugin/skills/best-practices/references/before-after-examples.md +1114 -0
  21. package/bundles/antigravity-plugin/skills/best-practices/references/best-practices-guide.md +513 -0
  22. package/bundles/antigravity-plugin/skills/best-practices/references/common-workflows.md +692 -0
  23. package/bundles/antigravity-plugin/skills/best-practices/references/prompt-patterns.md +547 -0
  24. package/bundles/antigravity-plugin/skills/brainstorming/SKILL.md +57 -0
  25. package/bundles/antigravity-plugin/skills/ci-cd-pipeline/SKILL.md +315 -0
  26. package/bundles/antigravity-plugin/skills/code-documentation/SKILL.md +271 -0
  27. package/bundles/antigravity-plugin/skills/code-review/SKILL.md +122 -0
  28. package/bundles/antigravity-plugin/skills/codebase-audit/SKILL.md +204 -0
  29. package/bundles/antigravity-plugin/skills/context-curator/SKILL.md +157 -0
  30. package/bundles/antigravity-plugin/skills/cross-review/SKILL.md +40 -0
  31. package/bundles/antigravity-plugin/skills/css-architecture/SKILL.md +305 -0
  32. package/bundles/antigravity-plugin/skills/css-architecture/references/RESPONSIVE-DESIGN.md +604 -0
  33. package/bundles/antigravity-plugin/skills/database-design/SKILL.md +177 -0
  34. package/bundles/antigravity-plugin/skills/db-diagram/SKILL.md +148 -0
  35. package/bundles/antigravity-plugin/skills/db-diagram/scripts/sql_to_graph.py +1212 -0
  36. package/bundles/antigravity-plugin/skills/digress/SKILL.md +61 -0
  37. package/bundles/antigravity-plugin/skills/draw-io/SKILL.md +162 -0
  38. package/bundles/antigravity-plugin/skills/draw-io/references/aws-icons.md +677 -0
  39. package/bundles/antigravity-plugin/skills/draw-io/references/layout-guidelines.md +142 -0
  40. package/bundles/antigravity-plugin/skills/draw-io/references/troubleshooting.md +118 -0
  41. package/bundles/antigravity-plugin/skills/draw-io/references/workflows.md +103 -0
  42. package/bundles/antigravity-plugin/skills/draw-io/scripts/convert-drawio-to-png.sh +25 -0
  43. package/bundles/antigravity-plugin/skills/draw-io/scripts/find_aws_icon.py +79 -0
  44. package/bundles/antigravity-plugin/skills/error-handling/SKILL.md +260 -0
  45. package/bundles/antigravity-plugin/skills/excalidraw-db/SKILL.md +38 -0
  46. package/bundles/antigravity-plugin/skills/fastapi-dev/SKILL.md +300 -0
  47. package/bundles/antigravity-plugin/skills/feature-plan/SKILL.md +198 -0
  48. package/bundles/antigravity-plugin/skills/frontend-design/SKILL.md +193 -0
  49. package/bundles/antigravity-plugin/skills/frontend-design/references/my-tech-stack.md +127 -0
  50. package/bundles/antigravity-plugin/skills/gh-cli/SKILL.md +195 -0
  51. package/bundles/antigravity-plugin/skills/git-commit/SKILL.md +285 -0
  52. package/bundles/antigravity-plugin/skills/golden-plan/SKILL.md +577 -0
  53. package/bundles/antigravity-plugin/skills/handoff/SKILL.md +100 -0
  54. package/bundles/antigravity-plugin/skills/implement/SKILL.md +114 -0
  55. package/bundles/antigravity-plugin/skills/javascript-typescript/SKILL.md +142 -0
  56. package/bundles/antigravity-plugin/skills/kb/SKILL.md +60 -0
  57. package/bundles/antigravity-plugin/skills/mermaid-db/SKILL.md +33 -0
  58. package/bundles/antigravity-plugin/skills/mermaid-diagrams/SKILL.md +236 -0
  59. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/ENHANCEMENTS.md +264 -0
  60. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/MERMAID-SUMMARY.md +137 -0
  61. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/advanced-features.md +556 -0
  62. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/architecture-diagrams.md +192 -0
  63. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/c4-diagrams.md +410 -0
  64. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/class-diagrams.md +361 -0
  65. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/erd-diagrams.md +510 -0
  66. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/flowcharts.md +450 -0
  67. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/sequence-diagrams.md +394 -0
  68. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/troubleshooting.md +335 -0
  69. package/bundles/antigravity-plugin/skills/mermaid-diagrams/references/workflows.md +418 -0
  70. package/bundles/antigravity-plugin/skills/migrate-dir/SKILL.md +68 -0
  71. package/bundles/antigravity-plugin/skills/mockup/SKILL.md +242 -0
  72. package/bundles/antigravity-plugin/skills/particle-art/SKILL.md +243 -0
  73. package/bundles/antigravity-plugin/skills/particle-art/references/canvas-utils.ts +171 -0
  74. package/bundles/antigravity-plugin/skills/particle-art/references/dot-field.template.tsx +203 -0
  75. package/bundles/antigravity-plugin/skills/particle-art/references/flow-field.template.tsx +263 -0
  76. package/bundles/antigravity-plugin/skills/particle-art/references/node-shape.template.tsx +261 -0
  77. package/bundles/antigravity-plugin/skills/particle-art/references/shape-sampler.ts +281 -0
  78. package/bundles/antigravity-plugin/skills/particle-art/references/stipple-morph.template.tsx +167 -0
  79. package/bundles/antigravity-plugin/skills/particle-art/references/stipple.template.tsx +175 -0
  80. package/bundles/antigravity-plugin/skills/particle-art/references/trail-ghost.template.tsx +266 -0
  81. package/bundles/antigravity-plugin/skills/particle-art/references/usage-examples.md +320 -0
  82. package/bundles/antigravity-plugin/skills/playwright/API_REFERENCE.md +653 -0
  83. package/bundles/antigravity-plugin/skills/playwright/SKILL.md +454 -0
  84. package/bundles/antigravity-plugin/skills/playwright/lib/helpers.js +441 -0
  85. package/bundles/antigravity-plugin/skills/playwright/package.json +26 -0
  86. package/bundles/antigravity-plugin/skills/playwright/run.js +228 -0
  87. package/bundles/antigravity-plugin/skills/prd/SKILL.md +107 -0
  88. package/bundles/antigravity-plugin/skills/preflight/SKILL.md +435 -0
  89. package/bundles/antigravity-plugin/skills/python/SKILL.md +388 -0
  90. package/bundles/antigravity-plugin/skills/react-best-practices/SKILL.md +269 -0
  91. package/bundles/antigravity-plugin/skills/react-dev/README.md +404 -0
  92. package/bundles/antigravity-plugin/skills/react-dev/SKILL.md +459 -0
  93. package/bundles/antigravity-plugin/skills/react-dev/examples/generic-components.md +579 -0
  94. package/bundles/antigravity-plugin/skills/react-dev/examples/server-components.md +579 -0
  95. package/bundles/antigravity-plugin/skills/react-dev/references/event-handlers.md +574 -0
  96. package/bundles/antigravity-plugin/skills/react-dev/references/hooks.md +456 -0
  97. package/bundles/antigravity-plugin/skills/react-dev/references/react-19-patterns.md +638 -0
  98. package/bundles/antigravity-plugin/skills/react-dev/references/react-router.md +1002 -0
  99. package/bundles/antigravity-plugin/skills/react-dev/references/tanstack-router.md +587 -0
  100. package/bundles/antigravity-plugin/skills/refactoring/SKILL.md +486 -0
  101. package/bundles/antigravity-plugin/skills/resume/SKILL.md +36 -0
  102. package/bundles/antigravity-plugin/skills/security-review/SKILL.md +196 -0
  103. package/bundles/antigravity-plugin/skills/setup-project-ai/SKILL.md +61 -0
  104. package/bundles/antigravity-plugin/skills/ship/SKILL.md +107 -0
  105. package/bundles/antigravity-plugin/skills/ship-merge/SKILL.md +103 -0
  106. package/bundles/antigravity-plugin/skills/ship-pr/SKILL.md +102 -0
  107. package/bundles/antigravity-plugin/skills/skill-creator/LICENSE.txt +202 -0
  108. package/bundles/antigravity-plugin/skills/skill-creator/SKILL.md +491 -0
  109. package/bundles/antigravity-plugin/skills/skill-creator/agents/analyzer.md +274 -0
  110. package/bundles/antigravity-plugin/skills/skill-creator/agents/comparator.md +202 -0
  111. package/bundles/antigravity-plugin/skills/skill-creator/agents/grader.md +223 -0
  112. package/bundles/antigravity-plugin/skills/skill-creator/assets/eval_review.html +146 -0
  113. package/bundles/antigravity-plugin/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  114. package/bundles/antigravity-plugin/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  115. package/bundles/antigravity-plugin/skills/skill-creator/references/schemas.md +430 -0
  116. package/bundles/antigravity-plugin/skills/skill-creator/scripts/__init__.py +0 -0
  117. package/bundles/antigravity-plugin/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  118. package/bundles/antigravity-plugin/skills/skill-creator/scripts/generate_report.py +326 -0
  119. package/bundles/antigravity-plugin/skills/skill-creator/scripts/improve_description.py +247 -0
  120. package/bundles/antigravity-plugin/skills/skill-creator/scripts/package_skill.py +136 -0
  121. package/bundles/antigravity-plugin/skills/skill-creator/scripts/quick_validate.py +103 -0
  122. package/bundles/antigravity-plugin/skills/skill-creator/scripts/run_eval.py +310 -0
  123. package/bundles/antigravity-plugin/skills/skill-creator/scripts/run_loop.py +328 -0
  124. package/bundles/antigravity-plugin/skills/skill-creator/scripts/utils.py +47 -0
  125. package/bundles/antigravity-plugin/skills/sql/SKILL.md +321 -0
  126. package/bundles/antigravity-plugin/skills/tdd/SKILL.md +37 -0
  127. package/bundles/antigravity-plugin/skills/tdd-workflow/SKILL.md +188 -0
  128. package/bundles/antigravity-plugin/skills/technical-writing/SKILL.md +286 -0
  129. package/bundles/antigravity-plugin/skills/test-strategy/SKILL.md +155 -0
  130. package/bundles/antigravity-plugin/skills/ui-brief/SKILL.md +84 -0
  131. package/bundles/antigravity-plugin/skills/ui-review/SKILL.md +176 -0
  132. package/bundles/antigravity-plugin/skills/ui-review/references/framework-fixes.md +471 -0
  133. package/bundles/antigravity-plugin/skills/ui-review/references/visual-checklist.md +236 -0
  134. package/bundles/antigravity-plugin/skills/usage-review/SKILL.md +77 -0
  135. package/bundles/antigravity-plugin/skills/use-model/SKILL.md +64 -0
  136. package/bundles/antigravity-plugin/skills/using-git-worktrees/SKILL.md +217 -0
  137. package/bundles/antigravity-plugin/skills/version/SKILL.md +18 -0
  138. package/bundles/antigravity-plugin/skills/warm-editorial-ui/DESIGN_TOKENS.md +487 -0
  139. package/bundles/antigravity-plugin/skills/warm-editorial-ui/IMPLEMENTATION_GUIDE.md +177 -0
  140. package/bundles/antigravity-plugin/skills/warm-editorial-ui/SKILL.md +732 -0
  141. package/bundles/antigravity-plugin/skills/webapp-testing/LICENSE.txt +202 -0
  142. package/bundles/antigravity-plugin/skills/webapp-testing/SKILL.md +97 -0
  143. package/bundles/antigravity-plugin/skills/webapp-testing/examples/console_logging.py +35 -0
  144. package/bundles/antigravity-plugin/skills/webapp-testing/examples/element_discovery.py +40 -0
  145. package/bundles/antigravity-plugin/skills/webapp-testing/examples/static_html_automation.py +33 -0
  146. package/bundles/antigravity-plugin/skills/webapp-testing/scripts/with_server.py +106 -0
  147. package/bundles/antigravity-plugin/skills/windows-deployment/SKILL.md +880 -0
  148. package/bundles/antigravity-plugin/skills/writing-plans/SKILL.md +384 -0
  149. package/bundles/antigravity-plugin/statusline-command-agy.sh +91 -0
  150. package/bundles/antigravity-plugin/warm_start_agy.py +149 -0
  151. package/bundles/manifest.json +6 -0
  152. package/dist/cli.js +5363 -0
  153. package/package.json +61 -4
@@ -0,0 +1,242 @@
1
+ ---
2
+ name: mockup
3
+ description: Create framework-aware UI mockups with feasibility checks. Prevents wasted effort by validating that proposed designs work within the target framework's constraints.
4
+ ---
5
+
6
+ # Mockup Skill
7
+
8
+ ## Purpose
9
+
10
+ Create visual mockups (HTML/SVG) for UI features with **mandatory framework feasibility validation**. This skill exists because of a real incident: a beautiful HTML mockup was created for a Streamlit app using `position: fixed` — which doesn't work in Streamlit's DOM. 24 hours were wasted discovering this.
11
+
12
+ **This skill prevents that class of failure for ANY framework.**
13
+
14
+ ---
15
+
16
+ ## When to Use
17
+
18
+ - Creating a UI mockup for a proposed feature
19
+ - Visualizing a design before implementation
20
+ - Producing a reference artifact for implementing agents
21
+ - When `@ux-designer` routes mockup creation here
22
+
23
+ ---
24
+
25
+ ## Steps
26
+
27
+ ### Step 1: Read Project Context
28
+
29
+ 1. Read `project-config.md` → identify:
30
+ - **Frontend framework** (Streamlit, React, Vue, Angular, Next.js, etc.)
31
+ - **Brand colors** (from profile or placeholder values)
32
+ - **CSS conventions** (scoping method, custom properties, etc.)
33
+ 2. Read `copilot-instructions.md` → identify:
34
+ - Existing component patterns
35
+ - Framework-specific conventions already documented
36
+ 3. If a `chain_id` is provided, read the Intent Document from `agent-docs/intents/`
37
+
38
+ ### Step 2: Framework Feasibility Check (MANDATORY)
39
+
40
+ **Before creating ANY mockup, validate that the proposed design is feasible in the target framework.**
41
+
42
+ Run through this checklist:
43
+
44
+ | Check | Question | If NO |
45
+ |-------|----------|-------|
46
+ | **DOM Control** | Does the framework give you full control over the DOM? | Identify which HTML/CSS features are restricted |
47
+ | **Positioning** | Does `position: fixed/absolute` work as expected? | Document the limitation and alternative approach |
48
+ | **Custom HTML** | Can you inject arbitrary HTML/JS? | Identify the framework's component/extension API |
49
+ | **Event Handling** | Can you attach custom JS event listeners? | Document how events work in this framework |
50
+ | **Styling** | Can you use global CSS freely? | Document CSS scoping constraints |
51
+ | **Third-party Libraries** | Can you load external JS/CSS? | Check if air-gapped deployment restricts this |
52
+
53
+ #### Known Framework Constraints
54
+
55
+ | Framework | Key Constraints |
56
+ |-----------|----------------|
57
+ | **Streamlit** | No `position: fixed/absolute` (DOM wrapping breaks it). No arbitrary HTML injection without `components.html()` or `declare_component()`. CSS is scoped — use `st.container(key=)` + `.st-key-` selectors. No external CDN in air-gapped environments. |
58
+ | **React** | JSX required. CSS-in-JS or CSS Modules typical. Virtual DOM diffing may interfere with manual DOM manipulation. |
59
+ | **Vue** | Template syntax. Scoped styles by default. `v-html` for raw HTML but XSS risk. |
60
+ | **Gradio** | Similar DOM constraints to Streamlit. Limited CSS control. Use `gr.HTML()` for custom elements. |
61
+ | **Next.js** | SSR considerations. `useEffect` needed for client-only code. CSS Modules or Tailwind typical. |
62
+
63
+ > **If ANY constraint would prevent the proposed design from working:**
64
+ > 1. **STOP** — do not create a mockup that can't be implemented
65
+ > 2. **WARN** the user with specific details about what won't work and why
66
+ > 3. **PROPOSE ALTERNATIVES** that work within the framework's constraints
67
+ > 4. **Get confirmation** before proceeding with an alternative approach
68
+
69
+ ### Step 3: Create the Mockup
70
+
71
+ **Output format**: HTML file (preferred for interactive mockups) or SVG (for static layouts)
72
+
73
+ **Requirements:**
74
+ - Use brand colors from `project-config.md` (never hardcode colors — use CSS custom properties)
75
+ - Include responsive behavior if applicable
76
+ - Add comments explaining key layout decisions
77
+ - If the mockup uses workarounds for framework constraints, document them clearly in comments
78
+
79
+ **HTML mockup template:**
80
+ ```html
81
+ <!DOCTYPE html>
82
+ <html lang="en">
83
+ <head>
84
+ <meta charset="UTF-8">
85
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
86
+ <title>{Feature Name} — Mockup</title>
87
+ <style>
88
+ /* Brand colors from project-config.md */
89
+ :root {
90
+ --brand-primary: {<BRAND_PRIMARY>};
91
+ --brand-dark: {<BRAND_DARK>};
92
+ --brand-light: {<BRAND_LIGHT>};
93
+ /* Additional colors from profile */
94
+ }
95
+
96
+ /* Mockup styles */
97
+ /* ... */
98
+ </style>
99
+ </head>
100
+ <body>
101
+ <!-- MOCKUP: {Feature description} -->
102
+ <!-- FRAMEWORK: {Target framework} -->
103
+ <!-- CONSTRAINTS: {Any framework constraints that shaped this design} -->
104
+ <!-- ALTERNATIVES: {If using a workaround, what was the original approach and why it wouldn't work} -->
105
+
106
+ <!-- Mockup content -->
107
+ </body>
108
+ </html>
109
+ ```
110
+
111
+ ### Step 3b: Implementation-Annotated Mockup (MANDATORY for handoff to implementing agents)
112
+
113
+ When the mockup will be handed off to `@implement`, `@frontend-developer`, or `@streamlit-developer`, embed **implementation annotations** throughout the HTML so the implementing agent knows exactly what to build without guessing.
114
+
115
+ #### Annotation Types
116
+
117
+ Use these four comment patterns consistently:
118
+
119
+ **1. Component annotations** — Which framework component implements this visual element:
120
+ ```html
121
+ <!-- React: <KpiFlipCard product="broadband" data={surveys.broadband}
122
+ trendData={trend.historicalNPS.byProduct.broadband} /> -->
123
+ <!-- React: <ResponsiveContainer width="100%" height={260}>
124
+ <AreaChart data={trendData}><Area type="monotone" dataKey="nps" ... /></AreaChart>
125
+ </ResponsiveContainer> -->
126
+ <!-- React: import { ScoreChip, DeltaBadge, SparkBar, TrendDot } from '@/components/table-cells' -->
127
+ ```
128
+
129
+ **2. Data source annotations** — Which JSON key / API response field provides the data:
130
+ ```html
131
+ <!-- DATA-SOURCE: surveys.broadband.nps, surveys.broadband.responses -->
132
+ <!-- DATA-SOURCE: trend.historicalNPS.byProduct.broadband (array of monthly values) -->
133
+ <!-- DATA-SOURCE: ceoInsight.headline, ceoInsight.keyFindings[] (objects with title, detail) -->
134
+ ```
135
+
136
+ **3. Implementation notes** — Broader guidance for the implementing agent:
137
+ ```html
138
+ <!-- IMPLEMENTATION NOTE [DATA-SOURCE]: This section uses hardcoded mock values for
139
+ layout reference. React implementation must fetch period-filtered data from the
140
+ /api/nps/overview endpoint and compute all KPIs dynamically. -->
141
+ <!-- IMPLEMENTATION NOTE [CHART]: Use Recharts AreaChart with gradient fill.
142
+ Spread CHART_DEFAULTS from chartTheme.ts. No axes/grid for sparkline variant. -->
143
+ <!-- IMPLEMENTATION NOTE [ANIMATION]: Use framer-motion rotateY for card flip.
144
+ duration: 0.52, ease: [0.4, 0.2, 0.2, 1]. backfaceVisibility: "hidden". -->
145
+ ```
146
+
147
+ **4. Styling annotations** — Which design tokens, CSS vars, or Tailwind classes to use:
148
+ ```html
149
+ <!-- STYLE: bg-surface-card (var(--surface-card)), shadow-card, rounded-lg (var(--r-lg)) -->
150
+ <!-- STYLE: Fill color uses var(--status-red) for detractor, var(--status-green) for promoter -->
151
+ <!-- STYLE: Tailwind: text-ink-primary font-heading text-2xl font-bold -->
152
+ ```
153
+
154
+ #### Annotation Placement Rules
155
+
156
+ 1. Place **component annotations** directly above or inside the HTML element that the component replaces
157
+ 2. Place **data source annotations** on the element that displays the data value
158
+ 3. Place **implementation notes** at the top of each major section (tab, panel, card group)
159
+ 4. Place **styling annotations** on elements where the visual appearance matters and the token name isn't obvious from the CSS
160
+ 5. Every hardcoded value in the mockup (numbers, text, colors) that will be dynamic in production MUST have a data source annotation
161
+
162
+ #### Example: Annotated KPI Card
163
+
164
+ ```html
165
+ <!-- React: <KpiFlipCard product="broadband" data={surveys.broadband}
166
+ trendData={trend.historicalNPS.byProduct.broadband} color={COLORS.broadband} /> -->
167
+ <!-- DATA-SOURCE: surveys.broadband.nps (current score), surveys.broadband.responses (count) -->
168
+ <!-- STYLE: var(--surface-card) bg, var(--shadow-card) shadow, 3px left border using COLORS.broadband -->
169
+ <div class="kpi-card">
170
+ <div class="kpi-score">+32</div> <!-- DATA-SOURCE: surveys.broadband.nps -->
171
+ <div class="kpi-delta">▲ 2.1</div> <!-- DATA-SOURCE: deriveMom(trend.historicalNPS.byProduct.broadband) -->
172
+ <div class="kpi-responses">1,247 responses</div> <!-- DATA-SOURCE: surveys.broadband.responses -->
173
+ <div class="sparkline">
174
+ <!-- React: <Sparkline data={trend.historicalNPS.byProduct.broadband}
175
+ color={COLORS.broadband} height={72} /> -->
176
+ <!-- IMPLEMENTATION NOTE [CHART]: Recharts AreaChart, no axes/grid/tooltip,
177
+ gradient fill from color at opacity 0.3 to opacity 0. -->
178
+ </div>
179
+ </div>
180
+ ```
181
+
182
+ #### Completeness Check
183
+
184
+ Before saving the mockup, verify:
185
+ - [ ] Every visual section has at least one **component annotation**
186
+ - [ ] Every dynamic value has a **data source annotation** with the exact JSON path
187
+ - [ ] Every chart/graph has an **implementation note** specifying the chart library and config
188
+ - [ ] The implementing agent can build the feature using ONLY the mockup + annotations (no guessing)
189
+
190
+ ### Step 4: Write Artifact
191
+
192
+ 1. Save the mockup file to `agent-docs/ux/mockups/{feature-slug}.html` (or `.svg`)
193
+ 2. Add YAML header to a companion markdown file or embed as HTML comment:
194
+ ```yaml
195
+ agent: ux-designer
196
+ created: {date}
197
+ status: current
198
+ chain_id: {chain_id if provided}
199
+ approval: pending
200
+ framework: {target framework}
201
+ feasibility_warnings: {list any constraints encountered}
202
+ ```
203
+ 3. Update `agent-docs/ARTIFACTS.md` manifest with the new entry
204
+
205
+ ### Step 5: Report
206
+
207
+ Provide:
208
+ - Path to the mockup file
209
+ - Framework feasibility summary (what was checked, any warnings)
210
+ - Implementation notes for the agent that will build this (which API/component to use, what CSS approach works)
211
+ - If alternatives were chosen, explain why the original approach wouldn't work
212
+
213
+ ---
214
+
215
+ ## Framework Feasibility Quick Reference
216
+
217
+ ### Streamlit-Specific
218
+
219
+ | Want to do | Don't use | Instead use |
220
+ |-----------|-----------|-------------|
221
+ | Floating element (chat widget, FAB) | `position: fixed/absolute` | `declare_component()` with custom HTML/JS |
222
+ | Custom styled container | Global CSS | `st.container(key="name")` + `.st-key-name` selector |
223
+ | Modal/overlay | `z-index` + absolute positioning | `st.dialog()` (Streamlit 1.33+) or `st.modal()` |
224
+ | Sidebar content | Custom sidebar HTML | `st.sidebar` API |
225
+ | Custom header | Fixed position header | `st.container()` at top + CSS with `st.container(key=)` |
226
+ | External JavaScript | `<script src="cdn...">` | Bundle locally for air-gapped; use `components.html()` |
227
+
228
+ ### React-Specific
229
+
230
+ | Want to do | Watch out for | Recommended approach |
231
+ |-----------|---------------|---------------------|
232
+ | Direct DOM manipulation | React re-renders will overwrite | Use refs (`useRef`) or state-driven rendering |
233
+ | Global styles | May conflict with component styles | CSS Modules, styled-components, or Tailwind |
234
+ | Third-party widgets | jQuery plugins fight React | Find React-native alternatives or wrap in `useEffect` |
235
+
236
+ ---
237
+
238
+ ## Important Notes
239
+
240
+ - This skill is designed to be loaded by `@ux-designer` or `@frontend-developer` agents
241
+ - The framework constraint tables should be extended as new frameworks and gotchas are discovered
242
+ - Always check `project-config.md` for the deployment environment — air-gapped deployments restrict external dependencies
@@ -0,0 +1,243 @@
1
+ ---
2
+ name: particle-art
3
+ version: 1.0.0
4
+ description: Generate animated particle art React/Next.js components — zero dependencies, spring physics, CSS-variable theming, DPR-correct canvas, mouse interaction. Use when the user wants animated hero art, a living logo, a branded initial or monogram, a constellation background, or any "particles that form a shape". Triggers on "particle animation", "node network", "animated letter/logo/initials", "living letter", "morphing particles", "constellation", "neural net art", "dot field", "stipple portrait", "halftone animation", "ASCII art animation", "background art for my site", or "art that reacts to mouse". Covers — text/initials → spring-node letter; preset patterns (constellation, helix, spiral, DNA, hex-grid, wave, infinity); custom SVG paths; custom polygon points; Unicode halftone stipple; Gaussian dot field with sparks; SVG circuit traces; hybrid combos. Outputs a complete, self-contained, copy-paste-ready React component. Prefer this over p5.js (zero-dep, React-native, TypeScript), tsParticles (richer spring physics, CSS-var theming), Three.js (lightweight, no WebGL).
5
+ ---
6
+
7
+ # Particle Art Generator
8
+
9
+ Produces animated React components using one of four rendering styles, each themeable via CSS custom properties and interactive via mouse. Zero npm dependencies — pure canvas and SVG.
10
+
11
+ ## Reference Files (read when needed)
12
+
13
+ | File | Read when |
14
+ |------|-----------|
15
+ | `references/canvas-utils.ts` | Starting any canvas-based component (DPR setup, theme colours, RAF loop) |
16
+ | `references/shape-sampler.ts` | Building target points for any shape — text, presets, SVG path, polygon |
17
+ | `references/node-shape.template.tsx` | Generating a **spring-node** component (repel/attract interaction) |
18
+ | `references/stipple.template.tsx` | Generating a **stipple** (Unicode halftone, static cloud) component |
19
+ | `references/stipple-morph.template.tsx` | Generating a **stipple-morph** component (halftone cloud → letter on hover) |
20
+ | `references/dot-field.template.tsx` | Generating a **dot-field** component |
21
+ | `references/trail-ghost.template.tsx` | Generating a **trail-ghost** component (spring-morph + phosphorescent trails) |
22
+ | `references/flow-field.template.tsx` | Generating a **flow-field** component (value-noise currents + letter assembly) |
23
+ | `references/usage-examples.md` | Checking finished examples before delivering |
24
+
25
+ ---
26
+
27
+ ## Step 0 — Gather Requirements
28
+
29
+ Ask (or infer from context) these five things before writing any code:
30
+
31
+ 1. **Shape** — What should the particles form?
32
+ - Text / initials: `"j"`, `"JS"`, `"AI"`, `"hello"`, any Unicode char or emoji
33
+ - Preset: `constellation` `helix` `spiral` `dna` `hexgrid` `wave` `infinity`
34
+ - Custom: SVG `d` path string, or `[x,y]` polygon coordinate array
35
+ - Abstract: no fixed shape (ambient cloud)
36
+
37
+ 2. **Style** — Which rendering engine?
38
+ - `spring-nodes` — canvas nodes spring to shape + ambient network (best for letters/logos, repel interaction)
39
+ - `morph-nodes` — nodes scatter in idle, coalesce into letter/shape on hover (best for "appear on demand")
40
+ - `stipple` — animated Unicode character halftone static cloud (best for atmospheric dot portraits)
41
+ - `stipple-morph` — halftone cloud that resolves into a letter/shape on hover (best for atmospheric + interactive)
42
+ - `dot-field` — Gaussian canvas dot cloud with sparks (best for cosmic/diffuse feel)
43
+ - `trail-ghost` — spring-morph nodes with phosphorescent trailing smears (best for ethereal/ghostly feel)
44
+ - `flow-field` — value-noise particle currents, assembles into letter on hover (best for organic/fluid feel)
45
+ - `circuit` — SVG grid traces with traveling pulses (best for tech/infrastructure feel)
46
+ - `hybrid` — spring-nodes foreground + dot-field background (most dramatic)
47
+
48
+ 3. **Size** — `sm` (240px) · `md` (300px) · `lg` (380px) · `xl` (480px) · or a number
49
+
50
+ 4. **Colors** — `theme-vars` (default, CSS custom props) · `[primary, secondary]` hex pair · `monochrome`
51
+
52
+ 5. **Interaction** — `repel` (default) · `attract` · `orbit` · `none`
53
+
54
+ If the user hasn't stated a style, recommend `spring-nodes` for text/initials, `dot-field` for abstract, `stipple` for atmospheric, `circuit` for technical backgrounds.
55
+
56
+ ---
57
+
58
+ ## Step 1 — Select and Read Reference Files
59
+
60
+ Read the canvas-utils and the template that matches the chosen style. Always read canvas-utils first — it has the DPR setup and theme colour helpers used by all canvas components.
61
+
62
+ For shape types:
63
+ - **text / initials / preset / polygon / SVG path** → read `shape-sampler.ts` for the correct `sampleShape()` call
64
+ - **abstract** → skip shape-sampler; use ambient-only config in the node-shape template
65
+
66
+ ---
67
+
68
+ ## Step 2 — Build the Component
69
+
70
+ ### Naming Convention
71
+ ```
72
+ <Subject><Style>Art.tsx
73
+ // Examples:
74
+ JSpringArt.tsx // letter "j", spring-nodes
75
+ ConstellationArt.tsx // preset constellation
76
+ HeroNodeArt.tsx // abstract spring-nodes for a hero section
77
+ ```
78
+
79
+ ### File Structure
80
+ ```tsx
81
+ "use client";
82
+ // 1. Imports (React only — no external deps)
83
+ // 2. Constants (physics params, sizing)
84
+ // 3. Shape builder function (calls sampleShape or defines points inline)
85
+ // 4. Component (useEffect → canvas setup → RAF loop → cleanup)
86
+ // 5. Export
87
+ ```
88
+
89
+ ### Physics Parameters by Use-Case
90
+
91
+ | Use-case | spring | friction | drift | linkDist | ambientN |
92
+ |----------|--------|----------|-------|----------|----------|
93
+ | Single letter | 0.036 | 0.88 | 0.06 | 72 | 14 |
94
+ | Short word (2-4 chars) | 0.030 | 0.90 | 0.04 | 60 | 8 |
95
+ | Long word / phrase | 0.025 | 0.92 | 0.03 | 50 | 4 |
96
+ | Abstract / no shape | — | 0.985 | — | 82 | all |
97
+ | Constellation preset | 0.012 | 0.94 | 0.05 | 90 | 6 |
98
+
99
+ ### Node Count Guidelines
100
+
101
+ | Shape | Recommended node count |
102
+ |-------|----------------------|
103
+ | Single letter (j, A) | 22–30 letter + 14–18 ambient |
104
+ | Two letters (JS, AI) | 35–45 letter + 12 ambient |
105
+ | Word ≤6 chars | 50–70 letter + 8 ambient |
106
+ | Preset shape | 28–40 |
107
+ | Abstract cloud | 32–48 ambient only |
108
+
109
+ ---
110
+
111
+ ## Step 3 — Adapt for the Project's Theme System
112
+
113
+ ### CSS-Variable Theming (default, always prefer this)
114
+ ```ts
115
+ // Read in the RAF loop — auto-updates on theme change
116
+ function themeRgb(v: string): [number, number, number] {
117
+ const ch = getComputedStyle(document.documentElement)
118
+ .getPropertyValue(v).trim().split(/\s+/).map(Number);
119
+ return [ch[0], ch[1], ch[2]];
120
+ }
121
+ // Usage: themeRgb("--accent-strong") → [79, 209, 197]
122
+ ```
123
+
124
+ Standard variable names (work with Tailwind CSS-variable setups):
125
+ - `--accent-strong` — primary / brightest nodes, tittle glow
126
+ - `--accent-soft` — secondary / lines and ambient nodes
127
+ - `--fg` — foreground text colour (fallback for monochrome)
128
+ - `--bg` — background (for any fill-behind effects)
129
+
130
+ If the project uses different variable names, ask the user or check `globals.css`.
131
+
132
+ ### Hex / Custom Colors
133
+ ```ts
134
+ function hexToRgb(hex: string): [number, number, number] {
135
+ const n = parseInt(hex.replace('#',''), 16);
136
+ return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
137
+ }
138
+ // Hard-code in the RAF loop instead of reading CSS vars
139
+ ```
140
+
141
+ ---
142
+
143
+ ## Step 4 — Interaction Modes
144
+
145
+ ### Repel (default)
146
+ ```ts
147
+ const mdx = p.x - mx, mdy = p.y - my;
148
+ const md = Math.sqrt(mdx*mdx + mdy*mdy);
149
+ if (md < REPEL_R && md > 0) {
150
+ const f = ((REPEL_R - md) / REPEL_R) * REPEL_F;
151
+ p.vx += (mdx / md) * f;
152
+ p.vy += (mdy / md) * f;
153
+ }
154
+ ```
155
+
156
+ ### Attract
157
+ ```ts
158
+ // Same but subtract instead of add
159
+ p.vx -= (mdx / md) * f;
160
+ p.vy -= (mdy / md) * f;
161
+ ```
162
+
163
+ ### Orbit
164
+ ```ts
165
+ // Apply tangential force (perpendicular to cursor vector)
166
+ p.vx += (-mdy / md) * f * 0.6;
167
+ p.vy += ( mdx / md) * f * 0.6;
168
+ ```
169
+
170
+ ### Spring-back (always apply for letter nodes)
171
+ ```ts
172
+ p.vx += (p.tx - p.x) * SPRING;
173
+ p.vy += (p.ty - p.y) * SPRING;
174
+ p.vx *= FRICTION;
175
+ p.vy *= FRICTION;
176
+ ```
177
+
178
+ ---
179
+
180
+ ## Step 5 — Accessibility & Performance
181
+
182
+ Always include:
183
+ ```tsx
184
+ <canvas aria-hidden="true" /> // decorative, not content
185
+ ```
186
+
187
+ Reduced-motion support — draw a static frame then return; never return before drawing:
188
+ ```ts
189
+ const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
190
+ // ... build pts, set up canvas, build mouse listeners ...
191
+ if (reduced) {
192
+ // Snap shape nodes to their targets and draw one static frame
193
+ pts.forEach(p => { if (p.isShape) { p.x = p.tx; p.y = p.ty; } });
194
+ tick(); // draw once
195
+ cancelAnimationFrame(raf); // immediately cancel the RAF tick queued inside
196
+ return;
197
+ }
198
+ // Full animation loop starts here
199
+ ```
200
+ ⚠️ Never `return` before drawing for canvas components — that leaves the canvas blank, which is worse than any animation.
201
+
202
+ Performance rules:
203
+ - Read `getComputedStyle` **inside** the RAF loop (theme changes auto-apply, ~0.02ms/call)
204
+ - Use `devicePixelRatio` for crisp retina rendering (see canvas-utils)
205
+ - Clean up with `cancelAnimationFrame` and remove event listeners in the return callback
206
+ - Cap velocity: `if (spd > MAX_SPEED) { vx *= MAX_SPEED/spd; vy *= MAX_SPEED/spd; }`
207
+
208
+ ---
209
+
210
+ ## Step 6 — Deliver
211
+
212
+ Output the complete component file, then show the import + usage:
213
+
214
+ ```tsx
215
+ // Usage in any React/Next.js component:
216
+ import { MyArt } from "@/components/art/MyArt";
217
+
218
+ // In JSX:
219
+ <MyArt size={360} />
220
+
221
+ // For Next.js App Router pages — component already has "use client"
222
+ // For hero sections — wrap in a hidden-on-mobile div:
223
+ <div className="hidden lg:flex items-center justify-center">
224
+ <MyArt size={360} />
225
+ </div>
226
+ ```
227
+
228
+ ---
229
+
230
+ ## Quality Checklist
231
+
232
+ Before delivering, verify:
233
+ - [ ] `"use client"` at the top
234
+ - [ ] Canvas size set with `devicePixelRatio` scaling (from canvas-utils)
235
+ - [ ] `cancelAnimationFrame` + `removeEventListener` in useEffect cleanup
236
+ - [ ] `aria-hidden="true"` on the canvas/container
237
+ - [ ] `themeRgb()` reads CSS vars inside RAF loop (not outside)
238
+ - [ ] Mouse leaves handled (`mouseleave` resets to off-screen coords)
239
+ - [ ] Velocity capped to `MAX_SPEED`
240
+ - [ ] For letter nodes: spring force applied + damped FRICTION (not AMBIENT_FRICTION)
241
+ - [ ] TypeScript types — no `any`, interfaces for Pt/Dot/Spark
242
+ - [ ] Prefers-reduced-motion check
243
+ - [ ] Component is self-contained (no imports beyond React)
@@ -0,0 +1,171 @@
1
+ /**
2
+ * canvas-utils.ts — Shared canvas helpers for all particle-art components.
3
+ *
4
+ * Copy the functions you need directly into your component file.
5
+ * These are NOT meant to be imported as a module — they are reference implementations.
6
+ */
7
+
8
+ // ─── DPR-Correct Canvas Setup ────────────────────────────────────────────────
9
+ //
10
+ // Must be called in useEffect, AFTER the canvas ref is attached.
11
+ // Returns the 2D context; the canvas is scaled so all drawing coordinates
12
+ // are in CSS pixels (no need to multiply by dpr elsewhere).
13
+ //
14
+ // Usage:
15
+ // const ctx = setupCanvas(ref.current!, size);
16
+ //
17
+ export function setupCanvas(
18
+ el: HTMLCanvasElement,
19
+ size: number,
20
+ ): CanvasRenderingContext2D {
21
+ const ctx = el.getContext("2d")!;
22
+ const dpr = window.devicePixelRatio || 1;
23
+ el.width = size * dpr;
24
+ el.height = size * dpr;
25
+ ctx.scale(dpr, dpr);
26
+ return ctx;
27
+ }
28
+
29
+ // ─── Theme-Aware Colour Reading ───────────────────────────────────────────────
30
+ //
31
+ // Reads a CSS custom property (e.g. "--accent-strong") and returns [R, G, B].
32
+ // The value must be space-separated channels: "79 209 197".
33
+ // Call this INSIDE the RAF loop so theme changes (light/dark toggle) auto-apply.
34
+ //
35
+ // Standard variable names for projects using CSS-variable design tokens:
36
+ // "--accent-strong" → primary colour (brightest nodes, tittle glow)
37
+ // "--accent-soft" → secondary colour (lines, ambient nodes)
38
+ // "--fg" → foreground / text colour
39
+ // "--bg" → page background
40
+ //
41
+ export function themeRgb(varName: string): [number, number, number] {
42
+ const raw = getComputedStyle(document.documentElement)
43
+ .getPropertyValue(varName)
44
+ .trim()
45
+ .split(/\s+/)
46
+ .map(Number);
47
+ return [raw[0] ?? 100, raw[1] ?? 100, raw[2] ?? 100];
48
+ }
49
+
50
+ // Convenience: build a CSS rgba() string from a themeRgb result + alpha
51
+ export function rgba(
52
+ [r, g, b]: [number, number, number],
53
+ alpha: number,
54
+ ): string {
55
+ return `rgba(${r},${g},${b},${alpha.toFixed(3)})`;
56
+ }
57
+
58
+ // ─── Hex Colour Fallback ──────────────────────────────────────────────────────
59
+ //
60
+ // Use when the project does NOT have CSS custom properties.
61
+ // Pass hex strings in the component's props and convert once.
62
+ //
63
+ export function hexToRgb(hex: string): [number, number, number] {
64
+ const n = parseInt(hex.replace("#", ""), 16);
65
+ return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
66
+ }
67
+
68
+ // ─── Mouse Tracking ───────────────────────────────────────────────────────────
69
+ //
70
+ // Returns a ref-compatible object and attaches listeners to the canvas.
71
+ // The position is in CSS pixels (matches drawing coordinates).
72
+ // Returns a cleanup function — call it in the useEffect return.
73
+ //
74
+ // Usage:
75
+ // const mouse = { x: -9999, y: -9999 };
76
+ // const cleanupMouse = attachMouseTracking(el, mouse);
77
+ // return () => { cancelAnimationFrame(raf); cleanupMouse(); };
78
+ //
79
+ export function attachMouseTracking(
80
+ el: HTMLCanvasElement,
81
+ mouse: { x: number; y: number },
82
+ ): () => void {
83
+ const onMove = (e: MouseEvent) => {
84
+ const r = el.getBoundingClientRect();
85
+ mouse.x = e.clientX - r.left;
86
+ mouse.y = e.clientY - r.top;
87
+ };
88
+ const onLeave = () => {
89
+ mouse.x = -9999;
90
+ mouse.y = -9999;
91
+ };
92
+ el.addEventListener("mousemove", onMove);
93
+ el.addEventListener("mouseleave", onLeave);
94
+ return () => {
95
+ el.removeEventListener("mousemove", onMove);
96
+ el.removeEventListener("mouseleave", onLeave);
97
+ };
98
+ }
99
+
100
+ // ─── Velocity Cap ─────────────────────────────────────────────────────────────
101
+ //
102
+ // Prevents particles from flying off-screen after strong mouse interactions.
103
+ // Apply AFTER adding forces, BEFORE updating position.
104
+ //
105
+ export function capVelocity(
106
+ p: { vx: number; vy: number },
107
+ maxSpeed: number,
108
+ ): void {
109
+ const spd = Math.sqrt(p.vx * p.vx + p.vy * p.vy);
110
+ if (spd > maxSpeed) {
111
+ p.vx *= maxSpeed / spd;
112
+ p.vy *= maxSpeed / spd;
113
+ }
114
+ }
115
+
116
+ // ─── Reduced-Motion Guard ─────────────────────────────────────────────────────
117
+ //
118
+ // ⚠️ DO NOT use this as an early `return` before drawing — that leaves the
119
+ // canvas completely blank, which is WORSE than showing animation.
120
+ //
121
+ // Correct pattern for canvas components:
122
+ // draw one static frame (nodes at target positions), then skip the RAF loop.
123
+ //
124
+ // const reduced = prefersReducedMotion();
125
+ // // ... build pts, set up canvas ...
126
+ // if (reduced) {
127
+ // pts.forEach(p => { p.x = p.tx; p.y = p.ty; }); // snap to targets
128
+ // drawOneFrame(ctx, pts, size); // render static
129
+ // return; // no RAF
130
+ // }
131
+ // tick(); // full animation
132
+ //
133
+ // For HTML/stipple components the early return IS fine because HTML content
134
+ // is already visible in the DOM without JavaScript.
135
+ //
136
+ export function prefersReducedMotion(): boolean {
137
+ return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
138
+ }
139
+
140
+ // ─── Connection Lines ─────────────────────────────────────────────────────────
141
+ //
142
+ // Draw faded lines between all particle pairs within linkDist.
143
+ // Call this BEFORE drawing nodes so lines appear underneath.
144
+ //
145
+ // pts must have { x, y } properties.
146
+ //
147
+ export function drawConnections(
148
+ ctx: CanvasRenderingContext2D,
149
+ pts: { x: number; y: number }[],
150
+ linkDist: number,
151
+ lineColor: [number, number, number],
152
+ maxAlpha = 0.32,
153
+ ): void {
154
+ const [r, g, b] = lineColor;
155
+ for (let i = 0; i < pts.length; i++) {
156
+ for (let j = i + 1; j < pts.length; j++) {
157
+ const dx = pts[i].x - pts[j].x;
158
+ const dy = pts[i].y - pts[j].y;
159
+ const d = Math.sqrt(dx * dx + dy * dy);
160
+ if (d < linkDist) {
161
+ const a = (1 - d / linkDist) * maxAlpha;
162
+ ctx.beginPath();
163
+ ctx.moveTo(pts[i].x, pts[i].y);
164
+ ctx.lineTo(pts[j].x, pts[j].y);
165
+ ctx.strokeStyle = `rgba(${r},${g},${b},${a.toFixed(3)})`;
166
+ ctx.lineWidth = 0.65;
167
+ ctx.stroke();
168
+ }
169
+ }
170
+ }
171
+ }