get-shit-pretty 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +15 -9
- package/agents/{gsp-accessibility-auditor.md → gsp-auditor.md} +17 -14
- package/agents/gsp-brand-auditor.md +97 -0
- package/agents/gsp-brand-strategist.md +64 -27
- package/agents/{gsp-design-engineer.md → gsp-builder.md} +12 -9
- package/agents/gsp-campaign-director.md +50 -11
- package/agents/gsp-codebase-scanner.md +171 -0
- package/agents/gsp-critic.md +18 -13
- package/agents/gsp-designer.md +126 -0
- package/agents/gsp-identity-designer.md +90 -0
- package/agents/gsp-project-researcher.md +102 -0
- package/agents/gsp-researcher.md +54 -18
- package/agents/gsp-reviewer.md +66 -0
- package/agents/gsp-scoper.md +103 -0
- package/agents/gsp-system-architect.md +91 -26
- package/agents/gsp-verbal-strategist.md +84 -0
- package/bin/install.js +161 -5
- package/commands/gsp/brand-audit.md +116 -0
- package/commands/gsp/brand-discover.md +17 -0
- package/commands/gsp/brand-identity.md +200 -0
- package/commands/gsp/brand-patterns.md +223 -0
- package/commands/gsp/brand-research.md +99 -0
- package/commands/gsp/brand-strategy.md +140 -0
- package/commands/gsp/brand-system.md +17 -0
- package/commands/gsp/brand-verbal.md +94 -0
- package/commands/gsp/brand.md +9 -83
- package/commands/gsp/brief.md +142 -0
- package/commands/gsp/build.md +49 -41
- package/commands/gsp/critique.md +140 -0
- package/commands/gsp/design.md +65 -50
- package/commands/gsp/discover.md +17 -0
- package/commands/gsp/doctor.md +319 -0
- package/commands/gsp/help.md +85 -38
- package/commands/gsp/identity.md +18 -0
- package/commands/gsp/launch.md +55 -35
- package/commands/gsp/new-project.md +5 -86
- package/commands/gsp/new.md +237 -0
- package/commands/gsp/plan.md +18 -0
- package/commands/gsp/progress.md +58 -26
- package/commands/gsp/research.md +91 -34
- package/commands/gsp/review.md +115 -59
- package/commands/gsp/strategy.md +18 -0
- package/commands/gsp/system.md +8 -65
- package/commands/gsp/update.md +102 -0
- package/commands/gsp/verbal.md +18 -0
- package/package.json +2 -2
- package/prompts/01-design-system-architect.md +35 -3
- package/prompts/03-ui-ux-pattern-master.md +11 -1
- package/prompts/09-design-to-code-translator.md +9 -0
- package/prompts/10-project-scoper.md +51 -0
- package/prompts/11-deliverable-reviewer.md +58 -0
- package/prompts/12-project-researcher.md +57 -0
- package/references/brand-archetypes.md +151 -0
- package/references/brand-prism.md +138 -0
- package/references/chunk-format.md +48 -0
- package/references/design-trends.md +47 -0
- package/references/positioning-frameworks.md +197 -0
- package/references/questioning.md +1 -1
- package/references/trends/aurora-gradients.md +245 -0
- package/references/trends/bento-grid.md +473 -0
- package/references/trends/claymorphism.md +232 -0
- package/references/trends/dark-mode-oled.md +282 -0
- package/references/trends/glassmorphism.md +455 -0
- package/references/trends/kinetic-typography.md +277 -0
- package/references/trends/liquid-glass.md +236 -0
- package/references/trends/micro-interactions.md +307 -0
- package/references/trends/neubrutalism.md +276 -0
- package/references/voice-tone.md +193 -0
- package/scripts/gsp-statusline.js +1 -1
- package/templates/branding/brief.md +74 -0
- package/templates/branding/config.json +26 -0
- package/templates/branding/roadmap.md +43 -0
- package/templates/branding/state.md +29 -0
- package/templates/changelog.md +4 -0
- package/templates/codebase-inventory.md +71 -0
- package/templates/exports-index.md +93 -0
- package/templates/manifest.md +19 -0
- package/templates/phases/brief.md +53 -0
- package/templates/phases/build.md +24 -48
- package/templates/phases/critique.md +68 -0
- package/templates/phases/design.md +54 -32
- package/templates/phases/discover.md +60 -0
- package/templates/phases/identity.md +78 -0
- package/templates/phases/launch.md +48 -55
- package/templates/phases/research.md +75 -47
- package/templates/phases/review.md +27 -75
- package/templates/phases/strategy.md +67 -0
- package/templates/phases/system.md +84 -78
- package/templates/phases/verbal.md +63 -0
- package/templates/{project.md → projects/brief.md} +13 -17
- package/templates/projects/config.json +32 -0
- package/templates/projects/roadmap.md +59 -0
- package/templates/{state.md → projects/state.md} +19 -9
- package/agents/gsp-spec-engineer.md +0 -121
- package/agents/gsp-ui-designer.md +0 -59
- package/commands/gsp/spec.md +0 -88
- package/templates/config.json +0 -26
- package/templates/phases/brand.md +0 -60
- package/templates/phases/spec.md +0 -46
- package/templates/roadmap.md +0 -62
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
# Micro-Interactions
|
|
2
|
+
|
|
3
|
+
> Small, specific UI responses to user actions — hover, click, scroll, focus. The invisible details that make an interface feel alive and polished.
|
|
4
|
+
|
|
5
|
+
Last verified: 2026-03-04
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Visual Characteristics
|
|
10
|
+
|
|
11
|
+
- Subtle motion responses tied to specific user input
|
|
12
|
+
- State-transition feedback: hover, active, focus, loading, success/error
|
|
13
|
+
- Timing precision in the 80-300ms range
|
|
14
|
+
- Natural easing curves that match human expectation
|
|
15
|
+
- 75% of customer-facing apps will incorporate micro-interactions as standard (Gartner, 2025)
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Timing Guidelines
|
|
20
|
+
|
|
21
|
+
| Interaction | Duration | Rationale |
|
|
22
|
+
|-------------|----------|-----------|
|
|
23
|
+
| Button press feedback | 80-120ms | Must feel instant — finger-to-response |
|
|
24
|
+
| Hover feedback | 100-150ms | Quick enough to feel responsive, slow enough to perceive |
|
|
25
|
+
| State transitions | 200-300ms | Visible change without feeling sluggish |
|
|
26
|
+
| Page transitions | 300-500ms | Enough time for spatial orientation |
|
|
27
|
+
| Micro-interaction (general) | 120-220ms | UX research sweet spot (NN/g, Material Design) |
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## CSS Implementation
|
|
32
|
+
|
|
33
|
+
### Button Hover Lift
|
|
34
|
+
|
|
35
|
+
```css
|
|
36
|
+
.micro-button {
|
|
37
|
+
transition: transform 0.15s ease-out, box-shadow 0.15s ease-out;
|
|
38
|
+
}
|
|
39
|
+
.micro-button:hover {
|
|
40
|
+
transform: translateY(-2px);
|
|
41
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
42
|
+
}
|
|
43
|
+
.micro-button:active {
|
|
44
|
+
transform: translateY(0px) scale(0.98);
|
|
45
|
+
transition-duration: 0.08s;
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Card Hover
|
|
50
|
+
|
|
51
|
+
```css
|
|
52
|
+
.micro-card {
|
|
53
|
+
transition: transform 0.2s ease-out, box-shadow 0.2s ease-out;
|
|
54
|
+
}
|
|
55
|
+
.micro-card:hover {
|
|
56
|
+
transform: translateY(-4px);
|
|
57
|
+
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.1);
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Checkbox Tick Animation
|
|
62
|
+
|
|
63
|
+
```css
|
|
64
|
+
.checkmark path {
|
|
65
|
+
stroke-dasharray: 24;
|
|
66
|
+
stroke-dashoffset: 24;
|
|
67
|
+
transition: stroke-dashoffset 0.3s cubic-bezier(0.65, 0, 0.35, 1);
|
|
68
|
+
}
|
|
69
|
+
.checkbox:checked + .checkmark path {
|
|
70
|
+
stroke-dashoffset: 0;
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Toggle Switch
|
|
75
|
+
|
|
76
|
+
```css
|
|
77
|
+
.toggle-thumb {
|
|
78
|
+
transition: transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
79
|
+
}
|
|
80
|
+
.toggle:checked .toggle-thumb {
|
|
81
|
+
transform: translateX(24px);
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Skeleton Shimmer (Loading)
|
|
86
|
+
|
|
87
|
+
```css
|
|
88
|
+
.skeleton {
|
|
89
|
+
background: linear-gradient(90deg,
|
|
90
|
+
rgba(0, 0, 0, 0.06) 25%,
|
|
91
|
+
rgba(0, 0, 0, 0.1) 50%,
|
|
92
|
+
rgba(0, 0, 0, 0.06) 75%);
|
|
93
|
+
background-size: 200% 100%;
|
|
94
|
+
animation: shimmer 1.5s linear infinite;
|
|
95
|
+
}
|
|
96
|
+
@keyframes shimmer {
|
|
97
|
+
from { background-position: 200% 0; }
|
|
98
|
+
to { background-position: -200% 0; }
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Interactive Cursor
|
|
103
|
+
|
|
104
|
+
```css
|
|
105
|
+
.cursor-follower {
|
|
106
|
+
width: 32px;
|
|
107
|
+
height: 32px;
|
|
108
|
+
border-radius: 50%;
|
|
109
|
+
border: 2px solid currentColor;
|
|
110
|
+
transition: width 0.2s ease, height 0.2s ease;
|
|
111
|
+
pointer-events: none;
|
|
112
|
+
}
|
|
113
|
+
.cursor-follower.hovering-link {
|
|
114
|
+
width: 64px;
|
|
115
|
+
height: 64px;
|
|
116
|
+
mix-blend-mode: difference;
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Easing Reference
|
|
121
|
+
|
|
122
|
+
| Feel | Cubic-Bezier | Use |
|
|
123
|
+
|------|-------------|-----|
|
|
124
|
+
| Snappy | `cubic-bezier(0.2, 0, 0, 1)` | General UI transitions |
|
|
125
|
+
| Bouncy | `cubic-bezier(0.34, 1.56, 0.64, 1)` | Toggles, playful elements |
|
|
126
|
+
| Smooth exit | `cubic-bezier(0.16, 1, 0.3, 1)` | Elements leaving viewport |
|
|
127
|
+
| Elastic | `cubic-bezier(0.68, -0.55, 0.27, 1.55)` | Attention-grabbing moments |
|
|
128
|
+
| Linear | `linear` | Progress bars, continuous motion |
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Implementation Guide
|
|
133
|
+
|
|
134
|
+
### Step-by-step
|
|
135
|
+
|
|
136
|
+
1. Identify every interactive element: buttons, cards, inputs, toggles, links
|
|
137
|
+
2. Define the interaction trigger: hover, click/tap, focus, scroll, state change
|
|
138
|
+
3. Choose the appropriate timing from the guidelines table above
|
|
139
|
+
4. Select an easing curve matching the desired feel (snappy for UI, bouncy for playful)
|
|
140
|
+
5. Animate only `transform` and `opacity` — avoid `width`, `height`, `top`, `left`
|
|
141
|
+
6. Add `:active` state for press feedback (scale down or translate)
|
|
142
|
+
7. Test on both mouse (hover) and touch (tap) — touch devices skip hover
|
|
143
|
+
|
|
144
|
+
### Progressive Enhancement
|
|
145
|
+
|
|
146
|
+
```css
|
|
147
|
+
/* Baseline: instant state changes */
|
|
148
|
+
.micro-button {
|
|
149
|
+
/* No transition — works in all browsers */
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* Enhanced: smooth transitions when motion is acceptable */
|
|
153
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
154
|
+
.micro-button {
|
|
155
|
+
transition: transform 0.15s ease-out, box-shadow 0.15s ease-out;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Framework Notes
|
|
161
|
+
|
|
162
|
+
#### React + Framer Motion
|
|
163
|
+
|
|
164
|
+
```tsx
|
|
165
|
+
import { motion } from 'framer-motion';
|
|
166
|
+
|
|
167
|
+
export function MicroButton({ children, onClick }) {
|
|
168
|
+
return (
|
|
169
|
+
<motion.button
|
|
170
|
+
onClick={onClick}
|
|
171
|
+
whileHover={{ y: -2, boxShadow: '0 4px 12px rgba(0,0,0,0.15)' }}
|
|
172
|
+
whileTap={{ y: 0, scale: 0.98 }}
|
|
173
|
+
transition={{ duration: 0.15, ease: 'easeOut' }}
|
|
174
|
+
className="px-6 py-3 bg-indigo-600 text-white rounded-xl"
|
|
175
|
+
>
|
|
176
|
+
{children}
|
|
177
|
+
</motion.button>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
#### React + Tailwind CSS
|
|
183
|
+
|
|
184
|
+
```tsx
|
|
185
|
+
export function MicroCard({ children }) {
|
|
186
|
+
return (
|
|
187
|
+
<div className="transition-all duration-200 ease-out hover:-translate-y-1 hover:shadow-lg active:translate-y-0 active:scale-[0.98] active:duration-75 rounded-2xl bg-white p-6 shadow-md">
|
|
188
|
+
{children}
|
|
189
|
+
</div>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
#### React Native
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
import Animated, { useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
|
|
198
|
+
import { Pressable } from 'react-native';
|
|
199
|
+
|
|
200
|
+
export function MicroButton({ title, onPress }) {
|
|
201
|
+
const scale = useSharedValue(1);
|
|
202
|
+
const animatedStyle = useAnimatedStyle(() => ({
|
|
203
|
+
transform: [{ scale: scale.value }],
|
|
204
|
+
}));
|
|
205
|
+
|
|
206
|
+
return (
|
|
207
|
+
<Pressable
|
|
208
|
+
onPressIn={() => { scale.value = withSpring(0.96, { damping: 15 }); }}
|
|
209
|
+
onPressOut={() => { scale.value = withSpring(1, { damping: 15 }); }}
|
|
210
|
+
onPress={onPress}
|
|
211
|
+
>
|
|
212
|
+
<Animated.View style={[styles.button, animatedStyle]}>
|
|
213
|
+
<Text>{title}</Text>
|
|
214
|
+
</Animated.View>
|
|
215
|
+
</Pressable>
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Common Pitfalls
|
|
221
|
+
|
|
222
|
+
1. **Hover-only interactions**: touch devices don't have hover. Always pair hover effects with active/tap states for mobile parity.
|
|
223
|
+
2. **Animating layout properties**: `width`, `height`, `top`, `left`, `margin`, `padding` trigger layout recalculation. Stick to `transform` and `opacity`.
|
|
224
|
+
3. **Too slow**: micro-interactions above 300ms feel sluggish. The "micro" means fast — 100-200ms for most.
|
|
225
|
+
4. **Too many at once**: if every element bounces, glows, and scales simultaneously, the UI feels chaotic. Apply micro-interactions selectively to primary interactive elements.
|
|
226
|
+
5. **No active/press state**: a button that hovers but doesn't respond to click feels broken. Always include `:active` feedback.
|
|
227
|
+
|
|
228
|
+
---
|
|
229
|
+
|
|
230
|
+
## Examples Gallery
|
|
231
|
+
|
|
232
|
+
| Site | What They Do Well | Screenshot Description |
|
|
233
|
+
|------|-------------------|----------------------|
|
|
234
|
+
| Stripe | Precise hover states on pricing cards — subtle lift, shadow expansion, gradient border glow | Pricing page with elevated hovered card |
|
|
235
|
+
| Linear | Toggle, checkbox, and dropdown animations with spring physics — every element feels tactile | Settings panel with bouncy toggle switches |
|
|
236
|
+
| Vercel | Skeleton shimmer loading states and smooth page transitions | Dashboard with skeleton placeholders resolving to content |
|
|
237
|
+
| Apple | iOS-quality button press feedback (scale 0.97) and page transition choreography on web | Product page with precise interaction states |
|
|
238
|
+
| Awwwards — Locomotive Scroll | Custom cursor interactions, magnetic buttons, and parallax micro-effects | Agency site with cursor that morphs over interactive elements |
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## Accessibility
|
|
243
|
+
|
|
244
|
+
- **Reduced motion**: wrap all transitions in `@media (prefers-reduced-motion: no-preference)`. For `reduce`: instant state changes, no animation.
|
|
245
|
+
- **Focus indicators**: animated focus rings must still meet 3:1 contrast ratio. Use `outline` (not `box-shadow`) for reliable focus visibility.
|
|
246
|
+
- **Timing**: ensure animations complete before the next interaction is expected — don't delay functionality behind animation.
|
|
247
|
+
- **Touch targets**: hover-lift effects can visually move elements. Ensure tap targets remain at least 44x44px regardless of visual position.
|
|
248
|
+
- **Loading states**: skeleton shimmer should eventually resolve. Add `aria-busy="true"` to loading containers.
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Performance
|
|
253
|
+
|
|
254
|
+
- **Transform + opacity only**: these are GPU-composited and stay off the main thread
|
|
255
|
+
- **`will-change` sparingly**: apply to elements that will animate, not globally. Remove after animation completes for long-lived elements.
|
|
256
|
+
- **Frame budget**: 16ms per frame at 60fps. Micro-interactions at 100-200ms use 6-12 frames — keep each frame under budget.
|
|
257
|
+
- **Batch transitions**: if multiple elements animate simultaneously, ensure total compositing cost stays low. Profile with Chrome DevTools Performance panel.
|
|
258
|
+
- **Mobile**: reduce hover animations (they don't apply anyway) and ensure tap feedback runs at 60fps.
|
|
259
|
+
|
|
260
|
+
---
|
|
261
|
+
|
|
262
|
+
## When to Use / When to Avoid
|
|
263
|
+
|
|
264
|
+
### Use When
|
|
265
|
+
- Every interactive element benefits from some micro-interaction
|
|
266
|
+
- Loading states, form validation feedback, navigation transitions
|
|
267
|
+
- Success/error confirmation animations
|
|
268
|
+
- Hover states on cards, buttons, and links
|
|
269
|
+
|
|
270
|
+
### Avoid When
|
|
271
|
+
- Decorative-only motion with no functional purpose
|
|
272
|
+
- Dense data displays where motion adds cognitive load
|
|
273
|
+
- High-frequency actions (typing, scrolling) where animation would create lag
|
|
274
|
+
- Accessibility-critical interfaces where motion could trigger vestibular disorders
|
|
275
|
+
|
|
276
|
+
---
|
|
277
|
+
|
|
278
|
+
## Design Tokens
|
|
279
|
+
|
|
280
|
+
```json
|
|
281
|
+
{
|
|
282
|
+
"micro": {
|
|
283
|
+
"duration-instant": "80ms",
|
|
284
|
+
"duration-fast": "120ms",
|
|
285
|
+
"duration-normal": "200ms",
|
|
286
|
+
"duration-slow": "300ms",
|
|
287
|
+
"duration-page": "400ms",
|
|
288
|
+
"ease-snappy": "cubic-bezier(0.2, 0, 0, 1)",
|
|
289
|
+
"ease-bouncy": "cubic-bezier(0.34, 1.56, 0.64, 1)",
|
|
290
|
+
"ease-smooth-exit": "cubic-bezier(0.16, 1, 0.3, 1)",
|
|
291
|
+
"ease-elastic": "cubic-bezier(0.68, -0.55, 0.27, 1.55)",
|
|
292
|
+
"hover-lift": "-2px",
|
|
293
|
+
"hover-shadow": "0 4px 12px rgba(0,0,0,0.15)",
|
|
294
|
+
"active-scale": "0.98",
|
|
295
|
+
"card-lift": "-4px",
|
|
296
|
+
"card-shadow": "0 12px 24px rgba(0,0,0,0.1)"
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Related
|
|
304
|
+
|
|
305
|
+
- [Kinetic Typography](./kinetic-typography.md) — complementary animation system for text
|
|
306
|
+
- [Bento Grid](./bento-grid.md) — card hover and entrance animations pair well
|
|
307
|
+
- [Claymorphism](./claymorphism.md) — tactile squish feedback enhances the clay feel
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# Neubrutalism (Neo-Brutalism)
|
|
2
|
+
|
|
3
|
+
> Bold, flat, high-contrast aesthetic with thick borders and hard-offset shadows — intentionally raw but usable. Anti-polish meets modern UX.
|
|
4
|
+
|
|
5
|
+
Last verified: 2026-03-04
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Visual Characteristics
|
|
10
|
+
|
|
11
|
+
- Flat colors — no gradients, no blur, no transparency
|
|
12
|
+
- Thick black borders (2-4px)
|
|
13
|
+
- Hard-offset box shadows with zero blur radius
|
|
14
|
+
- High contrast — pure black + bright saturated accent
|
|
15
|
+
- Geometric shapes, sharp corners or intentionally chunky radius (8-12px)
|
|
16
|
+
- Monospaced or grotesque sans-serif typography
|
|
17
|
+
- Popularized by Gumroad, Figma, Notion Calendar
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## CSS Implementation
|
|
22
|
+
|
|
23
|
+
```css
|
|
24
|
+
/* Neubrutalist card */
|
|
25
|
+
.neu-card {
|
|
26
|
+
background: #ffffff;
|
|
27
|
+
border: 3px solid #000000;
|
|
28
|
+
border-radius: 12px;
|
|
29
|
+
box-shadow: 4px 4px 0px 0px #000000;
|
|
30
|
+
padding: 24px;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/* Neubrutalist button */
|
|
34
|
+
.neu-button {
|
|
35
|
+
background: #FFD700;
|
|
36
|
+
color: #000000;
|
|
37
|
+
border: 3px solid #000000;
|
|
38
|
+
border-radius: 8px;
|
|
39
|
+
box-shadow: 4px 4px 0px 0px #000000;
|
|
40
|
+
padding: 12px 24px;
|
|
41
|
+
font-weight: 700;
|
|
42
|
+
font-family: 'Space Grotesk', 'Inter', sans-serif;
|
|
43
|
+
cursor: pointer;
|
|
44
|
+
transition: transform 0.1s ease, box-shadow 0.1s ease;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.neu-button:hover {
|
|
48
|
+
transform: translate(2px, 2px);
|
|
49
|
+
box-shadow: 2px 2px 0px 0px #000000;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.neu-button:active {
|
|
53
|
+
transform: translate(4px, 4px);
|
|
54
|
+
box-shadow: 0px 0px 0px 0px #000000;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/* Neubrutalist input */
|
|
58
|
+
.neu-input {
|
|
59
|
+
border: 3px solid #000000;
|
|
60
|
+
border-radius: 8px;
|
|
61
|
+
padding: 12px 16px;
|
|
62
|
+
font-size: 16px;
|
|
63
|
+
box-shadow: 3px 3px 0px 0px #000000;
|
|
64
|
+
outline: none;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.neu-input:focus {
|
|
68
|
+
box-shadow: 3px 3px 0px 0px #4169E1;
|
|
69
|
+
border-color: #4169E1;
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Shadow Scale
|
|
74
|
+
|
|
75
|
+
| Token | Value | Use |
|
|
76
|
+
|-------|-------|-----|
|
|
77
|
+
| sm | `2px 2px 0px 0px #000` | Small elements, tags, chips |
|
|
78
|
+
| md | `4px 4px 0px 0px #000` | Cards, buttons, inputs |
|
|
79
|
+
| lg | `6px 6px 0px 0px #000` | Featured cards, hero elements |
|
|
80
|
+
| xl | `8px 8px 0px 0px #000` | Modals, popovers |
|
|
81
|
+
|
|
82
|
+
### Color Palette Pattern
|
|
83
|
+
- Background: `#FFFFFF` or warm off-white `#FFF8F0`
|
|
84
|
+
- Text: `#000000`
|
|
85
|
+
- Accents: `#FFD700` (yellow), `#FF6B6B` (red), `#4169E1` (blue), `#50C878` (green), `#FF69B4` (pink)
|
|
86
|
+
- No gradients, no opacity, no blur
|
|
87
|
+
|
|
88
|
+
### Typography
|
|
89
|
+
- Primary: Space Grotesk, Space Mono, Inter, or DM Sans
|
|
90
|
+
- Headings: Bold/Black weight, 48-96px for hero
|
|
91
|
+
- Body: Regular weight, 16-18px
|
|
92
|
+
- Monospaced accent: JetBrains Mono, IBM Plex Mono
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## Implementation Guide
|
|
97
|
+
|
|
98
|
+
### Step-by-step
|
|
99
|
+
|
|
100
|
+
1. Set a flat background — white or warm off-white (`#FFF8F0`)
|
|
101
|
+
2. Apply thick borders: `3px solid #000000` to all interactive elements
|
|
102
|
+
3. Add hard-offset box-shadow: `4px 4px 0px 0px #000000` (zero blur is essential)
|
|
103
|
+
4. Choose 1-2 bright accent colors for CTAs and highlights
|
|
104
|
+
5. Set typography: grotesque sans-serif for headings, monospace for accents
|
|
105
|
+
6. Implement shadow-collapse interaction: hover reduces offset, active collapses to zero
|
|
106
|
+
7. Ensure all interactive states (hover, active, focus, disabled) are visually distinct
|
|
107
|
+
|
|
108
|
+
### Progressive Enhancement
|
|
109
|
+
|
|
110
|
+
Neubrutalism works in all browsers with no progressive enhancement needed — it uses only basic CSS properties (border, box-shadow, background-color). No `@supports` queries required.
|
|
111
|
+
|
|
112
|
+
### Framework Notes
|
|
113
|
+
|
|
114
|
+
#### React + Tailwind CSS
|
|
115
|
+
|
|
116
|
+
Tailwind doesn't ship hard-offset shadows by default. Add custom shadow utilities:
|
|
117
|
+
|
|
118
|
+
```js
|
|
119
|
+
// tailwind.config.js
|
|
120
|
+
module.exports = {
|
|
121
|
+
theme: {
|
|
122
|
+
extend: {
|
|
123
|
+
boxShadow: {
|
|
124
|
+
'neu-sm': '2px 2px 0px 0px #000000',
|
|
125
|
+
'neu-md': '4px 4px 0px 0px #000000',
|
|
126
|
+
'neu-lg': '6px 6px 0px 0px #000000',
|
|
127
|
+
'neu-xl': '8px 8px 0px 0px #000000',
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
```tsx
|
|
135
|
+
export function NeuButton({ children }: { children: React.ReactNode }) {
|
|
136
|
+
return (
|
|
137
|
+
<button className="bg-yellow-400 text-black border-[3px] border-black rounded-lg shadow-neu-md px-6 py-3 font-bold font-[Space_Grotesk] transition-all duration-100 hover:translate-x-[2px] hover:translate-y-[2px] hover:shadow-neu-sm active:translate-x-1 active:translate-y-1 active:shadow-none">
|
|
138
|
+
{children}
|
|
139
|
+
</button>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### React Native
|
|
145
|
+
|
|
146
|
+
Neubrutalism translates well to React Native since it uses no advanced CSS:
|
|
147
|
+
|
|
148
|
+
```tsx
|
|
149
|
+
import { Pressable, Text, StyleSheet } from 'react-native';
|
|
150
|
+
|
|
151
|
+
export function NeuButton({ title, onPress }) {
|
|
152
|
+
return (
|
|
153
|
+
<Pressable
|
|
154
|
+
onPress={onPress}
|
|
155
|
+
style={({ pressed }) => [
|
|
156
|
+
styles.button,
|
|
157
|
+
pressed && { transform: [{ translateX: 4 }, { translateY: 4 }], shadowOffset: { width: 0, height: 0 } }
|
|
158
|
+
]}
|
|
159
|
+
>
|
|
160
|
+
<Text style={styles.text}>{title}</Text>
|
|
161
|
+
</Pressable>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const styles = StyleSheet.create({
|
|
166
|
+
button: {
|
|
167
|
+
backgroundColor: '#FFD700',
|
|
168
|
+
borderWidth: 3,
|
|
169
|
+
borderColor: '#000000',
|
|
170
|
+
borderRadius: 8,
|
|
171
|
+
paddingVertical: 12,
|
|
172
|
+
paddingHorizontal: 24,
|
|
173
|
+
shadowColor: '#000000',
|
|
174
|
+
shadowOffset: { width: 4, height: 4 },
|
|
175
|
+
shadowOpacity: 1,
|
|
176
|
+
shadowRadius: 0,
|
|
177
|
+
elevation: 4,
|
|
178
|
+
},
|
|
179
|
+
text: { color: '#000000', fontWeight: '700', fontSize: 16 },
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
#### Vanilla CSS
|
|
184
|
+
|
|
185
|
+
The CSS implementation section above is already vanilla CSS. No additional tooling needed.
|
|
186
|
+
|
|
187
|
+
### Common Pitfalls
|
|
188
|
+
|
|
189
|
+
1. **Adding blur to shadows**: the entire aesthetic depends on `0px` blur radius in box-shadow. Any blur softens the hard offset and breaks the brutalist look.
|
|
190
|
+
2. **Mixing with glassmorphism**: these trends clash fundamentally — glass needs transparency and blur, neubrutalism demands flatness and opacity.
|
|
191
|
+
3. **Inconsistent border width**: mixing 2px and 3px borders within the same UI breaks visual rhythm. Pick one and stick with it.
|
|
192
|
+
4. **Shadow not collapsing on press**: the shadow-to-zero interaction pattern is what makes neubrutalism feel physical. Without it, buttons feel static and the hard shadow looks like a decoration.
|
|
193
|
+
5. **Too many accent colors**: limit to 2-3 bright accents max. More than that reads as chaotic rather than intentionally bold.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Examples Gallery
|
|
198
|
+
|
|
199
|
+
| Site | What They Do Well | Screenshot Description |
|
|
200
|
+
|------|-------------------|----------------------|
|
|
201
|
+
| Gumroad | The canonical neubrutalist product — thick borders, hard shadows, bright yellow accent on every CTA | Product pages with bold cards and shadow-collapse buttons |
|
|
202
|
+
| Figma Community | Bold flat cards with chunky radius and monospace accents — neubrutalism at scale | Community file browser with high-contrast cards |
|
|
203
|
+
| Notion Calendar | Soft neubrutalism variant — slightly rounded, pastel accents with hard shadows | Calendar grid with event chips using hard offsets |
|
|
204
|
+
| Poolsuite | Full commitment — retro-brutalist with monospace type, hot pink/green accents, and zero visual softness | App landing page with maximum contrast |
|
|
205
|
+
| The Whimsical Web (Awwwards) | Experimental neubrutalism with animated shadow offsets and color-shifting accents | Portfolio site with interactive card states |
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## Accessibility
|
|
210
|
+
|
|
211
|
+
- **High contrast by default**: neubrutalism's pure black + white base exceeds WCAG AAA (21:1 ratio). Colored accents on white also tend to pass AA.
|
|
212
|
+
- **Focus indicators**: replace the shadow-collapse focus state with a distinct visual — color-shifted shadow (`3px 3px 0px 0px #4169E1`) plus `border-color` change
|
|
213
|
+
- **Color alone**: don't rely on accent color alone to convey state — combine with shadow offset changes, border changes, or text labels
|
|
214
|
+
- **Motion**: the shadow-collapse animation is brief (100ms) and subtle — generally safe for `prefers-reduced-motion`, but provide instant state change as alternative
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Performance
|
|
219
|
+
|
|
220
|
+
- **Minimal GPU cost**: neubrutalism uses only basic CSS properties (border, box-shadow, background-color). No compositing layers, no blur, no filters.
|
|
221
|
+
- **Most performant trend**: flat colors + hard shadows = zero GPU overhead beyond standard rendering
|
|
222
|
+
- **Safe for low-end devices**: works identically on all hardware tiers
|
|
223
|
+
- **Shadow transition**: `transform` + `box-shadow` transition at 100ms is well within 16ms frame budget
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## When to Use / When to Avoid
|
|
228
|
+
|
|
229
|
+
### Use When
|
|
230
|
+
- SaaS products, developer tools, creative platforms
|
|
231
|
+
- Landing pages, marketing sites with personality
|
|
232
|
+
- Products targeting young/creative audiences
|
|
233
|
+
- Brands that want to stand out against the polished-glass mainstream
|
|
234
|
+
|
|
235
|
+
### Avoid When
|
|
236
|
+
- Luxury brands — hard shadows read as cheap/raw
|
|
237
|
+
- Healthcare, fintech — clashes with trust/security signals
|
|
238
|
+
- Enterprises expecting conservative visual language
|
|
239
|
+
- Products already using glassmorphism — the trends clash fundamentally
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Design Tokens
|
|
244
|
+
|
|
245
|
+
```json
|
|
246
|
+
{
|
|
247
|
+
"neubrutalism": {
|
|
248
|
+
"border-width": "3px",
|
|
249
|
+
"border-color": "#000000",
|
|
250
|
+
"radius-sm": "8px",
|
|
251
|
+
"radius-md": "12px",
|
|
252
|
+
"shadow-sm": "2px 2px 0px 0px #000000",
|
|
253
|
+
"shadow-md": "4px 4px 0px 0px #000000",
|
|
254
|
+
"shadow-lg": "6px 6px 0px 0px #000000",
|
|
255
|
+
"shadow-xl": "8px 8px 0px 0px #000000",
|
|
256
|
+
"bg-primary": "#FFFFFF",
|
|
257
|
+
"bg-warm": "#FFF8F0",
|
|
258
|
+
"text": "#000000",
|
|
259
|
+
"accent-yellow": "#FFD700",
|
|
260
|
+
"accent-red": "#FF6B6B",
|
|
261
|
+
"accent-blue": "#4169E1",
|
|
262
|
+
"accent-green": "#50C878",
|
|
263
|
+
"accent-pink": "#FF69B4",
|
|
264
|
+
"transition-duration": "100ms",
|
|
265
|
+
"transition-easing": "ease"
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Related
|
|
273
|
+
|
|
274
|
+
- [Kinetic Typography](./kinetic-typography.md) — great pairing for bold text effects
|
|
275
|
+
- [Micro-Interactions](./micro-interactions.md) — shadow collapse on press is the signature interaction
|
|
276
|
+
- [Bento Grid](./bento-grid.md) — compatible layout structure for neubrutalist cards
|