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,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Group Related Elements Spatially
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: ux, proximity, grouping, layout
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Group Related Elements Spatially
|
|
8
|
+
|
|
9
|
+
Elements near each other are perceived as related. Use spacing to create visual groups.
|
|
10
|
+
|
|
11
|
+
**Incorrect (uniform spacing between unrelated items):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.form label,
|
|
15
|
+
.form input,
|
|
16
|
+
.form .hint,
|
|
17
|
+
.form .divider {
|
|
18
|
+
margin-bottom: 16px;
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Correct (tighter spacing within groups, larger between):**
|
|
23
|
+
|
|
24
|
+
```css
|
|
25
|
+
.form label {
|
|
26
|
+
margin-bottom: 4px;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.form input {
|
|
30
|
+
margin-bottom: 2px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.form .hint {
|
|
34
|
+
margin-bottom: 24px;
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Reference: [Law of Proximity](https://lawsofux.com/law-of-proximity/)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Place Key Items First or Last
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: ux, serial-position, navigation, order
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Place Key Items First or Last
|
|
8
|
+
|
|
9
|
+
Users best remember the first and last items in a sequence. Place the most important actions at these positions.
|
|
10
|
+
|
|
11
|
+
**Incorrect (important action buried in middle):**
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
<nav>
|
|
15
|
+
<Link href="/settings">Settings</Link>
|
|
16
|
+
<Link href="/">Home</Link>
|
|
17
|
+
<Link href="/about">About</Link>
|
|
18
|
+
</nav>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Correct (key items at edges):**
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
<nav>
|
|
25
|
+
<Link href="/">Home</Link>
|
|
26
|
+
<Link href="/about">About</Link>
|
|
27
|
+
<Link href="/settings">Settings</Link>
|
|
28
|
+
</nav>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Reference: [Serial Position Effect](https://lawsofux.com/serial-position-effect/)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Similar Elements Should Look Alike
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: ux, similarity, consistency, visual
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Similar Elements Should Look Alike
|
|
8
|
+
|
|
9
|
+
Elements that function the same should look the same. Visual consistency signals functional consistency.
|
|
10
|
+
|
|
11
|
+
**Incorrect (same function, different appearance):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.save-button {
|
|
15
|
+
background: blue;
|
|
16
|
+
border-radius: 8px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.submit-button {
|
|
20
|
+
background: green;
|
|
21
|
+
border-radius: 0;
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Correct (same function, same appearance):**
|
|
26
|
+
|
|
27
|
+
```css
|
|
28
|
+
.primary-action {
|
|
29
|
+
background: var(--gray-12);
|
|
30
|
+
color: var(--gray-1);
|
|
31
|
+
border-radius: 8px;
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Reference: [Law of Similarity](https://lawsofux.com/law-of-similarity/)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Move Complexity, Don't Hide It
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: ux, teslers, complexity, simplicity
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Move Complexity, Don't Hide It
|
|
8
|
+
|
|
9
|
+
Every system has irreducible complexity. The question is who handles it — the user or the system.
|
|
10
|
+
|
|
11
|
+
**Incorrect (complexity pushed to user):**
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
<input
|
|
15
|
+
type="text"
|
|
16
|
+
placeholder="Enter date as YYYY-MM-DDTHH:mm:ss.sssZ"
|
|
17
|
+
/>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Correct (system absorbs complexity):**
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
<DatePicker
|
|
24
|
+
onChange={(date) => setDate(date.toISOString())}
|
|
25
|
+
/>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Reference: [Tesler's Law](https://lawsofux.com/teslers-law/)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Visually Connect Related Elements
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: ux, connectedness, grouping, visual
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Visually Connect Related Elements
|
|
8
|
+
|
|
9
|
+
Elements that are visually connected (by lines, color, or frames) are perceived as more related.
|
|
10
|
+
|
|
11
|
+
**Incorrect (steps with no visual connection):**
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
function Steps({ current }) {
|
|
15
|
+
return (
|
|
16
|
+
<div>
|
|
17
|
+
<span>Step 1</span>
|
|
18
|
+
<span>Step 2</span>
|
|
19
|
+
<span>Step 3</span>
|
|
20
|
+
</div>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**Correct (connected with a visual line):**
|
|
26
|
+
|
|
27
|
+
```tsx
|
|
28
|
+
function Steps({ current }) {
|
|
29
|
+
return (
|
|
30
|
+
<div className={styles.steps}>
|
|
31
|
+
{steps.map((step, i) => (
|
|
32
|
+
<div key={step.id} className={styles.step} data-active={i <= current}>
|
|
33
|
+
<div className={styles.dot} />
|
|
34
|
+
{i < steps.length - 1 && <div className={styles.connector} />}
|
|
35
|
+
<span>{step.label}</span>
|
|
36
|
+
</div>
|
|
37
|
+
))}
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Reference: [Law of Uniform Connectedness](https://lawsofux.com/law-of-uniform-connectedness/)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Make Important Elements Visually Distinct
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: ux, von-restorff, emphasis, distinction
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Make Important Elements Visually Distinct
|
|
8
|
+
|
|
9
|
+
When multiple similar elements are present, the one that differs is most likely to be remembered.
|
|
10
|
+
|
|
11
|
+
**Incorrect (primary action blends in):**
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
<div className={styles.actions}>
|
|
15
|
+
<button className={styles.button}>Cancel</button>
|
|
16
|
+
<button className={styles.button}>Delete Account</button>
|
|
17
|
+
</div>
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Correct (destructive action stands out):**
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
<div className={styles.actions}>
|
|
24
|
+
<button className={styles["button-secondary"]}>Cancel</button>
|
|
25
|
+
<button className={styles["button-danger"]}>Delete Account</button>
|
|
26
|
+
</div>
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Reference: [Von Restorff Effect](https://lawsofux.com/von-restorff-effect/)
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Show Incomplete State to Drive Completion
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: ux, zeigarnik, incomplete, engagement
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Show Incomplete State to Drive Completion
|
|
8
|
+
|
|
9
|
+
People remember incomplete tasks better than completed ones. Use this to drive engagement.
|
|
10
|
+
|
|
11
|
+
**Incorrect (no indication of incomplete profile):**
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
function Dashboard() {
|
|
15
|
+
return <DashboardContent />;
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (incomplete state visible):**
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
function Dashboard({ profile }) {
|
|
23
|
+
return (
|
|
24
|
+
<div>
|
|
25
|
+
{!profile.isComplete && (
|
|
26
|
+
<Banner>
|
|
27
|
+
Complete your profile — {profile.completionPercent}% done
|
|
28
|
+
</Banner>
|
|
29
|
+
)}
|
|
30
|
+
<DashboardContent />
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Reference: [Zeigarnik Effect](https://lawsofux.com/zeigarnik-effect/)
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Animate Shadows via Pseudo-Element Opacity
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: visual, shadow, animation, performance
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Animate Shadows via Pseudo-Element Opacity
|
|
8
|
+
|
|
9
|
+
Transitioning box-shadow directly forces expensive repaints. Instead, put the target shadow on a pseudo-element and animate its opacity.
|
|
10
|
+
|
|
11
|
+
**Incorrect (animating box-shadow):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.card {
|
|
15
|
+
box-shadow: var(--shadow-1);
|
|
16
|
+
transition: box-shadow 0.2s ease;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.card:hover {
|
|
20
|
+
box-shadow: var(--shadow-3);
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Correct (pseudo-element opacity):**
|
|
25
|
+
|
|
26
|
+
```css
|
|
27
|
+
.card {
|
|
28
|
+
position: relative;
|
|
29
|
+
box-shadow: var(--shadow-1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.card::after {
|
|
33
|
+
content: "";
|
|
34
|
+
position: absolute;
|
|
35
|
+
inset: 0;
|
|
36
|
+
border-radius: inherit;
|
|
37
|
+
box-shadow: var(--shadow-3);
|
|
38
|
+
opacity: 0;
|
|
39
|
+
transition: opacity 0.2s ease;
|
|
40
|
+
pointer-events: none;
|
|
41
|
+
z-index: -1;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.card:hover::after {
|
|
45
|
+
opacity: 1;
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Reference: [Designing Beautiful Shadows in CSS](https://www.joshwcomeau.com/css/designing-shadows/)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Semi-Transparent Borders for Subtle Separation
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: visual, border, alpha, separation
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Use Semi-Transparent Borders for Subtle Separation
|
|
8
|
+
|
|
9
|
+
Semi-transparent borders adapt to any background color and create subtle, non-jarring separation.
|
|
10
|
+
|
|
11
|
+
**Incorrect (hardcoded border color):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.card {
|
|
15
|
+
border: 1px solid #e5e5e5;
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (alpha border):**
|
|
20
|
+
|
|
21
|
+
```css
|
|
22
|
+
.card {
|
|
23
|
+
border: 1px solid var(--gray-a4);
|
|
24
|
+
}
|
|
25
|
+
```
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Full Shadow Anatomy on Buttons
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: visual, shadow, button, depth, gradient
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Use Full Shadow Anatomy on Buttons
|
|
8
|
+
|
|
9
|
+
A polished button uses six layered techniques, not just a single box-shadow.
|
|
10
|
+
|
|
11
|
+
1. **Outer cut shadow** — 0.5px dark box-shadow to "cut" the button into the surface
|
|
12
|
+
2. **Inner ambient highlight** — 1px inset box-shadow on all sides for environmental light reflections
|
|
13
|
+
3. **Inner top highlight** — 1px inset top highlight for the primary light source from above
|
|
14
|
+
4. **Layered depth shadows** — At least 3 external shadows for natural lighting
|
|
15
|
+
5. **Text drop-shadow** — Drop-shadow on text/icons for better contrast against the button background
|
|
16
|
+
6. **Subtle gradient background** — If you can tell there's a gradient, it's too much
|
|
17
|
+
|
|
18
|
+
**Incorrect (flat button):**
|
|
19
|
+
|
|
20
|
+
```css
|
|
21
|
+
.button {
|
|
22
|
+
background: var(--gray-12);
|
|
23
|
+
color: var(--gray-1);
|
|
24
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Correct (full shadow anatomy):**
|
|
29
|
+
|
|
30
|
+
```css
|
|
31
|
+
.button {
|
|
32
|
+
background: linear-gradient(
|
|
33
|
+
to bottom,
|
|
34
|
+
color-mix(in srgb, var(--gray-12) 100%, white 4%),
|
|
35
|
+
var(--gray-12)
|
|
36
|
+
);
|
|
37
|
+
color: var(--gray-1);
|
|
38
|
+
box-shadow:
|
|
39
|
+
0 0 0 0.5px rgba(0, 0, 0, 0.3),
|
|
40
|
+
inset 0 0 0 1px rgba(255, 255, 255, 0.04),
|
|
41
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.07),
|
|
42
|
+
0 1px 2px rgba(0, 0, 0, 0.1),
|
|
43
|
+
0 2px 4px rgba(0, 0, 0, 0.06),
|
|
44
|
+
0 4px 8px rgba(0, 0, 0, 0.03);
|
|
45
|
+
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Reference: [@PixelJanitor](https://threadreaderapp.com/thread/1623358514440859649)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Concentric Border Radius for Nested Elements
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: visual, border-radius, concentric, nesting
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Concentric Border Radius for Nested Elements
|
|
8
|
+
|
|
9
|
+
When nesting rounded elements, inner radius must equal outer radius minus the gap. Same radius on both creates uneven curves.
|
|
10
|
+
|
|
11
|
+
**Incorrect (same radius on both):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.outer {
|
|
15
|
+
border-radius: 16px;
|
|
16
|
+
padding: 8px;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.inner {
|
|
20
|
+
border-radius: 16px;
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
**Correct (concentric radius):**
|
|
25
|
+
|
|
26
|
+
```css
|
|
27
|
+
.outer {
|
|
28
|
+
--padding: 8px;
|
|
29
|
+
--inner-radius: 8px;
|
|
30
|
+
|
|
31
|
+
border-radius: calc(var(--inner-radius) + var(--padding));
|
|
32
|
+
padding: var(--padding);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.inner {
|
|
36
|
+
border-radius: var(--inner-radius);
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Reference: [Concentric Border Radius](https://jakub.kr/work/concentric-border-radius)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use a Consistent Spacing Scale
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: visual, spacing, scale, consistency
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Use a Consistent Spacing Scale
|
|
8
|
+
|
|
9
|
+
Don't use arbitrary pixel values for spacing. Define a scale and stick to it throughout the UI.
|
|
10
|
+
|
|
11
|
+
**Incorrect (arbitrary values):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.header { padding: 17px; }
|
|
15
|
+
.card { margin-bottom: 13px; }
|
|
16
|
+
.section { gap: 22px; }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (consistent scale):**
|
|
20
|
+
|
|
21
|
+
```css
|
|
22
|
+
:root {
|
|
23
|
+
--space-1: 4px;
|
|
24
|
+
--space-2: 8px;
|
|
25
|
+
--space-3: 12px;
|
|
26
|
+
--space-4: 16px;
|
|
27
|
+
--space-5: 24px;
|
|
28
|
+
--space-6: 32px;
|
|
29
|
+
--space-7: 48px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.header { padding: var(--space-4); }
|
|
33
|
+
.card { margin-bottom: var(--space-3); }
|
|
34
|
+
.section { gap: var(--space-5); }
|
|
35
|
+
```
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Layer Multiple Shadows for Realistic Depth
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: visual, shadow, layered, depth
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Layer Multiple Shadows for Realistic Depth
|
|
8
|
+
|
|
9
|
+
A single box-shadow looks flat. Layer multiple shadows with increasing blur and decreasing opacity to mimic real light.
|
|
10
|
+
|
|
11
|
+
**Incorrect (single flat shadow):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.card {
|
|
15
|
+
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (layered shadows):**
|
|
20
|
+
|
|
21
|
+
```css
|
|
22
|
+
.card {
|
|
23
|
+
box-shadow:
|
|
24
|
+
0 1px 2px rgba(0, 0, 0, 0.06),
|
|
25
|
+
0 4px 8px rgba(0, 0, 0, 0.04),
|
|
26
|
+
0 12px 24px rgba(0, 0, 0, 0.03);
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Reference: [Designing Beautiful Shadows in CSS](https://www.joshwcomeau.com/css/designing-shadows/)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Use Neutral Colors for Shadows, Not Pure Black
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: visual, shadow, color, neutral
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Use Neutral Colors for Shadows, Not Pure Black
|
|
8
|
+
|
|
9
|
+
Pure black shadows look harsh and artificial. Use deep neutrals or semi-transparent dark colors.
|
|
10
|
+
|
|
11
|
+
**Incorrect (pure black):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.card {
|
|
15
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (neutral shadow):**
|
|
20
|
+
|
|
21
|
+
```css
|
|
22
|
+
.card {
|
|
23
|
+
box-shadow: 0 4px 12px rgba(17, 24, 39, 0.08);
|
|
24
|
+
}
|
|
25
|
+
```
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Consistent Shadow Direction Across UI
|
|
3
|
+
impact: HIGH
|
|
4
|
+
tags: visual, shadow, direction, light-source
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Consistent Shadow Direction Across UI
|
|
8
|
+
|
|
9
|
+
All shadows must share the same offset direction to imply a single light source. Mixed directions feel broken.
|
|
10
|
+
|
|
11
|
+
**Incorrect (conflicting light sources):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
.card { box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); }
|
|
15
|
+
.modal { box-shadow: 4px 0 8px rgba(0, 0, 0, 0.1); }
|
|
16
|
+
.tooltip { box-shadow: 0 -4px 8px rgba(0, 0, 0, 0.1); }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (consistent top-down light):**
|
|
20
|
+
|
|
21
|
+
```css
|
|
22
|
+
.card { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); }
|
|
23
|
+
.modal { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); }
|
|
24
|
+
.tooltip { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); }
|
|
25
|
+
```
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Shadow Size Indicates Elevation
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: visual, shadow, elevation, hierarchy
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Shadow Size Indicates Elevation
|
|
8
|
+
|
|
9
|
+
Larger blur and offset means higher elevation. Use a consistent shadow scale across your UI.
|
|
10
|
+
|
|
11
|
+
**Correct (elevation scale):**
|
|
12
|
+
|
|
13
|
+
```css
|
|
14
|
+
:root {
|
|
15
|
+
--shadow-1: 0 1px 2px rgba(0, 0, 0, 0.05);
|
|
16
|
+
--shadow-2: 0 2px 8px rgba(0, 0, 0, 0.08);
|
|
17
|
+
--shadow-3: 0 8px 24px rgba(0, 0, 0, 0.12);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.card { box-shadow: var(--shadow-1); }
|
|
21
|
+
.dropdown { box-shadow: var(--shadow-2); }
|
|
22
|
+
.modal { box-shadow: var(--shadow-3); }
|
|
23
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Sound Duration Matches Action Duration
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: weight, duration, action
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Sound Duration Matches Action Duration
|
|
8
|
+
|
|
9
|
+
Sound duration should match action duration.
|
|
10
|
+
|
|
11
|
+
**Incorrect (long sound for instant action):**
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
function handleClick() {
|
|
15
|
+
playSound("long-whoosh"); // 2000ms
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Correct (matched duration):**
|
|
20
|
+
|
|
21
|
+
```tsx
|
|
22
|
+
function handleClick() {
|
|
23
|
+
playSound("click"); // 50ms
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function handleUpload() {
|
|
27
|
+
playSound("upload-progress"); // Matches upload duration
|
|
28
|
+
}
|
|
29
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Match Sound Weight to Action
|
|
3
|
+
impact: MEDIUM
|
|
4
|
+
tags: weight, action, importance
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Match Sound Weight to Action
|
|
8
|
+
|
|
9
|
+
Sound weight should match action importance.
|
|
10
|
+
|
|
11
|
+
**Incorrect (fanfare for toggle):**
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
function handleToggle() {
|
|
15
|
+
playSound("triumphant-fanfare");
|
|
16
|
+
setEnabled(!enabled);
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Correct (weight matches action):**
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
function handleToggle() {
|
|
24
|
+
playSound("soft-click");
|
|
25
|
+
setEnabled(!enabled);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function handlePurchase() {
|
|
29
|
+
playSound("success-chime");
|
|
30
|
+
completePurchase();
|
|
31
|
+
}
|
|
32
|
+
```
|