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,473 @@
|
|
|
1
|
+
# Bento Grid
|
|
2
|
+
|
|
3
|
+
> Modular asymmetric grid of varying-size cards — inspired by Japanese lunch boxes — that creates visual hierarchy through deliberate size contrast rather than sequential repetition.
|
|
4
|
+
|
|
5
|
+
Last verified: 2026-03-04
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Visual Characteristics
|
|
10
|
+
|
|
11
|
+
- Asymmetric cell sizes with a dominant "anchor" card (typically 2x2 or 3x2) flanked by smaller supporting cards
|
|
12
|
+
- Uniform gap between all cells — 16px or 24px, never mixed within a grid
|
|
13
|
+
- Consistent border-radius across every card in the grid (16–32px, typically 24px)
|
|
14
|
+
- One key message per card — "snackable" information density
|
|
15
|
+
- 4–8 compartments per grid maximum before cognitive load increases
|
|
16
|
+
- 2–3 accent colors with neutral card backgrounds
|
|
17
|
+
- Bold, short headlines inside cards with minimal or zero body text
|
|
18
|
+
- Cells are self-contained units: background, illustration, stat, or short copy — never a continuation of adjacent content
|
|
19
|
+
- Popularized on Apple product pages (iPhone, MacBook Air, Apple Watch feature breakdowns)
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## CSS Implementation
|
|
24
|
+
|
|
25
|
+
### Base Pattern — 12-Column System
|
|
26
|
+
|
|
27
|
+
Apple-style implementations use a 12-column base, which gives precise span control without custom line numbers.
|
|
28
|
+
|
|
29
|
+
```css
|
|
30
|
+
.bento-grid {
|
|
31
|
+
display: grid;
|
|
32
|
+
grid-template-columns: repeat(12, minmax(0, 1fr));
|
|
33
|
+
grid-auto-rows: 90px; /* row rhythm unit — stack multiples for taller cells */
|
|
34
|
+
gap: 24px;
|
|
35
|
+
padding: 24px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/* Anchor card: 6 cols wide, 4 rows tall */
|
|
39
|
+
.bento-anchor {
|
|
40
|
+
grid-column: span 6;
|
|
41
|
+
grid-row: span 4;
|
|
42
|
+
border-radius: 24px;
|
|
43
|
+
padding: 40px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/* Wide card: full width, 2 rows */
|
|
47
|
+
.bento-wide {
|
|
48
|
+
grid-column: span 12;
|
|
49
|
+
grid-row: span 2;
|
|
50
|
+
border-radius: 24px;
|
|
51
|
+
padding: 32px;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Half card: 6 cols, 2 rows */
|
|
55
|
+
.bento-half {
|
|
56
|
+
grid-column: span 6;
|
|
57
|
+
grid-row: span 2;
|
|
58
|
+
border-radius: 24px;
|
|
59
|
+
padding: 32px;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* Quarter card: 3 cols, 2 rows */
|
|
63
|
+
.bento-quarter {
|
|
64
|
+
grid-column: span 3;
|
|
65
|
+
grid-row: span 2;
|
|
66
|
+
border-radius: 24px;
|
|
67
|
+
padding: 24px;
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Responsive Collapse — 12 → 4 → 2 → 1 Columns
|
|
72
|
+
|
|
73
|
+
```css
|
|
74
|
+
/* Desktop default: 12 columns (above) */
|
|
75
|
+
|
|
76
|
+
/* Tablet: 4-column grid */
|
|
77
|
+
@media (max-width: 1024px) {
|
|
78
|
+
.bento-grid {
|
|
79
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
80
|
+
gap: 16px;
|
|
81
|
+
}
|
|
82
|
+
.bento-anchor { grid-column: span 4; grid-row: span 3; }
|
|
83
|
+
.bento-wide { grid-column: span 4; }
|
|
84
|
+
.bento-half { grid-column: span 2; }
|
|
85
|
+
.bento-quarter { grid-column: span 2; }
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Mobile: 2-column grid */
|
|
89
|
+
@media (max-width: 768px) {
|
|
90
|
+
.bento-grid {
|
|
91
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
92
|
+
gap: 12px;
|
|
93
|
+
}
|
|
94
|
+
.bento-anchor { grid-column: span 2; grid-row: span 2; }
|
|
95
|
+
.bento-wide { grid-column: span 2; }
|
|
96
|
+
.bento-half { grid-column: span 2; }
|
|
97
|
+
.bento-quarter { grid-column: span 1; }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* Small mobile: single column */
|
|
101
|
+
@media (max-width: 480px) {
|
|
102
|
+
.bento-grid {
|
|
103
|
+
grid-template-columns: 1fr;
|
|
104
|
+
gap: 12px;
|
|
105
|
+
}
|
|
106
|
+
.bento-anchor,
|
|
107
|
+
.bento-wide,
|
|
108
|
+
.bento-half,
|
|
109
|
+
.bento-quarter {
|
|
110
|
+
grid-column: span 1;
|
|
111
|
+
grid-row: span 1;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Explicit Placement — Precise Control
|
|
117
|
+
|
|
118
|
+
When auto-placement produces gaps, use explicit line numbers instead:
|
|
119
|
+
|
|
120
|
+
```css
|
|
121
|
+
.tile-hero { grid-column: 1 / 7; grid-row: 1 / 3; } /* 6 cols, 2 rows */
|
|
122
|
+
.tile-side-top { grid-column: 7 / 13; grid-row: 1 / 2; } /* 6 cols, 1 row */
|
|
123
|
+
.tile-side-bot { grid-column: 7 / 13; grid-row: 2 / 3; } /* 6 cols, 1 row */
|
|
124
|
+
.tile-full { grid-column: 1 / 13; grid-row: 3 / 4; } /* full width */
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Dense Auto-Placement — Fill Gaps Automatically
|
|
128
|
+
|
|
129
|
+
Use `grid-auto-flow: dense` when card count is dynamic (CMS-driven content):
|
|
130
|
+
|
|
131
|
+
```css
|
|
132
|
+
.bento-grid {
|
|
133
|
+
display: grid;
|
|
134
|
+
grid-template-columns: repeat(12, minmax(0, 1fr));
|
|
135
|
+
grid-auto-flow: dense; /* backfills gaps with smaller items */
|
|
136
|
+
gap: 24px;
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Warning: dense packing reorders visual display without changing DOM order. Audit tab order afterward.
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Implementation Guide
|
|
145
|
+
|
|
146
|
+
### Step-by-step
|
|
147
|
+
|
|
148
|
+
1. Define your grid's column count — use 12 columns for maximum span flexibility or 4 for simpler layouts.
|
|
149
|
+
2. Set `grid-auto-rows` with a base unit (60–100px). Cards then use `grid-row: span N` as multiples.
|
|
150
|
+
3. Classify each card as anchor / wide / half / quarter and apply the corresponding span class.
|
|
151
|
+
4. Apply uniform `gap`, uniform `border-radius`, and `overflow: hidden` on each card.
|
|
152
|
+
5. Test column collapse at 1024px, 768px, and 480px — reduce column count, simplify spans.
|
|
153
|
+
6. If card content has imagery, add `aspect-ratio` so cells do not collapse to zero height during load.
|
|
154
|
+
|
|
155
|
+
### Progressive Enhancement
|
|
156
|
+
|
|
157
|
+
Start with a single-column stacked layout for all breakpoints, then layer in grid behavior:
|
|
158
|
+
|
|
159
|
+
```css
|
|
160
|
+
.bento-grid {
|
|
161
|
+
display: flex;
|
|
162
|
+
flex-direction: column;
|
|
163
|
+
gap: 12px;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
@supports (display: grid) {
|
|
167
|
+
.bento-grid {
|
|
168
|
+
display: grid;
|
|
169
|
+
grid-template-columns: repeat(12, minmax(0, 1fr));
|
|
170
|
+
grid-auto-rows: 90px;
|
|
171
|
+
gap: 24px;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Framework Notes
|
|
177
|
+
|
|
178
|
+
#### React + Tailwind CSS
|
|
179
|
+
|
|
180
|
+
Tailwind's `col-span-{n}` and `row-span-{n}` utilities map directly to bento spans. Tailwind UI ships official bento grid marketing section components.
|
|
181
|
+
|
|
182
|
+
```jsx
|
|
183
|
+
// app/components/BentoGrid.tsx
|
|
184
|
+
export function BentoGrid() {
|
|
185
|
+
return (
|
|
186
|
+
<div className="grid grid-cols-12 auto-rows-[90px] gap-6 p-6">
|
|
187
|
+
{/* Anchor: 6 cols, 4 rows */}
|
|
188
|
+
<div className="col-span-12 md:col-span-6 row-span-4 rounded-3xl bg-zinc-900 p-10">
|
|
189
|
+
<h2 className="text-3xl font-bold text-white">Hero Feature</h2>
|
|
190
|
+
</div>
|
|
191
|
+
|
|
192
|
+
{/* Half card: 6 cols, 2 rows */}
|
|
193
|
+
<div className="col-span-12 md:col-span-6 row-span-2 rounded-3xl bg-indigo-600 p-8">
|
|
194
|
+
<p className="text-white font-semibold">Secondary</p>
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
{/* Quarter cards: 3 cols, 2 rows */}
|
|
198
|
+
<div className="col-span-6 md:col-span-3 row-span-2 rounded-3xl bg-zinc-100 p-6">
|
|
199
|
+
<p>Stat</p>
|
|
200
|
+
</div>
|
|
201
|
+
<div className="col-span-6 md:col-span-3 row-span-2 rounded-3xl bg-zinc-100 p-6">
|
|
202
|
+
<p>Stat</p>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
)
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
For Tailwind v4, use arbitrary values: `grid-cols-[repeat(12,minmax(0,1fr))]` or register a CSS custom property in `@theme`.
|
|
210
|
+
|
|
211
|
+
#### React Native
|
|
212
|
+
|
|
213
|
+
CSS Grid does not exist in React Native. Use nested Flexbox to approximate bento structure:
|
|
214
|
+
|
|
215
|
+
```jsx
|
|
216
|
+
// Bento approximation in React Native
|
|
217
|
+
import { View, StyleSheet } from 'react-native'
|
|
218
|
+
|
|
219
|
+
export function BentoGrid() {
|
|
220
|
+
return (
|
|
221
|
+
<View style={styles.grid}>
|
|
222
|
+
<View style={styles.anchor} />
|
|
223
|
+
<View style={styles.column}>
|
|
224
|
+
<View style={styles.half} />
|
|
225
|
+
<View style={styles.row}>
|
|
226
|
+
<View style={styles.quarter} />
|
|
227
|
+
<View style={styles.quarter} />
|
|
228
|
+
</View>
|
|
229
|
+
</View>
|
|
230
|
+
</View>
|
|
231
|
+
)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const GAP = 12
|
|
235
|
+
const styles = StyleSheet.create({
|
|
236
|
+
grid: { flexDirection: 'row', gap: GAP, padding: GAP },
|
|
237
|
+
anchor: { flex: 1, aspectRatio: 1, borderRadius: 20, backgroundColor: '#18181b' },
|
|
238
|
+
column: { flex: 1, gap: GAP },
|
|
239
|
+
half: { flex: 1, borderRadius: 20, backgroundColor: '#4f46e5' },
|
|
240
|
+
row: { flexDirection: 'row', gap: GAP },
|
|
241
|
+
quarter: { flex: 1, aspectRatio: 1, borderRadius: 20, backgroundColor: '#f4f4f5' },
|
|
242
|
+
})
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
#### Vanilla CSS — Container Queries Approach
|
|
246
|
+
|
|
247
|
+
Container queries let each bento card reflow based on its own allocated width rather than the viewport, making cards reusable in different grid positions:
|
|
248
|
+
|
|
249
|
+
```css
|
|
250
|
+
/* Mark each card as a query container */
|
|
251
|
+
.bento-card {
|
|
252
|
+
container-type: inline-size;
|
|
253
|
+
container-name: card;
|
|
254
|
+
border-radius: 24px;
|
|
255
|
+
overflow: hidden;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/* Card adapts its internal layout when narrow */
|
|
259
|
+
@container card (max-width: 280px) {
|
|
260
|
+
.card-media { display: none; }
|
|
261
|
+
.card-title { font-size: 1rem; }
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
@container card (min-width: 480px) {
|
|
265
|
+
.card-layout { flex-direction: row; }
|
|
266
|
+
.card-title { font-size: 1.75rem; }
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### Common Pitfalls
|
|
271
|
+
|
|
272
|
+
- **Source-order mismatch.** CSS Grid lets you place items anywhere visually, which decouples DOM order from visual order. Screen readers and keyboard users follow DOM order. Write HTML in the intended reading sequence first, then reposition visually only when necessary.
|
|
273
|
+
- **Fixed row heights breaking content.** `grid-auto-rows: 90px` is a rhythm unit, not a maximum. Set `overflow: hidden` on cards and test with real content at each row-span value.
|
|
274
|
+
- **Dense auto-flow scrambling accessible order.** `grid-auto-flow: dense` re-sorts items visually. Only use it with purely decorative grids or image galleries. Never use it when cards contain meaningful reading sequence.
|
|
275
|
+
- **Inconsistent border-radius.** The bento aesthetic depends on every card sharing the same radius. One flat-cornered card collapses the visual system.
|
|
276
|
+
- **Too many cells.** Beyond 8 cards the asymmetry reads as clutter, not hierarchy. If you need more cells, split into two stacked bento grids.
|
|
277
|
+
- **Forgetting aspect-ratio on image-only cells.** Without a defined aspect ratio, image cells collapse to zero height before the image loads, causing cumulative layout shift (CLS).
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Examples Gallery
|
|
282
|
+
|
|
283
|
+
### Apple — Product Feature Pages
|
|
284
|
+
URL: apple.com/iphone / apple.com/macbook-air
|
|
285
|
+
Apple's canonical use: a grid of 4–6 cards per section, one large card (typically 2-column span) paired with 1×1 stat or illustration cards. Cards use deep background colors, large typographic numerals, and product photography that bleeds to the card edge. Each card communicates a single spec or capability. The grid resets per feature section — not one long grid but multiple small ones.
|
|
286
|
+
|
|
287
|
+
### Linear — Homepage Feature Grid
|
|
288
|
+
URL: linear.app
|
|
289
|
+
Linear uses a dark bento grid to showcase product capabilities. Cards use subtle gradient borders on dark backgrounds, monospace figures for performance numbers, and short two-word headlines. The grid is notably sparse — they leave breathing room rather than filling every cell with heavy content. Strong reference for developer-tool aesthetics.
|
|
290
|
+
|
|
291
|
+
### Vercel — Dashboard and Marketing Pages
|
|
292
|
+
URL: vercel.com
|
|
293
|
+
Vercel blends bento with glassmorphism: frosted card surfaces, glowing accent lines, and animated deployment graphs embedded within cells. Their grid mixes full-width "wide" cards with narrow stat cards. A strong reference for animated bento where micro-interactions (hover glows, number counters) live inside cells.
|
|
294
|
+
|
|
295
|
+
### Notion — Landing Page Feature Sections
|
|
296
|
+
URL: notion.so
|
|
297
|
+
Notion's homepage is a textbook bento: template previews, testimonials, and feature descriptions share one grid. Cards use Notion's off-white background, minimal iconography, and tight two-line descriptions. It demonstrates bento working with light color palettes rather than the dark-dominant Apple/Linear approach.
|
|
298
|
+
|
|
299
|
+
### Awwwards Featured — Givingli Interactive Bento
|
|
300
|
+
URL: awwwards.com/inspiration/givingli-interactive-bento-grid-givingli
|
|
301
|
+
Awarded for interactive bento grid with animated cards, hover state transitions, and colorful per-card theming. Reference for elevated motion design inside bento cells. Each card has its own hover color logic while maintaining grid-level visual coherence.
|
|
302
|
+
|
|
303
|
+
### Awwwards Featured — Pixlspace Creative Studio
|
|
304
|
+
URL: awwwards.com/inspiration/interavtive-bento-grid-with-hover-and-scroll-effects-pixlspace-creative-studio
|
|
305
|
+
Scroll-triggered bento grid where cells animate into view at staggered intervals. Demonstrates how bento pairs with intersection-observer entry animations without triggering layout reflow.
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## Accessibility
|
|
310
|
+
|
|
311
|
+
### Source Order is Reading Order
|
|
312
|
+
|
|
313
|
+
HTML element sequence must reflect logical reading flow regardless of visual placement. The primary rule: write the DOM in the order a screen reader should announce it.
|
|
314
|
+
|
|
315
|
+
```html
|
|
316
|
+
<!-- Correct: anchor card first in DOM because it anchors meaning -->
|
|
317
|
+
<section class="bento-grid" style="reading-flow: grid-rows;">
|
|
318
|
+
<article class="bento-anchor"><!-- 1. Hero feature --></article>
|
|
319
|
+
<article class="bento-half"><!-- 2. Supporting detail --></article>
|
|
320
|
+
<article class="bento-quarter"><!-- 3. Stat --></article>
|
|
321
|
+
<article class="bento-quarter"><!-- 4. Stat --></article>
|
|
322
|
+
</section>
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
### CSS reading-flow Property (Chrome 137+)
|
|
326
|
+
|
|
327
|
+
The new `reading-flow` property aligns keyboard tab order with visual grid order for grid containers. This resolves the long-standing problem where grid reordering broke focus navigation.
|
|
328
|
+
|
|
329
|
+
```css
|
|
330
|
+
.bento-grid {
|
|
331
|
+
display: grid;
|
|
332
|
+
grid-template-columns: repeat(12, minmax(0, 1fr));
|
|
333
|
+
reading-flow: grid-rows; /* Tab follows visual row-by-row order */
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
Values:
|
|
338
|
+
- `grid-rows` — tab order follows rows left-to-right, top-to-bottom (most common for bento)
|
|
339
|
+
- `grid-columns` — tab order follows columns top-to-bottom, left-to-right
|
|
340
|
+
- `grid-order` — tab order respects CSS `order` property values
|
|
341
|
+
|
|
342
|
+
Support: Chrome 137+. For other browsers, ensure DOM order matches intended tab sequence without relying on this property.
|
|
343
|
+
|
|
344
|
+
### Landmark and ARIA Roles
|
|
345
|
+
|
|
346
|
+
Wrap bento grids in a `<section>` with `aria-label`. Each card should be an `<article>` or have `role="region"` with an `aria-labelledby` pointing to its headline.
|
|
347
|
+
|
|
348
|
+
```html
|
|
349
|
+
<section aria-label="Product features" class="bento-grid">
|
|
350
|
+
<article aria-labelledby="feature-speed">
|
|
351
|
+
<h3 id="feature-speed">Up to 2x faster</h3>
|
|
352
|
+
<p>M3 chip benchmark results.</p>
|
|
353
|
+
</article>
|
|
354
|
+
</section>
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Focus Visibility
|
|
358
|
+
|
|
359
|
+
Every interactive card must have a visible `:focus-visible` outline. The 24px border-radius on cards clips default browser outlines — define an explicit offset outline:
|
|
360
|
+
|
|
361
|
+
```css
|
|
362
|
+
.bento-card:focus-visible {
|
|
363
|
+
outline: 3px solid #4f46e5;
|
|
364
|
+
outline-offset: 4px;
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## Performance
|
|
371
|
+
|
|
372
|
+
### Aspect Ratio on Every Cell
|
|
373
|
+
|
|
374
|
+
Always define `aspect-ratio` on cells that contain images. Without it, cells collapse to zero height during load, causing CLS (Cumulative Layout Shift).
|
|
375
|
+
|
|
376
|
+
```css
|
|
377
|
+
.bento-anchor { aspect-ratio: 1 / 1; }
|
|
378
|
+
.bento-wide { aspect-ratio: 16 / 5; }
|
|
379
|
+
.bento-quarter { aspect-ratio: 3 / 4; }
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### CSS Containment
|
|
383
|
+
|
|
384
|
+
Apply `contain: layout paint` to individual cards to limit browser recalculation scope when one card's content changes:
|
|
385
|
+
|
|
386
|
+
```css
|
|
387
|
+
.bento-card {
|
|
388
|
+
contain: layout paint;
|
|
389
|
+
overflow: hidden;
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
### Image Optimization
|
|
394
|
+
|
|
395
|
+
- Use `loading="lazy"` on below-fold card images
|
|
396
|
+
- Use WebP or AVIF format
|
|
397
|
+
- Use `srcset` for cards that span different widths at different breakpoints
|
|
398
|
+
- Set explicit `width` and `height` attributes on `<img>` to reserve space before load
|
|
399
|
+
|
|
400
|
+
### Animation Budget
|
|
401
|
+
|
|
402
|
+
Animate only `transform` and `opacity` inside bento cells. Never animate `width`, `height`, `grid-column`, or `grid-row` — these trigger full layout recalculation across the entire grid.
|
|
403
|
+
|
|
404
|
+
```css
|
|
405
|
+
/* Safe: GPU-composited */
|
|
406
|
+
.bento-card:hover { transform: scale(1.02); transition: transform 200ms ease; }
|
|
407
|
+
|
|
408
|
+
/* Unsafe: triggers layout on every frame */
|
|
409
|
+
.bento-card:hover { width: 110%; }
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## When to Use / When to Avoid
|
|
415
|
+
|
|
416
|
+
### Use When
|
|
417
|
+
|
|
418
|
+
- Marketing landing pages with 4–8 distinct product features to highlight simultaneously
|
|
419
|
+
- App or SaaS dashboards where widgets have inherently different data densities
|
|
420
|
+
- Portfolio or gallery pages where visual interest from asymmetry is a goal
|
|
421
|
+
- Hero sections that need to present multiple parallel value propositions without hierarchy requiring prose
|
|
422
|
+
|
|
423
|
+
### Avoid When
|
|
424
|
+
|
|
425
|
+
- Long-form reading content — bento fragments the reading experience
|
|
426
|
+
- Dense data tables — tabular data requires aligned columns and rows, not varied card sizes
|
|
427
|
+
- Sequential workflows or step-by-step instructions — the asymmetric layout implies parallel comparison, not sequence
|
|
428
|
+
- Navigation menus — bento implies content, not wayfinding
|
|
429
|
+
- Mobile-first products where the primary surface is a phone and the collapsed single-column view loses all hierarchy benefit
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
## Design Tokens
|
|
434
|
+
|
|
435
|
+
These token values represent the consensus across Apple, Linear, Vercel, and Notion implementations:
|
|
436
|
+
|
|
437
|
+
```css
|
|
438
|
+
:root {
|
|
439
|
+
/* Grid structure */
|
|
440
|
+
--bento-gap-sm: 12px; /* mobile */
|
|
441
|
+
--bento-gap-md: 16px; /* tablet */
|
|
442
|
+
--bento-gap-lg: 24px; /* desktop */
|
|
443
|
+
|
|
444
|
+
/* Card radius — consistent across all cards */
|
|
445
|
+
--bento-radius-sm: 16px; /* compact UI */
|
|
446
|
+
--bento-radius-md: 24px; /* standard (Apple default) */
|
|
447
|
+
--bento-radius-lg: 32px; /* large/prominent cards */
|
|
448
|
+
|
|
449
|
+
/* Card elevation — muted shadows keep asymmetry readable */
|
|
450
|
+
--bento-shadow: 0 1px 3px rgba(0,0,0,0.07), 0 4px 16px rgba(0,0,0,0.05);
|
|
451
|
+
|
|
452
|
+
/* Padding inside cards — scale with card size */
|
|
453
|
+
--bento-padding-sm: 20px; /* quarter cards */
|
|
454
|
+
--bento-padding-md: 32px; /* half cards */
|
|
455
|
+
--bento-padding-lg: 48px; /* anchor cards */
|
|
456
|
+
|
|
457
|
+
/* Row rhythm — base unit; spans stack as multiples */
|
|
458
|
+
--bento-row-unit: 90px;
|
|
459
|
+
|
|
460
|
+
/* Column system */
|
|
461
|
+
--bento-cols-desktop: 12;
|
|
462
|
+
--bento-cols-tablet: 4;
|
|
463
|
+
--bento-cols-mobile: 2;
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## Related
|
|
470
|
+
|
|
471
|
+
- [Micro-Interactions](./micro-interactions.md) — card hover and entrance animations pair well with bento
|
|
472
|
+
- [Glassmorphism](./glassmorphism.md) — frosted card surfaces used by Vercel-style bento grids
|
|
473
|
+
- [Neubrutalism](./neubrutalism.md) — high-contrast card borders as an alternative bento aesthetic
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# Claymorphism
|
|
2
|
+
|
|
3
|
+
> Soft 3D aesthetic where UI elements look like inflated clay — playful, tactile, and friendly. Combines neumorphism's depth with warmer, colorful execution.
|
|
4
|
+
|
|
5
|
+
Last verified: 2026-03-04
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Visual Characteristics
|
|
10
|
+
|
|
11
|
+
- Soft 3D inflated appearance — elements look "puffed up"
|
|
12
|
+
- Double inset shadows (dark + light) creating clay-like depth
|
|
13
|
+
- Very rounded corners (24-40px)
|
|
14
|
+
- Pastel color palette — non-saturated, light, airy
|
|
15
|
+
- Outer shadow for floating elevation
|
|
16
|
+
- No sharp edges, no flat surfaces
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## CSS Implementation
|
|
21
|
+
|
|
22
|
+
```css
|
|
23
|
+
/* Claymorphism card */
|
|
24
|
+
.clay-card {
|
|
25
|
+
background: #F0E6FF;
|
|
26
|
+
border-radius: 30px;
|
|
27
|
+
box-shadow:
|
|
28
|
+
inset -8px -8px 16px rgba(0, 0, 0, 0.1),
|
|
29
|
+
inset 8px 8px 16px rgba(255, 255, 255, 0.5),
|
|
30
|
+
8px 8px 24px rgba(0, 0, 0, 0.15);
|
|
31
|
+
padding: 32px;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* Claymorphism button */
|
|
35
|
+
.clay-button {
|
|
36
|
+
background: #A8D8FF;
|
|
37
|
+
border: none;
|
|
38
|
+
border-radius: 20px;
|
|
39
|
+
box-shadow:
|
|
40
|
+
inset -4px -4px 8px rgba(0, 0, 0, 0.1),
|
|
41
|
+
inset 4px 4px 8px rgba(255, 255, 255, 0.5),
|
|
42
|
+
4px 4px 12px rgba(0, 0, 0, 0.15);
|
|
43
|
+
padding: 14px 28px;
|
|
44
|
+
font-weight: 600;
|
|
45
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.clay-button:hover {
|
|
49
|
+
transform: translateY(-2px);
|
|
50
|
+
box-shadow:
|
|
51
|
+
inset -4px -4px 8px rgba(0, 0, 0, 0.1),
|
|
52
|
+
inset 4px 4px 8px rgba(255, 255, 255, 0.5),
|
|
53
|
+
6px 6px 16px rgba(0, 0, 0, 0.2);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.clay-button:active {
|
|
57
|
+
transform: translateY(1px);
|
|
58
|
+
box-shadow:
|
|
59
|
+
inset -6px -6px 12px rgba(0, 0, 0, 0.12),
|
|
60
|
+
inset 6px 6px 12px rgba(255, 255, 255, 0.4),
|
|
61
|
+
2px 2px 8px rgba(0, 0, 0, 0.1);
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Shadow Formula
|
|
66
|
+
|
|
67
|
+
The 3D clay effect = 2 inset shadows (dark + light) + 1 outer shadow:
|
|
68
|
+
1. **Inset dark** (bottom-right): creates depth cavity, `rgba(0,0,0, 0.08-0.12)`
|
|
69
|
+
2. **Inset light** (top-left): creates highlight/bulge, `rgba(255,255,255, 0.4-0.6)`
|
|
70
|
+
3. **Outer dark**: lifts element off background, `rgba(0,0,0, 0.1-0.2)`
|
|
71
|
+
|
|
72
|
+
### Color Palette
|
|
73
|
+
- Pastels: `#F0E6FF` (lavender), `#A8D8FF` (sky), `#FFD4E8` (pink), `#C8F7C5` (mint), `#FFF3CD` (cream)
|
|
74
|
+
- Background: `#F5F0FF` or `#F0F4FF` (tinted white)
|
|
75
|
+
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
## Implementation Guide
|
|
79
|
+
|
|
80
|
+
### Step-by-step
|
|
81
|
+
|
|
82
|
+
1. Choose a pastel base color for the element background
|
|
83
|
+
2. Set a large border-radius (24-40px) — the puffy look depends on this
|
|
84
|
+
3. Apply the 3-shadow formula: `inset dark` + `inset light` + `outer`
|
|
85
|
+
4. Set background to a slightly lighter tint of the element color for the page
|
|
86
|
+
5. Add hover state: increase outer shadow spread + `translateY(-2px)`
|
|
87
|
+
6. Add active state: compress shadows + `translateY(1px)` for a "squish" effect
|
|
88
|
+
7. Remove all borders — claymorphism uses shadows exclusively for definition
|
|
89
|
+
|
|
90
|
+
### Progressive Enhancement
|
|
91
|
+
|
|
92
|
+
Claymorphism uses only `box-shadow` and `border-radius` — both have universal browser support. No `@supports` queries needed.
|
|
93
|
+
|
|
94
|
+
### Framework Notes
|
|
95
|
+
|
|
96
|
+
#### React + Tailwind CSS
|
|
97
|
+
|
|
98
|
+
Tailwind requires custom shadow definitions since the multi-shadow clay formula isn't built-in:
|
|
99
|
+
|
|
100
|
+
```js
|
|
101
|
+
// tailwind.config.js
|
|
102
|
+
module.exports = {
|
|
103
|
+
theme: {
|
|
104
|
+
extend: {
|
|
105
|
+
boxShadow: {
|
|
106
|
+
'clay': 'inset -8px -8px 16px rgba(0,0,0,0.1), inset 8px 8px 16px rgba(255,255,255,0.5), 8px 8px 24px rgba(0,0,0,0.15)',
|
|
107
|
+
'clay-hover': 'inset -8px -8px 16px rgba(0,0,0,0.1), inset 8px 8px 16px rgba(255,255,255,0.5), 6px 6px 16px rgba(0,0,0,0.2)',
|
|
108
|
+
'clay-active': 'inset -6px -6px 12px rgba(0,0,0,0.12), inset 6px 6px 12px rgba(255,255,255,0.4), 2px 2px 8px rgba(0,0,0,0.1)',
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
```tsx
|
|
116
|
+
export function ClayCard({ children }: { children: React.ReactNode }) {
|
|
117
|
+
return (
|
|
118
|
+
<div className="bg-[#F0E6FF] rounded-[30px] shadow-clay p-8 hover:shadow-clay-hover hover:-translate-y-0.5 active:shadow-clay-active active:translate-y-px transition-all duration-200">
|
|
119
|
+
{children}
|
|
120
|
+
</div>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### React Native
|
|
126
|
+
|
|
127
|
+
```tsx
|
|
128
|
+
const styles = StyleSheet.create({
|
|
129
|
+
clay: {
|
|
130
|
+
backgroundColor: '#F0E6FF',
|
|
131
|
+
borderRadius: 30,
|
|
132
|
+
padding: 32,
|
|
133
|
+
// React Native can't do inset shadows — approximate with outer shadow + gradient overlay
|
|
134
|
+
shadowColor: '#000',
|
|
135
|
+
shadowOffset: { width: 8, height: 8 },
|
|
136
|
+
shadowOpacity: 0.15,
|
|
137
|
+
shadowRadius: 12,
|
|
138
|
+
elevation: 8,
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Note: React Native cannot render inset shadows natively. The full clay effect requires a `LinearGradient` overlay from `expo-linear-gradient` or `react-native-linear-gradient` to simulate the inner highlight.
|
|
144
|
+
|
|
145
|
+
#### Vanilla CSS
|
|
146
|
+
|
|
147
|
+
The implementation section above is pure vanilla CSS. Use CSS custom properties for theming multiple clay colors.
|
|
148
|
+
|
|
149
|
+
### Common Pitfalls
|
|
150
|
+
|
|
151
|
+
1. **Missing the inset light shadow**: without the top-left white inset, elements look dented rather than puffy. The highlight is what creates the 3D clay illusion.
|
|
152
|
+
2. **Borders**: adding any `border` breaks the soft organic feel. Use shadows exclusively for definition.
|
|
153
|
+
3. **Dark backgrounds**: claymorphism requires light/pastel backgrounds. On dark surfaces, the inset shadows become invisible and the effect collapses.
|
|
154
|
+
4. **Too many clay elements**: a page full of puffy elements feels overwhelming. Use clay for 3-5 key interactive elements, not every UI component.
|
|
155
|
+
5. **Confusing with neumorphism**: claymorphism uses color and asymmetric shadows — neumorphism uses monochrome with symmetric shadows. The result is visually very different.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Examples Gallery
|
|
160
|
+
|
|
161
|
+
| Site | What They Do Well | Screenshot Description |
|
|
162
|
+
|------|-------------------|----------------------|
|
|
163
|
+
| Duolingo | Signature clay aesthetic across the entire app — 3D inflated buttons, character cards, and progress elements | Lesson cards with colorful puffy buttons |
|
|
164
|
+
| Headspace | Meditation cards use soft 3D elevation with pastel backgrounds and rounded corners | Session selection with inflated card grid |
|
|
165
|
+
| Oatly | Brand pages with playful 3D card elements and pastel palette on warm backgrounds | Product showcase with clay-styled CTA buttons |
|
|
166
|
+
| Figma Community | Clay-inspired plugin cards with soft shadows and rounded thumbnails | Plugin browser with puffy card hover states |
|
|
167
|
+
| Awwwards — Cuberto portfolio | Clay-styled interactive elements with exaggerated 3D shadows and pastel accents | Portfolio cards with tactile hover animations |
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Accessibility
|
|
172
|
+
|
|
173
|
+
- **Contrast on pastels**: pastel backgrounds with light text can fail WCAG. Use dark text (`#333` minimum) on all pastel surfaces.
|
|
174
|
+
- **Focus indicators**: shadow-only styling makes focus rings essential — use `outline: 3px solid #5B4FA0` with `outline-offset: 3px`
|
|
175
|
+
- **No border definition**: since claymorphism removes borders, ensure interactive elements have sufficient shadow contrast to be distinguishable from background
|
|
176
|
+
- **Reduced motion**: the hover lift and squish are subtle (200ms, 2px) — generally safe, but provide instant state change as fallback
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Performance
|
|
181
|
+
|
|
182
|
+
- **Low GPU cost**: `box-shadow` is well-optimized in all browsers. No compositing layers or filters.
|
|
183
|
+
- **Multi-shadow cost**: 3 shadows per element is slightly more expensive than single-shadow designs but negligible in practice
|
|
184
|
+
- **Safe for all devices**: no blur, no filters, no backdrop effects
|
|
185
|
+
- **Animation**: `transform` + `box-shadow` transitions at 200ms stay within frame budget
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## When to Use / When to Avoid
|
|
190
|
+
|
|
191
|
+
### Use When
|
|
192
|
+
- Children's apps, educational platforms, gamified UX
|
|
193
|
+
- Landing pages for friendly/approachable products
|
|
194
|
+
- Onboarding flows, empty states, playful CTAs
|
|
195
|
+
- Brands targeting warmth and whimsy
|
|
196
|
+
|
|
197
|
+
### Avoid When
|
|
198
|
+
- Enterprise apps — reads as too playful for corporate contexts
|
|
199
|
+
- Fintech, healthcare — undermines trust signals
|
|
200
|
+
- Data-heavy interfaces — inflated elements waste screen real estate
|
|
201
|
+
- Dark mode — the clay effect requires light backgrounds to function
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Design Tokens
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
{
|
|
209
|
+
"claymorphism": {
|
|
210
|
+
"radius-sm": "20px",
|
|
211
|
+
"radius-md": "30px",
|
|
212
|
+
"radius-lg": "40px",
|
|
213
|
+
"shadow-card": "inset -8px -8px 16px rgba(0,0,0,0.1), inset 8px 8px 16px rgba(255,255,255,0.5), 8px 8px 24px rgba(0,0,0,0.15)",
|
|
214
|
+
"shadow-button": "inset -4px -4px 8px rgba(0,0,0,0.1), inset 4px 4px 8px rgba(255,255,255,0.5), 4px 4px 12px rgba(0,0,0,0.15)",
|
|
215
|
+
"palette-lavender": "#F0E6FF",
|
|
216
|
+
"palette-sky": "#A8D8FF",
|
|
217
|
+
"palette-pink": "#FFD4E8",
|
|
218
|
+
"palette-mint": "#C8F7C5",
|
|
219
|
+
"palette-cream": "#FFF3CD",
|
|
220
|
+
"bg-light": "#F5F0FF",
|
|
221
|
+
"transition-duration": "200ms",
|
|
222
|
+
"transition-easing": "ease"
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Related
|
|
230
|
+
|
|
231
|
+
- [Micro-Interactions](./micro-interactions.md) — tactile feedback (squish, lift) enhances the clay feel
|
|
232
|
+
- [Bento Grid](./bento-grid.md) — compatible layout structure for clay cards
|