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.
- package/defaults/memory-promoter.md +99 -0
- package/defaults/self/staging.md +48 -0
- package/package.json +7 -3
- package/skills/code-review/pr-review.md +14 -1
- package/skills/cro/page.md +22 -0
- package/skills/frontend-design/SKILL.md +7 -3
- package/skills/frontend-design/building.md +17 -2
- package/skills/qa/SKILL.md +108 -72
- package/skills/userinterface-wiki/AGENTS.md +3749 -0
- package/skills/userinterface-wiki/SKILL.md +253 -0
- package/skills/userinterface-wiki/metadata.json +26 -0
- package/skills/userinterface-wiki/rules/_sections.md +66 -0
- package/skills/userinterface-wiki/rules/_template.md +24 -0
- package/skills/userinterface-wiki/rules/a11y-reduced-motion-check.md +30 -0
- package/skills/userinterface-wiki/rules/a11y-toggle-setting.md +30 -0
- package/skills/userinterface-wiki/rules/a11y-visual-equivalent.md +36 -0
- package/skills/userinterface-wiki/rules/a11y-volume-control.md +28 -0
- package/skills/userinterface-wiki/rules/appropriate-confirmations-only.md +19 -0
- package/skills/userinterface-wiki/rules/appropriate-errors-warnings.md +18 -0
- package/skills/userinterface-wiki/rules/appropriate-no-decorative.md +21 -0
- package/skills/userinterface-wiki/rules/appropriate-no-high-frequency.md +28 -0
- package/skills/userinterface-wiki/rules/appropriate-no-punishing.md +27 -0
- package/skills/userinterface-wiki/rules/container-callback-ref.md +31 -0
- package/skills/userinterface-wiki/rules/container-guard-initial-zero.md +25 -0
- package/skills/userinterface-wiki/rules/container-no-excessive-use.md +13 -0
- package/skills/userinterface-wiki/rules/container-overflow-hidden.md +25 -0
- package/skills/userinterface-wiki/rules/container-transition-delay.md +21 -0
- package/skills/userinterface-wiki/rules/container-two-div-pattern.md +35 -0
- package/skills/userinterface-wiki/rules/container-use-resize-observer.md +48 -0
- package/skills/userinterface-wiki/rules/context-cleanup-nodes.md +25 -0
- package/skills/userinterface-wiki/rules/context-resume-suspended.md +28 -0
- package/skills/userinterface-wiki/rules/context-reuse-single.md +30 -0
- package/skills/userinterface-wiki/rules/design-filter-for-character.md +25 -0
- package/skills/userinterface-wiki/rules/design-noise-for-percussion.md +26 -0
- package/skills/userinterface-wiki/rules/design-oscillator-for-tonal.md +22 -0
- package/skills/userinterface-wiki/rules/duration-max-300ms.md +21 -0
- package/skills/userinterface-wiki/rules/duration-press-hover.md +21 -0
- package/skills/userinterface-wiki/rules/duration-shorten-before-curve.md +21 -0
- package/skills/userinterface-wiki/rules/duration-small-state.md +15 -0
- package/skills/userinterface-wiki/rules/easing-entrance-ease-out.md +21 -0
- package/skills/userinterface-wiki/rules/easing-exit-ease-in.md +21 -0
- package/skills/userinterface-wiki/rules/easing-for-state-change.md +27 -0
- package/skills/userinterface-wiki/rules/easing-linear-only-progress.md +21 -0
- package/skills/userinterface-wiki/rules/easing-natural-decay.md +22 -0
- package/skills/userinterface-wiki/rules/easing-no-linear-motion.md +22 -0
- package/skills/userinterface-wiki/rules/easing-transition-ease-in-out.md +15 -0
- package/skills/userinterface-wiki/rules/envelope-exponential-decay.md +21 -0
- package/skills/userinterface-wiki/rules/envelope-no-zero-target.md +21 -0
- package/skills/userinterface-wiki/rules/envelope-set-initial-value.md +22 -0
- package/skills/userinterface-wiki/rules/exit-key-required.md +29 -0
- package/skills/userinterface-wiki/rules/exit-matches-initial.md +29 -0
- package/skills/userinterface-wiki/rules/exit-prop-required.md +33 -0
- package/skills/userinterface-wiki/rules/exit-requires-wrapper.md +27 -0
- package/skills/userinterface-wiki/rules/impl-default-subtle.md +21 -0
- package/skills/userinterface-wiki/rules/impl-preload-audio.md +34 -0
- package/skills/userinterface-wiki/rules/impl-reset-current-time.md +26 -0
- package/skills/userinterface-wiki/rules/mode-pop-layout-for-lists.md +25 -0
- package/skills/userinterface-wiki/rules/mode-sync-layout-conflict.md +29 -0
- package/skills/userinterface-wiki/rules/mode-wait-doubles-duration.md +25 -0
- package/skills/userinterface-wiki/rules/morphing-aria-hidden.md +21 -0
- package/skills/userinterface-wiki/rules/morphing-consistent-viewbox.md +23 -0
- package/skills/userinterface-wiki/rules/morphing-group-variants.md +33 -0
- package/skills/userinterface-wiki/rules/morphing-jump-non-grouped.md +29 -0
- package/skills/userinterface-wiki/rules/morphing-reduced-motion.md +28 -0
- package/skills/userinterface-wiki/rules/morphing-spring-rotation.md +23 -0
- package/skills/userinterface-wiki/rules/morphing-strokelinecap-round.md +21 -0
- package/skills/userinterface-wiki/rules/morphing-three-lines.md +32 -0
- package/skills/userinterface-wiki/rules/morphing-use-collapsed.md +33 -0
- package/skills/userinterface-wiki/rules/native-backdrop-styling.md +27 -0
- package/skills/userinterface-wiki/rules/native-placeholder-styling.md +27 -0
- package/skills/userinterface-wiki/rules/native-selection-styling.md +18 -0
- package/skills/userinterface-wiki/rules/nested-consistent-timing.md +25 -0
- package/skills/userinterface-wiki/rules/nested-propagate-required.md +41 -0
- package/skills/userinterface-wiki/rules/none-context-menu-entrance.md +25 -0
- package/skills/userinterface-wiki/rules/none-high-frequency.md +29 -0
- package/skills/userinterface-wiki/rules/none-keyboard-navigation.md +32 -0
- package/skills/userinterface-wiki/rules/param-click-duration.md +21 -0
- package/skills/userinterface-wiki/rules/param-filter-frequency-range.md +21 -0
- package/skills/userinterface-wiki/rules/param-q-value-range.md +21 -0
- package/skills/userinterface-wiki/rules/param-reasonable-gain.md +21 -0
- package/skills/userinterface-wiki/rules/physics-active-state.md +23 -0
- package/skills/userinterface-wiki/rules/physics-no-excessive-stagger.md +22 -0
- package/skills/userinterface-wiki/rules/physics-spring-for-overshoot.md +23 -0
- package/skills/userinterface-wiki/rules/physics-subtle-deformation.md +22 -0
- package/skills/userinterface-wiki/rules/prefetch-hit-slop.md +27 -0
- package/skills/userinterface-wiki/rules/prefetch-keyboard-tab.md +19 -0
- package/skills/userinterface-wiki/rules/prefetch-not-everything.md +22 -0
- package/skills/userinterface-wiki/rules/prefetch-touch-fallback.md +34 -0
- package/skills/userinterface-wiki/rules/prefetch-trajectory-over-hover.md +32 -0
- package/skills/userinterface-wiki/rules/prefetch-use-selectively.md +13 -0
- package/skills/userinterface-wiki/rules/presence-disable-interactions.md +31 -0
- package/skills/userinterface-wiki/rules/presence-hook-in-child.md +31 -0
- package/skills/userinterface-wiki/rules/presence-safe-to-remove.md +37 -0
- package/skills/userinterface-wiki/rules/pseudo-content-required.md +28 -0
- package/skills/userinterface-wiki/rules/pseudo-first-line-styling.md +27 -0
- package/skills/userinterface-wiki/rules/pseudo-hit-target-expansion.md +31 -0
- package/skills/userinterface-wiki/rules/pseudo-marker-styling.md +28 -0
- package/skills/userinterface-wiki/rules/pseudo-over-dom-node.md +32 -0
- package/skills/userinterface-wiki/rules/pseudo-position-relative-parent.md +33 -0
- package/skills/userinterface-wiki/rules/pseudo-z-index-layering.md +37 -0
- package/skills/userinterface-wiki/rules/spring-for-gestures.md +27 -0
- package/skills/userinterface-wiki/rules/spring-for-interruptible.md +27 -0
- package/skills/userinterface-wiki/rules/spring-params-balanced.md +29 -0
- package/skills/userinterface-wiki/rules/spring-preserves-velocity.md +28 -0
- package/skills/userinterface-wiki/rules/staging-dim-background.md +22 -0
- package/skills/userinterface-wiki/rules/staging-one-focal-point.md +24 -0
- package/skills/userinterface-wiki/rules/staging-z-index-hierarchy.md +22 -0
- package/skills/userinterface-wiki/rules/timing-consistent.md +24 -0
- package/skills/userinterface-wiki/rules/timing-no-entrance-context-menu.md +22 -0
- package/skills/userinterface-wiki/rules/timing-under-300ms.md +22 -0
- package/skills/userinterface-wiki/rules/transition-name-cleanup.md +28 -0
- package/skills/userinterface-wiki/rules/transition-name-required.md +27 -0
- package/skills/userinterface-wiki/rules/transition-name-unique.md +24 -0
- package/skills/userinterface-wiki/rules/transition-over-js-library.md +32 -0
- package/skills/userinterface-wiki/rules/transition-style-pseudo-elements.md +24 -0
- package/skills/userinterface-wiki/rules/type-antialiased-on-retina.md +18 -0
- package/skills/userinterface-wiki/rules/type-disambiguation-stylistic-set.md +15 -0
- package/skills/userinterface-wiki/rules/type-font-display-swap.md +28 -0
- package/skills/userinterface-wiki/rules/type-justify-with-hyphens.md +24 -0
- package/skills/userinterface-wiki/rules/type-letter-spacing-uppercase.md +28 -0
- package/skills/userinterface-wiki/rules/type-no-font-synthesis.md +18 -0
- package/skills/userinterface-wiki/rules/type-oldstyle-nums-for-prose.md +21 -0
- package/skills/userinterface-wiki/rules/type-opentype-contextual-alternates.md +15 -0
- package/skills/userinterface-wiki/rules/type-optical-sizing-auto.md +25 -0
- package/skills/userinterface-wiki/rules/type-proper-fractions.md +15 -0
- package/skills/userinterface-wiki/rules/type-slashed-zero.md +17 -0
- package/skills/userinterface-wiki/rules/type-tabular-nums-for-data.md +21 -0
- package/skills/userinterface-wiki/rules/type-text-wrap-balance-headings.md +21 -0
- package/skills/userinterface-wiki/rules/type-text-wrap-pretty.md +16 -0
- package/skills/userinterface-wiki/rules/type-underline-offset.md +25 -0
- package/skills/userinterface-wiki/rules/type-variable-weight-continuous.md +23 -0
- package/skills/userinterface-wiki/rules/ux-aesthetic-usability.md +32 -0
- package/skills/userinterface-wiki/rules/ux-cognitive-load-reduce.md +49 -0
- package/skills/userinterface-wiki/rules/ux-common-region-boundaries.md +50 -0
- package/skills/userinterface-wiki/rules/ux-doherty-perceived-speed.md +29 -0
- package/skills/userinterface-wiki/rules/ux-doherty-under-400ms.md +30 -0
- package/skills/userinterface-wiki/rules/ux-fitts-hit-area.md +32 -0
- package/skills/userinterface-wiki/rules/ux-fitts-target-size.md +31 -0
- package/skills/userinterface-wiki/rules/ux-goal-gradient-progress.md +33 -0
- package/skills/userinterface-wiki/rules/ux-hicks-minimize-choices.md +45 -0
- package/skills/userinterface-wiki/rules/ux-jakobs-familiar-patterns.md +37 -0
- package/skills/userinterface-wiki/rules/ux-millers-chunking.md +23 -0
- package/skills/userinterface-wiki/rules/ux-pareto-prioritize-features.md +36 -0
- package/skills/userinterface-wiki/rules/ux-peak-end-finish-strong.md +35 -0
- package/skills/userinterface-wiki/rules/ux-postels-accept-messy-input.md +45 -0
- package/skills/userinterface-wiki/rules/ux-pragnanz-simplify.md +33 -0
- package/skills/userinterface-wiki/rules/ux-progressive-disclosure.md +41 -0
- package/skills/userinterface-wiki/rules/ux-proximity-grouping.md +38 -0
- package/skills/userinterface-wiki/rules/ux-serial-position.md +31 -0
- package/skills/userinterface-wiki/rules/ux-similarity-consistency.md +35 -0
- package/skills/userinterface-wiki/rules/ux-teslers-complexity.md +28 -0
- package/skills/userinterface-wiki/rules/ux-uniform-connectedness.md +43 -0
- package/skills/userinterface-wiki/rules/ux-von-restorff-emphasis.md +29 -0
- package/skills/userinterface-wiki/rules/ux-zeigarnik-show-incomplete.md +36 -0
- package/skills/userinterface-wiki/rules/visual-animate-shadow-pseudo.md +49 -0
- package/skills/userinterface-wiki/rules/visual-border-alpha-colors.md +25 -0
- package/skills/userinterface-wiki/rules/visual-button-shadow-anatomy.md +49 -0
- package/skills/userinterface-wiki/rules/visual-concentric-radius.md +40 -0
- package/skills/userinterface-wiki/rules/visual-consistent-spacing-scale.md +35 -0
- package/skills/userinterface-wiki/rules/visual-layered-shadows.md +30 -0
- package/skills/userinterface-wiki/rules/visual-no-pure-black-shadow.md +25 -0
- package/skills/userinterface-wiki/rules/visual-shadow-direction.md +25 -0
- package/skills/userinterface-wiki/rules/visual-shadow-matches-elevation.md +23 -0
- package/skills/userinterface-wiki/rules/weight-duration-matches-action.md +29 -0
- package/skills/userinterface-wiki/rules/weight-match-action.md +32 -0
- package/src/cli/index.ts +23 -73
- package/src/cli/job.ts +25 -92
- package/src/cli/status.ts +17 -9
- package/src/commands/init.ts +1 -0
- package/src/commands/validate.ts +12 -10
- package/src/core/agents.ts +6 -19
- package/src/core/consolidator.ts +97 -91
- package/src/core/daemon.ts +71 -43
- package/src/core/finalizer.ts +31 -3
- package/src/core/health.ts +5 -17
- package/src/core/runner.ts +8 -44
- package/src/core/scheduler.ts +12 -49
- package/src/core/skills.ts +4 -11
- package/src/core/summarizer.ts +7 -21
- package/src/db/connection.ts +0 -11
- package/src/db/models/job.ts +23 -22
- package/src/db/with-db.ts +11 -0
- package/src/mcp/server.ts +1 -1
- package/src/prompts/environment.md +44 -41
- package/src/utils/pid.ts +44 -0
- package/src/utils/schedule.ts +39 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Springs for Gesture-Driven Motion
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: spring, gesture, drag
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Springs for Gesture-Driven Motion
|
|
8
|
+
|
|
9
|
+
Gesture-driven motion (drag, flick, swipe) must use springs.
|
|
10
|
+
|
|
11
|
+
**Incorrect (easing for drag):**
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
<motion.div
|
|
15
|
+
drag="x"
|
|
16
|
+
transition={{ duration: 0.3, ease: "easeOut" }}
|
|
17
|
+
/>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Correct (spring for drag):**
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
<motion.div
|
|
24
|
+
drag="x"
|
|
25
|
+
transition={{ type: "spring", stiffness: 500, damping: 30 }}
|
|
26
|
+
/>
|
|
27
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Springs for Interruptible Motion
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: spring, interruptible, animation
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Springs for Interruptible Motion
|
|
8
|
+
|
|
9
|
+
Motion that can be interrupted must use springs.
|
|
10
|
+
|
|
11
|
+
**Incorrect (easing for interruptible):**
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
<motion.div
|
|
15
|
+
animate={{ x: isOpen ? 200 : 0 }}
|
|
16
|
+
transition={{ duration: 0.3 }}
|
|
17
|
+
/>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Correct (spring for interruptible):**
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
<motion.div
|
|
24
|
+
animate={{ x: isOpen ? 200 : 0 }}
|
|
25
|
+
transition={{ type: "spring", stiffness: 400, damping: 25 }}
|
|
26
|
+
/>
|
|
27
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Balanced Spring Parameters
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: spring, stiffness, damping
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Balanced Spring Parameters
|
|
8
|
+
|
|
9
|
+
Spring parameters must be balanced; avoid excessive oscillation.
|
|
10
|
+
|
|
11
|
+
**Incorrect (too bouncy):**
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
transition={{
|
|
15
|
+
type: "spring",
|
|
16
|
+
stiffness: 1000,
|
|
17
|
+
damping: 5,
|
|
18
|
+
}}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Correct (balanced):**
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
transition={{
|
|
25
|
+
type: "spring",
|
|
26
|
+
stiffness: 500,
|
|
27
|
+
damping: 30,
|
|
28
|
+
}}
|
|
29
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Springs Preserve Input Velocity
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: spring, velocity, drag
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Springs Preserve Input Velocity
|
|
8
|
+
|
|
9
|
+
When velocity matters, use springs to preserve input energy.
|
|
10
|
+
|
|
11
|
+
**Incorrect (velocity ignored):**
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
onDragEnd={(e, info) => {
|
|
15
|
+
animate(target, { x: 0 }, { duration: 0.3 });
|
|
16
|
+
}}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (velocity preserved):**
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
onDragEnd={(e, info) => {
|
|
23
|
+
animate(target, { x: 0 }, {
|
|
24
|
+
type: "spring",
|
|
25
|
+
velocity: info.velocity.x,
|
|
26
|
+
});
|
|
27
|
+
}}
|
|
28
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Dim Background for Focus
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Transparent overlays fail to direct focus; dimmed backgrounds isolate the modal and reduce distraction.
|
|
5
|
+
tags: staging, modal, overlay
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Dim Background for Focus
|
|
9
|
+
|
|
10
|
+
Modal/dialog backgrounds should dim to direct focus.
|
|
11
|
+
|
|
12
|
+
**Incorrect (transparent overlay):**
|
|
13
|
+
|
|
14
|
+
```css
|
|
15
|
+
.overlay { background: transparent; }
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Correct (dimmed overlay):**
|
|
19
|
+
|
|
20
|
+
```css
|
|
21
|
+
.overlay { background: var(--black-a6); }
|
|
22
|
+
```
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Single Focal Point
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Competing animations split attention and reduce clarity; one focal point guides the user effectively.
|
|
5
|
+
tags: staging, focus, attention
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Single Focal Point
|
|
9
|
+
|
|
10
|
+
Only one element should animate prominently at a time.
|
|
11
|
+
|
|
12
|
+
**Incorrect (competing animations):**
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
<motion.div animate={{ scale: 1.1 }} />
|
|
16
|
+
<motion.div animate={{ scale: 1.1 }} />
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (single focal point):**
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
<motion.div animate={{ scale: 1.1 }} />
|
|
23
|
+
<motion.div animate={{ scale: 1 }} />
|
|
24
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Z-Index Layering for Animated Elements
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
impactDescription: Missing z-index causes tooltips and overlays to render behind other content, breaking the visual hierarchy.
|
|
5
|
+
tags: staging, z-index, layering
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Z-Index Layering for Animated Elements
|
|
9
|
+
|
|
10
|
+
Animated elements must respect z-index layering.
|
|
11
|
+
|
|
12
|
+
**Incorrect (no z-index):**
|
|
13
|
+
|
|
14
|
+
```css
|
|
15
|
+
.tooltip { /* No z-index, may render behind other elements */ }
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Correct (explicit z-index):**
|
|
19
|
+
|
|
20
|
+
```css
|
|
21
|
+
.tooltip { z-index: 50; }
|
|
22
|
+
```
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Consistent Timing for Similar Elements
|
|
3
|
+
impact: CRITICAL
|
|
4
|
+
impactDescription: Inconsistent timing across similar elements creates a disjointed, unpolished feel and undermines design system coherence.
|
|
5
|
+
tags: timing, consistency, animation
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Consistent Timing for Similar Elements
|
|
9
|
+
|
|
10
|
+
Similar elements must use identical timing values.
|
|
11
|
+
|
|
12
|
+
**Incorrect (inconsistent timing):**
|
|
13
|
+
|
|
14
|
+
```css
|
|
15
|
+
.button-primary { transition: 200ms; }
|
|
16
|
+
.button-secondary { transition: 150ms; }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (consistent timing):**
|
|
20
|
+
|
|
21
|
+
```css
|
|
22
|
+
.button-primary { transition: 200ms; }
|
|
23
|
+
.button-secondary { transition: 200ms; }
|
|
24
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: No Entrance Animation on Context Menus
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Entrance animations on context menus delay access to options and feel unnecessary for ephemeral UI.
|
|
5
|
+
tags: timing, context-menu, entrance
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## No Entrance Animation on Context Menus
|
|
9
|
+
|
|
10
|
+
Context menus should not animate on entrance (exit only).
|
|
11
|
+
|
|
12
|
+
**Incorrect (animates entrance):**
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
<motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} />
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Correct (exit only):**
|
|
19
|
+
|
|
20
|
+
```tsx
|
|
21
|
+
<motion.div exit={{ opacity: 0 }} />
|
|
22
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: User Animations Under 300ms
|
|
3
|
+
impact: CRITICAL
|
|
4
|
+
impactDescription: Exceeding 300ms for user-initiated actions degrades perceived responsiveness and makes the interface feel sluggish.
|
|
5
|
+
tags: timing, duration, animation
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## User Animations Under 300ms
|
|
9
|
+
|
|
10
|
+
User-initiated animations must complete within 300ms.
|
|
11
|
+
|
|
12
|
+
**Incorrect (exceeds 300ms limit):**
|
|
13
|
+
|
|
14
|
+
```css
|
|
15
|
+
.button { transition: transform 400ms; }
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Correct (within 300ms):**
|
|
19
|
+
|
|
20
|
+
```css
|
|
21
|
+
.button { transition: transform 200ms; }
|
|
22
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Clean Up View Transition Names
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: view-transition, cleanup
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Clean Up View Transition Names
|
|
8
|
+
|
|
9
|
+
Remove view-transition-name after transition completes.
|
|
10
|
+
|
|
11
|
+
**Incorrect (stale name):**
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
sourceImg.style.viewTransitionName = "card";
|
|
15
|
+
document.startViewTransition(() => {
|
|
16
|
+
targetImg.style.viewTransitionName = "card";
|
|
17
|
+
});
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Correct (name cleaned up):**
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
sourceImg.style.viewTransitionName = "card";
|
|
24
|
+
document.startViewTransition(() => {
|
|
25
|
+
sourceImg.style.viewTransitionName = "";
|
|
26
|
+
targetImg.style.viewTransitionName = "card";
|
|
27
|
+
});
|
|
28
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: View Transition Name Required
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: view-transition, transition-name
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## View Transition Name Required
|
|
8
|
+
|
|
9
|
+
Elements participating in view transitions need view-transition-name.
|
|
10
|
+
|
|
11
|
+
**Incorrect (no transition name):**
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
document.startViewTransition(() => {
|
|
15
|
+
targetImg.src = newSrc;
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (transition name assigned):**
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
sourceImg.style.viewTransitionName = "card";
|
|
23
|
+
document.startViewTransition(() => {
|
|
24
|
+
sourceImg.style.viewTransitionName = "";
|
|
25
|
+
targetImg.style.viewTransitionName = "card";
|
|
26
|
+
});
|
|
27
|
+
```
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Unique View Transition Names
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: view-transition, unique, naming
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Unique View Transition Names
|
|
8
|
+
|
|
9
|
+
Each view-transition-name must be unique on the page during transition.
|
|
10
|
+
|
|
11
|
+
**Incorrect (duplicate names):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.card {
|
|
15
|
+
view-transition-name: card;
|
|
16
|
+
}
|
|
17
|
+
/* Multiple cards with same name */
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Correct (unique per element):**
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
element.style.viewTransitionName = `card-${id}`;
|
|
24
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: View Transitions Over JS Libraries
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: view-transition, native, performance
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## View Transitions Over JS Libraries
|
|
8
|
+
|
|
9
|
+
Prefer View Transitions API over JavaScript animation libraries for page transitions.
|
|
10
|
+
|
|
11
|
+
**Incorrect (JS-based transition):**
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { motion } from "motion/react";
|
|
15
|
+
|
|
16
|
+
function ImageLightbox() {
|
|
17
|
+
return (
|
|
18
|
+
<motion.img layoutId="hero" />
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Correct (native View Transition):**
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
function openLightbox(img: HTMLImageElement) {
|
|
27
|
+
img.style.viewTransitionName = "hero";
|
|
28
|
+
document.startViewTransition(() => {
|
|
29
|
+
// Native browser transition
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
```
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Style View Transition Pseudo-Elements
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: view-transition, pseudo, styling
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Style View Transition Pseudo-Elements
|
|
8
|
+
|
|
9
|
+
Style view transition pseudo-elements for custom animations.
|
|
10
|
+
|
|
11
|
+
**Incorrect (default crossfade only):**
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
document.startViewTransition(() => { /* ... */ });
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Correct (custom animation):**
|
|
18
|
+
|
|
19
|
+
```css
|
|
20
|
+
::view-transition-group(card) {
|
|
21
|
+
animation-duration: 300ms;
|
|
22
|
+
animation-timing-function: cubic-bezier(0.215, 0.61, 0.355, 1);
|
|
23
|
+
}
|
|
24
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Antialiased Font Smoothing
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: type, rendering, antialiased
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Use Antialiased Font Smoothing
|
|
8
|
+
|
|
9
|
+
Set -webkit-font-smoothing: antialiased on retina displays. The default subpixel rendering looks thicker and fuzzier.
|
|
10
|
+
|
|
11
|
+
**Correct:**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
body {
|
|
15
|
+
-webkit-font-smoothing: antialiased;
|
|
16
|
+
-moz-osx-font-smoothing: grayscale;
|
|
17
|
+
}
|
|
18
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Disambiguation Stylistic Set for UI
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: type, stylistic-set, disambiguation
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Use Disambiguation Stylistic Set for UI
|
|
8
|
+
|
|
9
|
+
Enable ss02 (or your font's disambiguation set) in code-facing UIs to distinguish I, l, 1 and 0, O.
|
|
10
|
+
|
|
11
|
+
**Correct:**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.code-ui { font-feature-settings: "ss02"; }
|
|
15
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use font-display swap to Avoid Invisible Text
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: type, font-display, loading, FOIT
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Use font-display swap to Avoid Invisible Text
|
|
8
|
+
|
|
9
|
+
Set font-display: swap so text renders immediately with a fallback font while the custom font loads.
|
|
10
|
+
|
|
11
|
+
**Incorrect (invisible text during load):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
@font-face {
|
|
15
|
+
font-family: "Inter";
|
|
16
|
+
src: url("/fonts/inter.woff2") format("woff2");
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Correct (text visible immediately):**
|
|
21
|
+
|
|
22
|
+
```css
|
|
23
|
+
@font-face {
|
|
24
|
+
font-family: "Inter";
|
|
25
|
+
src: url("/fonts/inter.woff2") format("woff2");
|
|
26
|
+
font-display: swap;
|
|
27
|
+
}
|
|
28
|
+
```
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Pair Justified Text with Hyphens
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: type, justify, hyphens, rivers
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Pair Justified Text with Hyphens
|
|
8
|
+
|
|
9
|
+
Justified text without hyphens creates rivers of whitespace. Always pair with hyphens: auto.
|
|
10
|
+
|
|
11
|
+
**Incorrect (rivers of whitespace):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.article { text-align: justify; }
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Correct (hyphenation prevents rivers):**
|
|
18
|
+
|
|
19
|
+
```css
|
|
20
|
+
.article {
|
|
21
|
+
text-align: justify;
|
|
22
|
+
hyphens: auto;
|
|
23
|
+
}
|
|
24
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Add Letter Spacing to Uppercase Text
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: type, letter-spacing, uppercase, small-caps
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Add Letter Spacing to Uppercase Text
|
|
8
|
+
|
|
9
|
+
Uppercase and small-caps text needs positive letter-spacing to feel open and readable.
|
|
10
|
+
|
|
11
|
+
**Incorrect (tight uppercase):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.label {
|
|
15
|
+
text-transform: uppercase;
|
|
16
|
+
font-size: 12px;
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Correct (opened up):**
|
|
21
|
+
|
|
22
|
+
```css
|
|
23
|
+
.label {
|
|
24
|
+
text-transform: uppercase;
|
|
25
|
+
font-size: 12px;
|
|
26
|
+
letter-spacing: 0.05em;
|
|
27
|
+
}
|
|
28
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Disable Font Synthesis for Missing Styles
|
|
3
|
+
impact: LOW
|
|
4
|
+
tags: type, synthesis, italic, bold
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Disable Font Synthesis for Missing Styles
|
|
8
|
+
|
|
9
|
+
Set font-synthesis: none to prevent the browser from faking bold or italic. Browser-generated faux styles look terrible.
|
|
10
|
+
|
|
11
|
+
**Correct:**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.icon-font,
|
|
15
|
+
.display-font {
|
|
16
|
+
font-synthesis: none;
|
|
17
|
+
}
|
|
18
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Oldstyle Numbers for Body Text
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: type, numeric, oldstyle, prose
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Oldstyle Numbers for Body Text
|
|
8
|
+
|
|
9
|
+
Use oldstyle-nums in body text so numbers blend with lowercase letters. Use lining-nums in tables and headings.
|
|
10
|
+
|
|
11
|
+
**Correct (prose):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.body-text { font-variant-numeric: oldstyle-nums; }
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Correct (data):**
|
|
18
|
+
|
|
19
|
+
```css
|
|
20
|
+
.data-table { font-variant-numeric: lining-nums tabular-nums; }
|
|
21
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Enable Contextual Alternates
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: type, opentype, calt
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Enable Contextual Alternates
|
|
8
|
+
|
|
9
|
+
Keep contextual alternates enabled (calt). They adjust punctuation and glyph shapes based on surrounding characters.
|
|
10
|
+
|
|
11
|
+
**Correct (usually on by default, don't disable):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
body { font-feature-settings: "calt" 1; }
|
|
15
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Keep Optical Sizing Auto
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: type, variable-font, optical-sizing
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Keep Optical Sizing Auto
|
|
8
|
+
|
|
9
|
+
Leave font-optical-sizing at auto. The font adjusts glyph shapes for the current size — thicker strokes at small sizes, finer details at large sizes.
|
|
10
|
+
|
|
11
|
+
**Incorrect (forced optical size):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
body {
|
|
15
|
+
font-optical-sizing: none;
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (automatic adjustment):**
|
|
20
|
+
|
|
21
|
+
```css
|
|
22
|
+
body {
|
|
23
|
+
font-optical-sizing: auto;
|
|
24
|
+
}
|
|
25
|
+
```
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Typographic Fractions
|
|
3
|
+
impact: LOW
|
|
4
|
+
tags: type, fractions, numeric, opentype
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Use Typographic Fractions
|
|
8
|
+
|
|
9
|
+
Enable diagonal-fractions to convert 1/2, 1/3, etc. into proper typographic fractions.
|
|
10
|
+
|
|
11
|
+
**Correct:**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.recipe { font-variant-numeric: diagonal-fractions; }
|
|
15
|
+
```
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Slashed Zero for Disambiguation
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: type, zero, disambiguation
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Slashed Zero for Disambiguation
|
|
8
|
+
|
|
9
|
+
Enable slashed zero in code-adjacent UIs so users never confuse 0 with O.
|
|
10
|
+
|
|
11
|
+
**Correct:**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.code { font-variant-numeric: slashed-zero; }
|
|
15
|
+
/* or */
|
|
16
|
+
.code { font-feature-settings: "zero"; }
|
|
17
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Tabular Numbers for Data Display
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: type, numeric, tabular, alignment
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Tabular Numbers for Data Display
|
|
8
|
+
|
|
9
|
+
Use tabular-nums for any numeric data that should align in columns (tables, dashboards, pricing).
|
|
10
|
+
|
|
11
|
+
**Incorrect (proportional numbers misalign):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.price { font-variant-numeric: proportional-nums; }
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Correct (tabular numbers align):**
|
|
18
|
+
|
|
19
|
+
```css
|
|
20
|
+
.price { font-variant-numeric: tabular-nums; }
|
|
21
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Balance Headings with text-wrap
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: type, text-wrap, balance, headings
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Balance Headings with text-wrap
|
|
8
|
+
|
|
9
|
+
Use text-wrap: balance on headings to make lines roughly equal length instead of one long line and a short orphan.
|
|
10
|
+
|
|
11
|
+
**Incorrect (unbalanced heading):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
h1 { /* default text-wrap */ }
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**Correct (balanced):**
|
|
18
|
+
|
|
19
|
+
```css
|
|
20
|
+
h1 { text-wrap: balance; }
|
|
21
|
+
```
|