niahere 0.2.61 → 0.2.63

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 (186) hide show
  1. package/defaults/memory-promoter.md +99 -0
  2. package/defaults/self/staging.md +48 -0
  3. package/package.json +7 -3
  4. package/skills/code-review/pr-review.md +14 -1
  5. package/skills/cro/page.md +22 -0
  6. package/skills/frontend-design/SKILL.md +7 -3
  7. package/skills/frontend-design/building.md +17 -2
  8. package/skills/qa/SKILL.md +108 -72
  9. package/skills/userinterface-wiki/AGENTS.md +3749 -0
  10. package/skills/userinterface-wiki/SKILL.md +253 -0
  11. package/skills/userinterface-wiki/metadata.json +26 -0
  12. package/skills/userinterface-wiki/rules/_sections.md +66 -0
  13. package/skills/userinterface-wiki/rules/_template.md +24 -0
  14. package/skills/userinterface-wiki/rules/a11y-reduced-motion-check.md +30 -0
  15. package/skills/userinterface-wiki/rules/a11y-toggle-setting.md +30 -0
  16. package/skills/userinterface-wiki/rules/a11y-visual-equivalent.md +36 -0
  17. package/skills/userinterface-wiki/rules/a11y-volume-control.md +28 -0
  18. package/skills/userinterface-wiki/rules/appropriate-confirmations-only.md +19 -0
  19. package/skills/userinterface-wiki/rules/appropriate-errors-warnings.md +18 -0
  20. package/skills/userinterface-wiki/rules/appropriate-no-decorative.md +21 -0
  21. package/skills/userinterface-wiki/rules/appropriate-no-high-frequency.md +28 -0
  22. package/skills/userinterface-wiki/rules/appropriate-no-punishing.md +27 -0
  23. package/skills/userinterface-wiki/rules/container-callback-ref.md +31 -0
  24. package/skills/userinterface-wiki/rules/container-guard-initial-zero.md +25 -0
  25. package/skills/userinterface-wiki/rules/container-no-excessive-use.md +13 -0
  26. package/skills/userinterface-wiki/rules/container-overflow-hidden.md +25 -0
  27. package/skills/userinterface-wiki/rules/container-transition-delay.md +21 -0
  28. package/skills/userinterface-wiki/rules/container-two-div-pattern.md +35 -0
  29. package/skills/userinterface-wiki/rules/container-use-resize-observer.md +48 -0
  30. package/skills/userinterface-wiki/rules/context-cleanup-nodes.md +25 -0
  31. package/skills/userinterface-wiki/rules/context-resume-suspended.md +28 -0
  32. package/skills/userinterface-wiki/rules/context-reuse-single.md +30 -0
  33. package/skills/userinterface-wiki/rules/design-filter-for-character.md +25 -0
  34. package/skills/userinterface-wiki/rules/design-noise-for-percussion.md +26 -0
  35. package/skills/userinterface-wiki/rules/design-oscillator-for-tonal.md +22 -0
  36. package/skills/userinterface-wiki/rules/duration-max-300ms.md +21 -0
  37. package/skills/userinterface-wiki/rules/duration-press-hover.md +21 -0
  38. package/skills/userinterface-wiki/rules/duration-shorten-before-curve.md +21 -0
  39. package/skills/userinterface-wiki/rules/duration-small-state.md +15 -0
  40. package/skills/userinterface-wiki/rules/easing-entrance-ease-out.md +21 -0
  41. package/skills/userinterface-wiki/rules/easing-exit-ease-in.md +21 -0
  42. package/skills/userinterface-wiki/rules/easing-for-state-change.md +27 -0
  43. package/skills/userinterface-wiki/rules/easing-linear-only-progress.md +21 -0
  44. package/skills/userinterface-wiki/rules/easing-natural-decay.md +22 -0
  45. package/skills/userinterface-wiki/rules/easing-no-linear-motion.md +22 -0
  46. package/skills/userinterface-wiki/rules/easing-transition-ease-in-out.md +15 -0
  47. package/skills/userinterface-wiki/rules/envelope-exponential-decay.md +21 -0
  48. package/skills/userinterface-wiki/rules/envelope-no-zero-target.md +21 -0
  49. package/skills/userinterface-wiki/rules/envelope-set-initial-value.md +22 -0
  50. package/skills/userinterface-wiki/rules/exit-key-required.md +29 -0
  51. package/skills/userinterface-wiki/rules/exit-matches-initial.md +29 -0
  52. package/skills/userinterface-wiki/rules/exit-prop-required.md +33 -0
  53. package/skills/userinterface-wiki/rules/exit-requires-wrapper.md +27 -0
  54. package/skills/userinterface-wiki/rules/impl-default-subtle.md +21 -0
  55. package/skills/userinterface-wiki/rules/impl-preload-audio.md +34 -0
  56. package/skills/userinterface-wiki/rules/impl-reset-current-time.md +26 -0
  57. package/skills/userinterface-wiki/rules/mode-pop-layout-for-lists.md +25 -0
  58. package/skills/userinterface-wiki/rules/mode-sync-layout-conflict.md +29 -0
  59. package/skills/userinterface-wiki/rules/mode-wait-doubles-duration.md +25 -0
  60. package/skills/userinterface-wiki/rules/morphing-aria-hidden.md +21 -0
  61. package/skills/userinterface-wiki/rules/morphing-consistent-viewbox.md +23 -0
  62. package/skills/userinterface-wiki/rules/morphing-group-variants.md +33 -0
  63. package/skills/userinterface-wiki/rules/morphing-jump-non-grouped.md +29 -0
  64. package/skills/userinterface-wiki/rules/morphing-reduced-motion.md +28 -0
  65. package/skills/userinterface-wiki/rules/morphing-spring-rotation.md +23 -0
  66. package/skills/userinterface-wiki/rules/morphing-strokelinecap-round.md +21 -0
  67. package/skills/userinterface-wiki/rules/morphing-three-lines.md +32 -0
  68. package/skills/userinterface-wiki/rules/morphing-use-collapsed.md +33 -0
  69. package/skills/userinterface-wiki/rules/native-backdrop-styling.md +27 -0
  70. package/skills/userinterface-wiki/rules/native-placeholder-styling.md +27 -0
  71. package/skills/userinterface-wiki/rules/native-selection-styling.md +18 -0
  72. package/skills/userinterface-wiki/rules/nested-consistent-timing.md +25 -0
  73. package/skills/userinterface-wiki/rules/nested-propagate-required.md +41 -0
  74. package/skills/userinterface-wiki/rules/none-context-menu-entrance.md +25 -0
  75. package/skills/userinterface-wiki/rules/none-high-frequency.md +29 -0
  76. package/skills/userinterface-wiki/rules/none-keyboard-navigation.md +32 -0
  77. package/skills/userinterface-wiki/rules/param-click-duration.md +21 -0
  78. package/skills/userinterface-wiki/rules/param-filter-frequency-range.md +21 -0
  79. package/skills/userinterface-wiki/rules/param-q-value-range.md +21 -0
  80. package/skills/userinterface-wiki/rules/param-reasonable-gain.md +21 -0
  81. package/skills/userinterface-wiki/rules/physics-active-state.md +23 -0
  82. package/skills/userinterface-wiki/rules/physics-no-excessive-stagger.md +22 -0
  83. package/skills/userinterface-wiki/rules/physics-spring-for-overshoot.md +23 -0
  84. package/skills/userinterface-wiki/rules/physics-subtle-deformation.md +22 -0
  85. package/skills/userinterface-wiki/rules/prefetch-hit-slop.md +27 -0
  86. package/skills/userinterface-wiki/rules/prefetch-keyboard-tab.md +19 -0
  87. package/skills/userinterface-wiki/rules/prefetch-not-everything.md +22 -0
  88. package/skills/userinterface-wiki/rules/prefetch-touch-fallback.md +34 -0
  89. package/skills/userinterface-wiki/rules/prefetch-trajectory-over-hover.md +32 -0
  90. package/skills/userinterface-wiki/rules/prefetch-use-selectively.md +13 -0
  91. package/skills/userinterface-wiki/rules/presence-disable-interactions.md +31 -0
  92. package/skills/userinterface-wiki/rules/presence-hook-in-child.md +31 -0
  93. package/skills/userinterface-wiki/rules/presence-safe-to-remove.md +37 -0
  94. package/skills/userinterface-wiki/rules/pseudo-content-required.md +28 -0
  95. package/skills/userinterface-wiki/rules/pseudo-first-line-styling.md +27 -0
  96. package/skills/userinterface-wiki/rules/pseudo-hit-target-expansion.md +31 -0
  97. package/skills/userinterface-wiki/rules/pseudo-marker-styling.md +28 -0
  98. package/skills/userinterface-wiki/rules/pseudo-over-dom-node.md +32 -0
  99. package/skills/userinterface-wiki/rules/pseudo-position-relative-parent.md +33 -0
  100. package/skills/userinterface-wiki/rules/pseudo-z-index-layering.md +37 -0
  101. package/skills/userinterface-wiki/rules/spring-for-gestures.md +27 -0
  102. package/skills/userinterface-wiki/rules/spring-for-interruptible.md +27 -0
  103. package/skills/userinterface-wiki/rules/spring-params-balanced.md +29 -0
  104. package/skills/userinterface-wiki/rules/spring-preserves-velocity.md +28 -0
  105. package/skills/userinterface-wiki/rules/staging-dim-background.md +22 -0
  106. package/skills/userinterface-wiki/rules/staging-one-focal-point.md +24 -0
  107. package/skills/userinterface-wiki/rules/staging-z-index-hierarchy.md +22 -0
  108. package/skills/userinterface-wiki/rules/timing-consistent.md +24 -0
  109. package/skills/userinterface-wiki/rules/timing-no-entrance-context-menu.md +22 -0
  110. package/skills/userinterface-wiki/rules/timing-under-300ms.md +22 -0
  111. package/skills/userinterface-wiki/rules/transition-name-cleanup.md +28 -0
  112. package/skills/userinterface-wiki/rules/transition-name-required.md +27 -0
  113. package/skills/userinterface-wiki/rules/transition-name-unique.md +24 -0
  114. package/skills/userinterface-wiki/rules/transition-over-js-library.md +32 -0
  115. package/skills/userinterface-wiki/rules/transition-style-pseudo-elements.md +24 -0
  116. package/skills/userinterface-wiki/rules/type-antialiased-on-retina.md +18 -0
  117. package/skills/userinterface-wiki/rules/type-disambiguation-stylistic-set.md +15 -0
  118. package/skills/userinterface-wiki/rules/type-font-display-swap.md +28 -0
  119. package/skills/userinterface-wiki/rules/type-justify-with-hyphens.md +24 -0
  120. package/skills/userinterface-wiki/rules/type-letter-spacing-uppercase.md +28 -0
  121. package/skills/userinterface-wiki/rules/type-no-font-synthesis.md +18 -0
  122. package/skills/userinterface-wiki/rules/type-oldstyle-nums-for-prose.md +21 -0
  123. package/skills/userinterface-wiki/rules/type-opentype-contextual-alternates.md +15 -0
  124. package/skills/userinterface-wiki/rules/type-optical-sizing-auto.md +25 -0
  125. package/skills/userinterface-wiki/rules/type-proper-fractions.md +15 -0
  126. package/skills/userinterface-wiki/rules/type-slashed-zero.md +17 -0
  127. package/skills/userinterface-wiki/rules/type-tabular-nums-for-data.md +21 -0
  128. package/skills/userinterface-wiki/rules/type-text-wrap-balance-headings.md +21 -0
  129. package/skills/userinterface-wiki/rules/type-text-wrap-pretty.md +16 -0
  130. package/skills/userinterface-wiki/rules/type-underline-offset.md +25 -0
  131. package/skills/userinterface-wiki/rules/type-variable-weight-continuous.md +23 -0
  132. package/skills/userinterface-wiki/rules/ux-aesthetic-usability.md +32 -0
  133. package/skills/userinterface-wiki/rules/ux-cognitive-load-reduce.md +49 -0
  134. package/skills/userinterface-wiki/rules/ux-common-region-boundaries.md +50 -0
  135. package/skills/userinterface-wiki/rules/ux-doherty-perceived-speed.md +29 -0
  136. package/skills/userinterface-wiki/rules/ux-doherty-under-400ms.md +30 -0
  137. package/skills/userinterface-wiki/rules/ux-fitts-hit-area.md +32 -0
  138. package/skills/userinterface-wiki/rules/ux-fitts-target-size.md +31 -0
  139. package/skills/userinterface-wiki/rules/ux-goal-gradient-progress.md +33 -0
  140. package/skills/userinterface-wiki/rules/ux-hicks-minimize-choices.md +45 -0
  141. package/skills/userinterface-wiki/rules/ux-jakobs-familiar-patterns.md +37 -0
  142. package/skills/userinterface-wiki/rules/ux-millers-chunking.md +23 -0
  143. package/skills/userinterface-wiki/rules/ux-pareto-prioritize-features.md +36 -0
  144. package/skills/userinterface-wiki/rules/ux-peak-end-finish-strong.md +35 -0
  145. package/skills/userinterface-wiki/rules/ux-postels-accept-messy-input.md +45 -0
  146. package/skills/userinterface-wiki/rules/ux-pragnanz-simplify.md +33 -0
  147. package/skills/userinterface-wiki/rules/ux-progressive-disclosure.md +41 -0
  148. package/skills/userinterface-wiki/rules/ux-proximity-grouping.md +38 -0
  149. package/skills/userinterface-wiki/rules/ux-serial-position.md +31 -0
  150. package/skills/userinterface-wiki/rules/ux-similarity-consistency.md +35 -0
  151. package/skills/userinterface-wiki/rules/ux-teslers-complexity.md +28 -0
  152. package/skills/userinterface-wiki/rules/ux-uniform-connectedness.md +43 -0
  153. package/skills/userinterface-wiki/rules/ux-von-restorff-emphasis.md +29 -0
  154. package/skills/userinterface-wiki/rules/ux-zeigarnik-show-incomplete.md +36 -0
  155. package/skills/userinterface-wiki/rules/visual-animate-shadow-pseudo.md +49 -0
  156. package/skills/userinterface-wiki/rules/visual-border-alpha-colors.md +25 -0
  157. package/skills/userinterface-wiki/rules/visual-button-shadow-anatomy.md +49 -0
  158. package/skills/userinterface-wiki/rules/visual-concentric-radius.md +40 -0
  159. package/skills/userinterface-wiki/rules/visual-consistent-spacing-scale.md +35 -0
  160. package/skills/userinterface-wiki/rules/visual-layered-shadows.md +30 -0
  161. package/skills/userinterface-wiki/rules/visual-no-pure-black-shadow.md +25 -0
  162. package/skills/userinterface-wiki/rules/visual-shadow-direction.md +25 -0
  163. package/skills/userinterface-wiki/rules/visual-shadow-matches-elevation.md +23 -0
  164. package/skills/userinterface-wiki/rules/weight-duration-matches-action.md +29 -0
  165. package/skills/userinterface-wiki/rules/weight-match-action.md +32 -0
  166. package/src/cli/index.ts +23 -73
  167. package/src/cli/job.ts +25 -92
  168. package/src/cli/status.ts +17 -9
  169. package/src/commands/init.ts +1 -0
  170. package/src/commands/validate.ts +12 -10
  171. package/src/core/agents.ts +6 -19
  172. package/src/core/consolidator.ts +97 -91
  173. package/src/core/daemon.ts +71 -43
  174. package/src/core/finalizer.ts +31 -3
  175. package/src/core/health.ts +5 -17
  176. package/src/core/runner.ts +8 -44
  177. package/src/core/scheduler.ts +12 -49
  178. package/src/core/skills.ts +4 -11
  179. package/src/core/summarizer.ts +7 -21
  180. package/src/db/connection.ts +0 -11
  181. package/src/db/models/job.ts +23 -22
  182. package/src/db/with-db.ts +11 -0
  183. package/src/mcp/server.ts +1 -1
  184. package/src/prompts/environment.md +44 -41
  185. package/src/utils/pid.ts +44 -0
  186. package/src/utils/schedule.ts +39 -0
@@ -0,0 +1,33 @@
1
+ ---
2
+ title: Exit Prop Required Inside AnimatePresence
3
+ impact: HIGH
4
+ tags: exit, prop, animate-presence
5
+ ---
6
+
7
+ ## Exit Prop Required Inside AnimatePresence
8
+
9
+ Elements inside AnimatePresence should have exit prop defined.
10
+
11
+ **Incorrect (missing exit):**
12
+
13
+ ```tsx
14
+ <AnimatePresence>
15
+ {isOpen && (
16
+ <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} />
17
+ )}
18
+ </AnimatePresence>
19
+ ```
20
+
21
+ **Correct (exit defined):**
22
+
23
+ ```tsx
24
+ <AnimatePresence>
25
+ {isOpen && (
26
+ <motion.div
27
+ initial={{ opacity: 0 }}
28
+ animate={{ opacity: 1 }}
29
+ exit={{ opacity: 0 }}
30
+ />
31
+ )}
32
+ </AnimatePresence>
33
+ ```
@@ -0,0 +1,27 @@
1
+ ---
2
+ title: AnimatePresence Wrapper Required
3
+ impact: HIGH
4
+ tags: exit, animate-presence, wrapper
5
+ ---
6
+
7
+ ## AnimatePresence Wrapper Required
8
+
9
+ Conditional motion elements must be wrapped in AnimatePresence.
10
+
11
+ **Incorrect (no wrapper):**
12
+
13
+ ```tsx
14
+ {isVisible && (
15
+ <motion.div exit={{ opacity: 0 }} />
16
+ )}
17
+ ```
18
+
19
+ **Correct (wrapped):**
20
+
21
+ ```tsx
22
+ <AnimatePresence>
23
+ {isVisible && (
24
+ <motion.div exit={{ opacity: 0 }} />
25
+ )}
26
+ </AnimatePresence>
27
+ ```
@@ -0,0 +1,21 @@
1
+ ---
2
+ title: Subtle Default Volume
3
+ impact: MEDIUM
4
+ tags: impl, volume, default
5
+ ---
6
+
7
+ ## Subtle Default Volume
8
+
9
+ Default volume should be subtle, not loud.
10
+
11
+ **Incorrect (too loud):**
12
+
13
+ ```tsx
14
+ const DEFAULT_VOLUME = 1.0;
15
+ ```
16
+
17
+ **Correct (subtle):**
18
+
19
+ ```tsx
20
+ const DEFAULT_VOLUME = 0.3;
21
+ ```
@@ -0,0 +1,34 @@
1
+ ---
2
+ title: Preload Audio Files
3
+ impact: MEDIUM
4
+ tags: impl, preload, performance
5
+ ---
6
+
7
+ ## Preload Audio Files
8
+
9
+ Preload audio files to avoid playback delay.
10
+
11
+ **Incorrect (loads on demand):**
12
+
13
+ ```tsx
14
+ function playSound(name: string) {
15
+ const audio = new Audio(`/sounds/${name}.mp3`);
16
+ audio.play();
17
+ }
18
+ ```
19
+
20
+ **Correct (preloaded):**
21
+
22
+ ```tsx
23
+ const sounds = {
24
+ success: new Audio("/sounds/success.mp3"),
25
+ error: new Audio("/sounds/error.mp3"),
26
+ };
27
+
28
+ Object.values(sounds).forEach(audio => audio.load());
29
+
30
+ function playSound(name: keyof typeof sounds) {
31
+ sounds[name].currentTime = 0;
32
+ sounds[name].play();
33
+ }
34
+ ```
@@ -0,0 +1,26 @@
1
+ ---
2
+ title: Reset currentTime Before Replay
3
+ impact: MEDIUM
4
+ tags: impl, replay, current-time
5
+ ---
6
+
7
+ ## Reset currentTime Before Replay
8
+
9
+ Reset audio currentTime before replay to allow rapid triggering.
10
+
11
+ **Incorrect (won't replay if playing):**
12
+
13
+ ```tsx
14
+ function playSound() {
15
+ audio.play();
16
+ }
17
+ ```
18
+
19
+ **Correct (reset before play):**
20
+
21
+ ```tsx
22
+ function playSound() {
23
+ audio.currentTime = 0;
24
+ audio.play();
25
+ }
26
+ ```
@@ -0,0 +1,25 @@
1
+ ---
2
+ title: popLayout for List Reordering
3
+ impact: MEDIUM
4
+ tags: mode, pop-layout, list
5
+ ---
6
+
7
+ ## popLayout for List Reordering
8
+
9
+ Use popLayout mode for list reordering animations.
10
+
11
+ **Incorrect (default mode causes shifts):**
12
+
13
+ ```tsx
14
+ <AnimatePresence>
15
+ {items.map(item => <ListItem key={item.id} />)}
16
+ </AnimatePresence>
17
+ ```
18
+
19
+ **Correct (popLayout prevents shifts):**
20
+
21
+ ```tsx
22
+ <AnimatePresence mode="popLayout">
23
+ {items.map(item => <ListItem key={item.id} />)}
24
+ </AnimatePresence>
25
+ ```
@@ -0,0 +1,29 @@
1
+ ---
2
+ title: Mode "sync" Causes Layout Conflicts
3
+ impact: MEDIUM
4
+ tags: mode, sync, layout
5
+ ---
6
+
7
+ ## Mode "sync" Causes Layout Conflicts
8
+
9
+ Mode "sync" causes layout conflicts; position exiting elements absolutely.
10
+
11
+ **Incorrect (sync with layout competition):**
12
+
13
+ ```tsx
14
+ <AnimatePresence mode="sync">
15
+ {items.map(item => (
16
+ <motion.div exit={{ opacity: 0 }}>{item}</motion.div>
17
+ ))}
18
+ </AnimatePresence>
19
+ ```
20
+
21
+ **Correct (popLayout instead):**
22
+
23
+ ```tsx
24
+ <AnimatePresence mode="popLayout">
25
+ {items.map(item => (
26
+ <motion.div exit={{ opacity: 0 }}>{item}</motion.div>
27
+ ))}
28
+ </AnimatePresence>
29
+ ```
@@ -0,0 +1,25 @@
1
+ ---
2
+ title: Mode "wait" Doubles Duration
3
+ impact: MEDIUM
4
+ tags: mode, wait, duration
5
+ ---
6
+
7
+ ## Mode "wait" Doubles Duration
8
+
9
+ Mode "wait" nearly doubles animation duration; adjust timing accordingly.
10
+
11
+ **Incorrect (too slow with wait):**
12
+
13
+ ```tsx
14
+ <AnimatePresence mode="wait">
15
+ <motion.div transition={{ duration: 0.3 }} />
16
+ </AnimatePresence>
17
+ ```
18
+
19
+ **Correct (halved timing):**
20
+
21
+ ```tsx
22
+ <AnimatePresence mode="wait">
23
+ <motion.div transition={{ duration: 0.15 }} />
24
+ </AnimatePresence>
25
+ ```
@@ -0,0 +1,21 @@
1
+ ---
2
+ title: Aria Hidden on Icon SVGs
3
+ impact: LOW
4
+ tags: morphing, a11y, aria
5
+ ---
6
+
7
+ ## Aria Hidden on Icon SVGs
8
+
9
+ Icon SVGs should be aria-hidden since they're decorative.
10
+
11
+ **Incorrect (no aria attribute):**
12
+
13
+ ```tsx
14
+ <svg width={size} height={size}>...</svg>
15
+ ```
16
+
17
+ **Correct (aria-hidden):**
18
+
19
+ ```tsx
20
+ <svg width={size} height={size} aria-hidden="true">...</svg>
21
+ ```
@@ -0,0 +1,23 @@
1
+ ---
2
+ title: Consistent ViewBox Size
3
+ impact: HIGH
4
+ tags: morphing, viewbox, svg
5
+ ---
6
+
7
+ ## Consistent ViewBox Size
8
+
9
+ All icons must use the same viewBox (14x14 recommended).
10
+
11
+ **Incorrect (mixed scales):**
12
+
13
+ ```ts
14
+ const icon1 = { lines: [{ x1: 2, y1: 7, x2: 12, y2: 7 }, ...] }; // 14x14
15
+ const icon2 = { lines: [{ x1: 4, y1: 14, x2: 24, y2: 14 }, ...] }; // 28x28
16
+ ```
17
+
18
+ **Correct (consistent scale):**
19
+
20
+ ```ts
21
+ const VIEWBOX_SIZE = 14;
22
+ const CENTER = 7;
23
+ ```
@@ -0,0 +1,33 @@
1
+ ---
2
+ title: Shared Group for Rotational Variants
3
+ impact: HIGH
4
+ tags: morphing, group, rotation
5
+ ---
6
+
7
+ ## Shared Group for Rotational Variants
8
+
9
+ Icons that are rotational variants MUST share the same group and base lines.
10
+
11
+ **Incorrect (different line definitions):**
12
+
13
+ ```ts
14
+ const arrowRight = { lines: [{ x1: 2, y1: 7, x2: 12, y2: 7 }, ...] };
15
+ const arrowDown = { lines: [{ x1: 7, y1: 2, x2: 7, y2: 12 }, ...] };
16
+ ```
17
+
18
+ **Correct (shared base lines):**
19
+
20
+ ```ts
21
+ const arrowLines: [IconLine, IconLine, IconLine] = [
22
+ { x1: 2, y1: 7, x2: 12, y2: 7 },
23
+ { x1: 7.5, y1: 2.5, x2: 12, y2: 7 },
24
+ { x1: 7.5, y1: 11.5, x2: 12, y2: 7 },
25
+ ];
26
+
27
+ const icons = {
28
+ "arrow-right": { lines: arrowLines, rotation: 0, group: "arrow" },
29
+ "arrow-down": { lines: arrowLines, rotation: 90, group: "arrow" },
30
+ "arrow-left": { lines: arrowLines, rotation: 180, group: "arrow" },
31
+ "arrow-up": { lines: arrowLines, rotation: -90, group: "arrow" },
32
+ };
33
+ ```
@@ -0,0 +1,29 @@
1
+ ---
2
+ title: Instant Jump for Non-Grouped Icons
3
+ impact: MEDIUM
4
+ tags: morphing, jump, group
5
+ ---
6
+
7
+ ## Instant Jump for Non-Grouped Icons
8
+
9
+ When transitioning between icons NOT in the same group, rotation should jump instantly.
10
+
11
+ **Incorrect (always animates rotation):**
12
+
13
+ ```tsx
14
+ useEffect(() => {
15
+ rotation.set(definition.rotation ?? 0);
16
+ }, [definition]);
17
+ ```
18
+
19
+ **Correct (jumps when not grouped):**
20
+
21
+ ```tsx
22
+ useEffect(() => {
23
+ if (shouldRotate) {
24
+ rotation.set(definition.rotation ?? 0);
25
+ } else {
26
+ rotation.jump(definition.rotation ?? 0);
27
+ }
28
+ }, [definition, shouldRotate]);
29
+ ```
@@ -0,0 +1,28 @@
1
+ ---
2
+ title: Reduced Motion Support for Icons
3
+ impact: MEDIUM
4
+ tags: morphing, a11y, reduced-motion
5
+ ---
6
+
7
+ ## Reduced Motion Support for Icons
8
+
9
+ Respect prefers-reduced-motion by disabling animations.
10
+
11
+ **Incorrect (always animates):**
12
+
13
+ ```tsx
14
+ function MorphingIcon({ icon }: Props) {
15
+ return <motion.line animate={...} transition={{ duration: 0.4 }} />;
16
+ }
17
+ ```
18
+
19
+ **Correct (respects preference):**
20
+
21
+ ```tsx
22
+ function MorphingIcon({ icon }: Props) {
23
+ const reducedMotion = useReducedMotion() ?? false;
24
+ const activeTransition = reducedMotion ? { duration: 0 } : transition;
25
+
26
+ return <motion.line animate={...} transition={activeTransition} />;
27
+ }
28
+ ```
@@ -0,0 +1,23 @@
1
+ ---
2
+ title: Spring Physics for Rotation
3
+ impact: MEDIUM
4
+ tags: morphing, spring, rotation
5
+ ---
6
+
7
+ ## Spring Physics for Rotation
8
+
9
+ Rotation between grouped icons should use spring physics for natural motion.
10
+
11
+ **Incorrect (duration-based rotation):**
12
+
13
+ ```tsx
14
+ <motion.g animate={{ rotate: rotation }} transition={{ duration: 0.3 }} />
15
+ ```
16
+
17
+ **Correct (spring rotation):**
18
+
19
+ ```tsx
20
+ const rotation = useSpring(definition.rotation ?? 0, activeTransition);
21
+
22
+ <motion.g style={{ rotate: rotation, transformOrigin: "center" }} />
23
+ ```
@@ -0,0 +1,21 @@
1
+ ---
2
+ title: Round Stroke Line Caps
3
+ impact: LOW
4
+ tags: morphing, stroke, svg
5
+ ---
6
+
7
+ ## Round Stroke Line Caps
8
+
9
+ Lines should use strokeLinecap="round" for polished endpoints.
10
+
11
+ **Incorrect (butt caps):**
12
+
13
+ ```tsx
14
+ <motion.line strokeLinecap="butt" />
15
+ ```
16
+
17
+ **Correct (round caps):**
18
+
19
+ ```tsx
20
+ <motion.line strokeLinecap="round" />
21
+ ```
@@ -0,0 +1,32 @@
1
+ ---
2
+ title: Icons Must Use Exactly Three Lines
3
+ impact: HIGH
4
+ tags: morphing, svg, structure
5
+ ---
6
+
7
+ ## Icons Must Use Exactly Three Lines
8
+
9
+ Every icon MUST use exactly 3 lines. No more, no fewer.
10
+
11
+ **Incorrect (only 2 lines):**
12
+
13
+ ```ts
14
+ const checkIcon = {
15
+ lines: [
16
+ { x1: 2, y1: 7.5, x2: 5.5, y2: 11 },
17
+ { x1: 5.5, y1: 11, x2: 12, y2: 3 },
18
+ ],
19
+ };
20
+ ```
21
+
22
+ **Correct (3 lines with collapsed):**
23
+
24
+ ```ts
25
+ const checkIcon = {
26
+ lines: [
27
+ { x1: 2, y1: 7.5, x2: 5.5, y2: 11 },
28
+ { x1: 5.5, y1: 11, x2: 12, y2: 3 },
29
+ collapsed,
30
+ ],
31
+ };
32
+ ```
@@ -0,0 +1,33 @@
1
+ ---
2
+ title: Use Collapsed Constant for Unused Lines
3
+ impact: HIGH
4
+ tags: morphing, collapsed, structure
5
+ ---
6
+
7
+ ## Use Collapsed Constant for Unused Lines
8
+
9
+ Unused lines must use the collapsed constant, not omission or null.
10
+
11
+ **Incorrect (null for unused):**
12
+
13
+ ```ts
14
+ const minusIcon = {
15
+ lines: [
16
+ { x1: 2, y1: 7, x2: 12, y2: 7 },
17
+ null,
18
+ null,
19
+ ],
20
+ };
21
+ ```
22
+
23
+ **Correct (collapsed constant):**
24
+
25
+ ```ts
26
+ const minusIcon = {
27
+ lines: [
28
+ { x1: 2, y1: 7, x2: 12, y2: 7 },
29
+ collapsed,
30
+ collapsed,
31
+ ],
32
+ };
33
+ ```
@@ -0,0 +1,27 @@
1
+ ---
2
+ title: Use ::backdrop for Dialog Backgrounds
3
+ impact: MEDIUM
4
+ tags: native, backdrop, dialog
5
+ ---
6
+
7
+ ## Use ::backdrop for Dialog Backgrounds
8
+
9
+ Use ::backdrop pseudo-element for dialog/popover backgrounds.
10
+
11
+ **Incorrect (extra overlay node):**
12
+
13
+ ```tsx
14
+ <>
15
+ <div className={styles.overlay} onClick={close} />
16
+ <dialog className={styles.dialog}>{children}</dialog>
17
+ </>
18
+ ```
19
+
20
+ **Correct (native ::backdrop):**
21
+
22
+ ```css
23
+ dialog::backdrop {
24
+ background: var(--black-a6);
25
+ backdrop-filter: blur(4px);
26
+ }
27
+ ```
@@ -0,0 +1,27 @@
1
+ ---
2
+ title: Use ::placeholder for Input Styling
3
+ impact: LOW
4
+ tags: native, placeholder, input
5
+ ---
6
+
7
+ ## Use ::placeholder for Input Styling
8
+
9
+ Use ::placeholder for input placeholder styling, not wrapper elements.
10
+
11
+ **Incorrect (custom placeholder node):**
12
+
13
+ ```tsx
14
+ <div className={styles.inputWrapper}>
15
+ {!value && <span className={styles.placeholder}>Enter text...</span>}
16
+ <input value={value} />
17
+ </div>
18
+ ```
19
+
20
+ **Correct (native ::placeholder):**
21
+
22
+ ```css
23
+ input::placeholder {
24
+ color: var(--gray-9);
25
+ opacity: 1;
26
+ }
27
+ ```
@@ -0,0 +1,18 @@
1
+ ---
2
+ title: Use ::selection for Text Styling
3
+ impact: LOW
4
+ tags: native, selection, text
5
+ ---
6
+
7
+ ## Use ::selection for Text Styling
8
+
9
+ Use ::selection for text selection styling.
10
+
11
+ **Correct:**
12
+
13
+ ```css
14
+ ::selection {
15
+ background: var(--blue-a5);
16
+ color: var(--gray-12);
17
+ }
18
+ ```
@@ -0,0 +1,25 @@
1
+ ---
2
+ title: Coordinated Parent-Child Exit Timing
3
+ impact: MEDIUM
4
+ tags: nested, timing, exit
5
+ ---
6
+
7
+ ## Coordinated Parent-Child Exit Timing
8
+
9
+ Parent and child exit durations should be coordinated.
10
+
11
+ **Incorrect (parent too fast):**
12
+
13
+ ```tsx
14
+ <motion.div exit={{ opacity: 0 }} transition={{ duration: 0.1 }}>
15
+ <motion.div exit={{ scale: 0 }} transition={{ duration: 0.5 }} />
16
+ </motion.div>
17
+ ```
18
+
19
+ **Correct (coordinated timing):**
20
+
21
+ ```tsx
22
+ <motion.div exit={{ opacity: 0 }} transition={{ duration: 0.2 }}>
23
+ <motion.div exit={{ scale: 0 }} transition={{ duration: 0.15 }} />
24
+ </motion.div>
25
+ ```
@@ -0,0 +1,41 @@
1
+ ---
2
+ title: Propagate Prop for Nested AnimatePresence
3
+ impact: HIGH
4
+ tags: nested, propagate, exit
5
+ ---
6
+
7
+ ## Propagate Prop for Nested AnimatePresence
8
+
9
+ Nested AnimatePresence must use propagate prop for coordinated exits.
10
+
11
+ **Incorrect (children vanish instantly):**
12
+
13
+ ```tsx
14
+ <AnimatePresence>
15
+ {isOpen && (
16
+ <motion.div exit={{ opacity: 0 }}>
17
+ <AnimatePresence>
18
+ {items.map(item => (
19
+ <motion.div key={item.id} exit={{ scale: 0 }} />
20
+ ))}
21
+ </AnimatePresence>
22
+ </motion.div>
23
+ )}
24
+ </AnimatePresence>
25
+ ```
26
+
27
+ **Correct (propagate on both):**
28
+
29
+ ```tsx
30
+ <AnimatePresence propagate>
31
+ {isOpen && (
32
+ <motion.div exit={{ opacity: 0 }}>
33
+ <AnimatePresence propagate>
34
+ {items.map(item => (
35
+ <motion.div key={item.id} exit={{ scale: 0 }} />
36
+ ))}
37
+ </AnimatePresence>
38
+ </motion.div>
39
+ )}
40
+ </AnimatePresence>
41
+ ```
@@ -0,0 +1,25 @@
1
+ ---
2
+ title: No Entrance Animation for Context Menus
3
+ impact: MEDIUM
4
+ tags: none, context-menu, entrance
5
+ ---
6
+
7
+ ## No Entrance Animation for Context Menus
8
+
9
+ Context menus should not animate on entrance (exit only).
10
+
11
+ **Incorrect (entrance animation):**
12
+
13
+ ```tsx
14
+ <motion.div
15
+ initial={{ opacity: 0, scale: 0.95 }}
16
+ animate={{ opacity: 1, scale: 1 }}
17
+ exit={{ opacity: 0 }}
18
+ />
19
+ ```
20
+
21
+ **Correct (exit only):**
22
+
23
+ ```tsx
24
+ <motion.div exit={{ opacity: 0, scale: 0.95 }} />
25
+ ```
@@ -0,0 +1,29 @@
1
+ ---
2
+ title: No Animation for High-Frequency Interactions
3
+ impact: HIGH
4
+ tags: none, high-frequency, performance
5
+ ---
6
+
7
+ ## No Animation for High-Frequency Interactions
8
+
9
+ High-frequency interactions should have no animation.
10
+
11
+ **Incorrect (animated on every keystroke):**
12
+
13
+ ```tsx
14
+ function SearchInput() {
15
+ return (
16
+ <motion.div animate={{ scale: [1, 1.02, 1] }}>
17
+ <input onChange={handleSearch} />
18
+ </motion.div>
19
+ );
20
+ }
21
+ ```
22
+
23
+ **Correct (no animation):**
24
+
25
+ ```tsx
26
+ function SearchInput() {
27
+ return <input onChange={handleSearch} />;
28
+ }
29
+ ```