picasso-skill 1.0.0 → 1.2.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/README.md +70 -45
- package/agents/picasso.md +326 -0
- package/bin/install.mjs +54 -24
- package/package.json +5 -3
- package/skills/picasso/references/accessibility.md +172 -0
- package/skills/picasso/references/design-system.md +14 -14
- package/skills/picasso/references/generative-art.md +626 -32
- package/skills/picasso/references/motion-and-animation.md +2 -2
- package/skills/picasso/references/react-patterns.md +193 -91
- package/skills/picasso/references/responsive-design.md +349 -15
- package/skills/picasso/references/sensory-design.md +294 -50
- package/SKILL.md +0 -202
- package/references/anti-patterns.md +0 -95
- package/references/color-and-contrast.md +0 -174
- package/references/component-patterns.md +0 -113
- package/references/design-system.md +0 -176
- package/references/generative-art.md +0 -54
- package/references/interaction-design.md +0 -162
- package/references/motion-and-animation.md +0 -260
- package/references/react-patterns.md +0 -216
- package/references/responsive-design.md +0 -118
- package/references/sensory-design.md +0 -125
- package/references/spatial-design.md +0 -176
- package/references/typography.md +0 -168
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Responsive Design Reference
|
|
2
2
|
|
|
3
|
+
## Table of Contents
|
|
4
|
+
1. Breakpoints
|
|
5
|
+
2. Mobile-First Approach
|
|
6
|
+
3. Fluid Design
|
|
7
|
+
4. Dynamic Viewport Units
|
|
8
|
+
5. Container Queries
|
|
9
|
+
6. Touch Targets
|
|
10
|
+
7. Responsive Typography
|
|
11
|
+
8. Navigation Patterns
|
|
12
|
+
9. Images
|
|
13
|
+
10. Responsive Tables
|
|
14
|
+
11. Print Styles
|
|
15
|
+
12. Progressive Enhancement
|
|
16
|
+
13. Landscape and Orientation
|
|
17
|
+
14. Common Mistakes
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
3
21
|
## 1. Breakpoints
|
|
4
22
|
|
|
5
23
|
Use content-driven breakpoints, not device-driven. These are sensible defaults:
|
|
@@ -18,6 +36,8 @@ Use content-driven breakpoints, not device-driven. These are sensible defaults:
|
|
|
18
36
|
@media (min-width: 1536px) { }
|
|
19
37
|
```
|
|
20
38
|
|
|
39
|
+
When a layout breaks before reaching a named breakpoint, add a custom one. The content dictates the breakpoint, not the other way around. Avoid more than five or six breakpoints total.
|
|
40
|
+
|
|
21
41
|
## 2. Mobile-First Approach
|
|
22
42
|
|
|
23
43
|
Start with the mobile layout (single column, stacked). Add complexity at wider breakpoints. This ensures the core experience works everywhere before enhancements.
|
|
@@ -52,20 +72,113 @@ h1 {
|
|
|
52
72
|
}
|
|
53
73
|
```
|
|
54
74
|
|
|
55
|
-
|
|
75
|
+
For spacing systems, combine `clamp()` with CSS custom properties so every spacing token scales together:
|
|
76
|
+
|
|
77
|
+
```css
|
|
78
|
+
:root {
|
|
79
|
+
--space-s: clamp(0.5rem, 1.5vw, 0.75rem);
|
|
80
|
+
--space-m: clamp(1rem, 3vw, 1.5rem);
|
|
81
|
+
--space-l: clamp(1.5rem, 5vw, 3rem);
|
|
82
|
+
}
|
|
83
|
+
```
|
|
56
84
|
|
|
57
|
-
|
|
85
|
+
## 4. Dynamic Viewport Units
|
|
86
|
+
|
|
87
|
+
The classic `vh` unit does not account for browser chrome (address bar, toolbar) on mobile devices. This causes content to be hidden behind the UI. Use the newer viewport units instead:
|
|
88
|
+
|
|
89
|
+
| Unit | Meaning | Use when |
|
|
90
|
+
|------|---------|----------|
|
|
91
|
+
| `svh` | Small viewport height (browser chrome fully visible) | You want the smallest guaranteed visible area |
|
|
92
|
+
| `lvh` | Large viewport height (browser chrome hidden) | You want the largest possible area |
|
|
93
|
+
| `dvh` | Dynamic viewport height (updates live as chrome shows/hides) | You want the hero or section to always fill exactly the visible area |
|
|
94
|
+
| `dvw` | Dynamic viewport width | Rare, but useful for side-panel layouts on mobile browsers with edge UI |
|
|
95
|
+
|
|
96
|
+
```css
|
|
97
|
+
/* Full-screen hero that actually fills the screen on mobile */
|
|
98
|
+
.hero {
|
|
99
|
+
min-height: 100dvh;
|
|
100
|
+
display: grid;
|
|
101
|
+
place-items: center;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* Sticky footer layout that respects mobile browser chrome */
|
|
105
|
+
.app-shell {
|
|
106
|
+
display: grid;
|
|
107
|
+
grid-template-rows: auto 1fr auto;
|
|
108
|
+
min-height: 100dvh;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* Fallback for older browsers */
|
|
112
|
+
.hero {
|
|
113
|
+
min-height: 100vh;
|
|
114
|
+
min-height: 100dvh;
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Always declare a `vh` fallback before the `dvh` value. Browser support is strong (2023+), but the fallback costs nothing.
|
|
119
|
+
|
|
120
|
+
## 5. Container Queries
|
|
121
|
+
|
|
122
|
+
For component-level responsiveness (when the component's width, not the viewport, should determine layout). This is essential for reusable components that live in different layout contexts (main content area, sidebar, modal, dashboard grid).
|
|
123
|
+
|
|
124
|
+
### Card that adapts to its container
|
|
58
125
|
|
|
59
126
|
```css
|
|
60
127
|
.card-container {
|
|
61
128
|
container-type: inline-size;
|
|
129
|
+
container-name: card;
|
|
62
130
|
}
|
|
63
|
-
|
|
64
|
-
|
|
131
|
+
|
|
132
|
+
/* Compact: image on top, content below */
|
|
133
|
+
.card {
|
|
134
|
+
display: grid;
|
|
135
|
+
gap: 0.75rem;
|
|
136
|
+
}
|
|
137
|
+
.card img {
|
|
138
|
+
width: 100%;
|
|
139
|
+
aspect-ratio: 16 / 9;
|
|
140
|
+
object-fit: cover;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/* Wide enough: image beside content */
|
|
144
|
+
@container card (min-width: 400px) {
|
|
145
|
+
.card {
|
|
146
|
+
grid-template-columns: 200px 1fr;
|
|
147
|
+
}
|
|
148
|
+
.card img {
|
|
149
|
+
aspect-ratio: 1;
|
|
150
|
+
height: 100%;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/* Very wide: add metadata column */
|
|
155
|
+
@container card (min-width: 700px) {
|
|
156
|
+
.card {
|
|
157
|
+
grid-template-columns: 240px 1fr 180px;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Sidebar-aware layout
|
|
163
|
+
|
|
164
|
+
```css
|
|
165
|
+
.main-content { container-type: inline-size; }
|
|
166
|
+
|
|
167
|
+
@container (min-width: 600px) {
|
|
168
|
+
.dashboard-grid {
|
|
169
|
+
grid-template-columns: repeat(2, 1fr);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
@container (min-width: 900px) {
|
|
173
|
+
.dashboard-grid {
|
|
174
|
+
grid-template-columns: repeat(3, 1fr);
|
|
175
|
+
}
|
|
65
176
|
}
|
|
66
177
|
```
|
|
67
178
|
|
|
68
|
-
|
|
179
|
+
This means when the sidebar is open and the main area shrinks, the grid automatically drops columns without any viewport media query.
|
|
180
|
+
|
|
181
|
+
## 6. Touch Targets
|
|
69
182
|
|
|
70
183
|
Minimum touch target: 44x44px (WCAG) or 48x48px (Material). Apply to all interactive elements on mobile. If the visual element is smaller, use padding or `::before` pseudo-element to extend the hit area.
|
|
71
184
|
|
|
@@ -82,20 +195,22 @@ Minimum touch target: 44x44px (WCAG) or 48x48px (Material). Apply to all interac
|
|
|
82
195
|
}
|
|
83
196
|
```
|
|
84
197
|
|
|
85
|
-
|
|
198
|
+
Also ensure at least 8px of space between adjacent touch targets to prevent mis-taps.
|
|
199
|
+
|
|
200
|
+
## 7. Responsive Typography
|
|
86
201
|
|
|
87
202
|
Do not just shrink everything on mobile. Adjust the type scale:
|
|
88
203
|
- Mobile: use a smaller ratio (1.2) with a 15-16px base
|
|
89
204
|
- Desktop: use a larger ratio (1.25-1.333) with a 16-18px base
|
|
90
205
|
- Headings should scale more aggressively than body text
|
|
91
206
|
|
|
92
|
-
##
|
|
207
|
+
## 8. Navigation Patterns
|
|
93
208
|
|
|
94
209
|
- **Mobile (< 768px)**: Hamburger menu, bottom tab bar, or slide-out drawer
|
|
95
210
|
- **Tablet (768-1024px)**: Collapsed sidebar or icon-only navigation
|
|
96
211
|
- **Desktop (> 1024px)**: Full sidebar, top navigation bar, or mega-menu
|
|
97
212
|
|
|
98
|
-
##
|
|
213
|
+
## 9. Images
|
|
99
214
|
|
|
100
215
|
Use `srcset` and `sizes` for responsive images. Use `loading="lazy"` for below-the-fold images. Set `aspect-ratio` to prevent layout shift:
|
|
101
216
|
|
|
@@ -108,11 +223,230 @@ img {
|
|
|
108
223
|
}
|
|
109
224
|
```
|
|
110
225
|
|
|
111
|
-
##
|
|
226
|
+
## 10. Responsive Tables
|
|
227
|
+
|
|
228
|
+
Tables are one of the hardest elements to make responsive. Two proven patterns:
|
|
229
|
+
|
|
230
|
+
### Pattern A: Horizontal scroll wrapper
|
|
231
|
+
|
|
232
|
+
Keeps the table structure intact. Best for data-dense tables where column relationships matter (financial data, comparison grids).
|
|
233
|
+
|
|
234
|
+
```css
|
|
235
|
+
.table-wrapper {
|
|
236
|
+
overflow-x: auto;
|
|
237
|
+
-webkit-overflow-scrolling: touch;
|
|
238
|
+
border: 1px solid var(--border);
|
|
239
|
+
border-radius: 0.5rem;
|
|
240
|
+
}
|
|
241
|
+
.table-wrapper table {
|
|
242
|
+
min-width: 600px; /* prevents columns from crushing */
|
|
243
|
+
width: 100%;
|
|
244
|
+
border-collapse: collapse;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/* Visual hint that the table scrolls */
|
|
248
|
+
.table-wrapper {
|
|
249
|
+
background:
|
|
250
|
+
linear-gradient(to right, white 30%, transparent),
|
|
251
|
+
linear-gradient(to left, white 30%, transparent),
|
|
252
|
+
linear-gradient(to right, rgba(0,0,0,0.1), transparent 15px),
|
|
253
|
+
linear-gradient(to left, rgba(0,0,0,0.1), transparent 15px);
|
|
254
|
+
background-position: left, right, left, right;
|
|
255
|
+
background-size: 40px 100%, 40px 100%, 15px 100%, 15px 100%;
|
|
256
|
+
background-repeat: no-repeat;
|
|
257
|
+
background-attachment: local, local, scroll, scroll;
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Pattern B: Stacked cards on mobile
|
|
262
|
+
|
|
263
|
+
Reformats each row into a standalone card. Best for user-facing lists (orders, contacts, transactions) where each row is an independent record.
|
|
264
|
+
|
|
265
|
+
```css
|
|
266
|
+
@media (max-width: 767px) {
|
|
267
|
+
table, thead, tbody, th, td, tr {
|
|
268
|
+
display: block;
|
|
269
|
+
}
|
|
270
|
+
thead {
|
|
271
|
+
position: absolute;
|
|
272
|
+
width: 1px;
|
|
273
|
+
height: 1px;
|
|
274
|
+
overflow: hidden;
|
|
275
|
+
clip: rect(0, 0, 0, 0);
|
|
276
|
+
}
|
|
277
|
+
tr {
|
|
278
|
+
margin-bottom: 1rem;
|
|
279
|
+
border: 1px solid var(--border);
|
|
280
|
+
border-radius: 0.5rem;
|
|
281
|
+
padding: 0.75rem;
|
|
282
|
+
}
|
|
283
|
+
td {
|
|
284
|
+
display: flex;
|
|
285
|
+
justify-content: space-between;
|
|
286
|
+
padding: 0.4rem 0;
|
|
287
|
+
border-bottom: 1px solid var(--border-light);
|
|
288
|
+
}
|
|
289
|
+
td:last-child {
|
|
290
|
+
border-bottom: none;
|
|
291
|
+
}
|
|
292
|
+
/* Use data attributes for labels */
|
|
293
|
+
td::before {
|
|
294
|
+
content: attr(data-label);
|
|
295
|
+
font-weight: 600;
|
|
296
|
+
margin-right: 1rem;
|
|
297
|
+
flex-shrink: 0;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
The HTML needs `data-label` attributes on each `<td>`:
|
|
303
|
+
|
|
304
|
+
```html
|
|
305
|
+
<td data-label="Name">Alice Johnson</td>
|
|
306
|
+
<td data-label="Status">Active</td>
|
|
307
|
+
<td data-label="Amount">$1,240.00</td>
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
## 11. Print Styles
|
|
311
|
+
|
|
312
|
+
Always include basic print styles for pages with substantive content (articles, invoices, dashboards, reports):
|
|
313
|
+
|
|
314
|
+
```css
|
|
315
|
+
@media print {
|
|
316
|
+
/* Remove non-essential UI */
|
|
317
|
+
nav, .sidebar, .toolbar, footer, .no-print {
|
|
318
|
+
display: none !important;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/* Reset backgrounds and colors for ink saving */
|
|
322
|
+
body {
|
|
323
|
+
background: white !important;
|
|
324
|
+
color: black !important;
|
|
325
|
+
font-size: 12pt;
|
|
326
|
+
line-height: 1.5;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/* Prevent elements from breaking across pages */
|
|
330
|
+
h1, h2, h3 {
|
|
331
|
+
break-after: avoid;
|
|
332
|
+
}
|
|
333
|
+
table, figure, .card {
|
|
334
|
+
break-inside: avoid;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/* Show link URLs inline */
|
|
338
|
+
a[href^="http"]::after {
|
|
339
|
+
content: " (" attr(href) ")";
|
|
340
|
+
font-size: 0.85em;
|
|
341
|
+
color: #555;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/* Constrain width for readability */
|
|
345
|
+
.container {
|
|
346
|
+
max-width: 100% !important;
|
|
347
|
+
padding: 0 !important;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## 12. Progressive Enhancement
|
|
353
|
+
|
|
354
|
+
Use `@supports` to deliver modern layouts to capable browsers while keeping a usable fallback:
|
|
355
|
+
|
|
356
|
+
```css
|
|
357
|
+
/* Fallback: flexbox grid */
|
|
358
|
+
.grid {
|
|
359
|
+
display: flex;
|
|
360
|
+
flex-wrap: wrap;
|
|
361
|
+
gap: 1rem;
|
|
362
|
+
}
|
|
363
|
+
.grid > * {
|
|
364
|
+
flex: 1 1 300px;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/* Enhancement: subgrid for aligned cards */
|
|
368
|
+
@supports (grid-template-rows: subgrid) {
|
|
369
|
+
.grid {
|
|
370
|
+
display: grid;
|
|
371
|
+
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
|
|
372
|
+
}
|
|
373
|
+
.grid > .card {
|
|
374
|
+
display: grid;
|
|
375
|
+
grid-template-rows: subgrid;
|
|
376
|
+
grid-row: span 3;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
Other useful `@supports` checks:
|
|
382
|
+
|
|
383
|
+
```css
|
|
384
|
+
/* Container queries */
|
|
385
|
+
@supports (container-type: inline-size) {
|
|
386
|
+
.widget-wrapper { container-type: inline-size; }
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/* Has selector for advanced targeting */
|
|
390
|
+
@supports selector(:has(*)) {
|
|
391
|
+
.form-group:has(:invalid) { border-color: red; }
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/* Backdrop filter for frosted glass */
|
|
395
|
+
@supports (backdrop-filter: blur(10px)) {
|
|
396
|
+
.overlay {
|
|
397
|
+
backdrop-filter: blur(10px);
|
|
398
|
+
background: rgba(255, 255, 255, 0.6);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
## 13. Landscape and Orientation
|
|
404
|
+
|
|
405
|
+
Handle orientation changes explicitly, especially for mobile devices where landscape mode drastically changes available height:
|
|
406
|
+
|
|
407
|
+
```css
|
|
408
|
+
/* Landscape phones: reduce vertical spacing, switch to row layout */
|
|
409
|
+
@media (orientation: landscape) and (max-height: 500px) {
|
|
410
|
+
.hero {
|
|
411
|
+
min-height: auto;
|
|
412
|
+
padding: 2rem 1rem;
|
|
413
|
+
}
|
|
414
|
+
.onboarding-steps {
|
|
415
|
+
flex-direction: row;
|
|
416
|
+
overflow-x: auto;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
/* Tablet landscape: often wide enough for desktop layout */
|
|
421
|
+
@media (orientation: landscape) and (min-width: 768px) {
|
|
422
|
+
.sidebar { display: block; }
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Key considerations:
|
|
427
|
+
- Landscape phones have very little vertical space (typically under 400px). Do not use full-height heroes or tall modals.
|
|
428
|
+
- Virtual keyboards consume even more vertical space in landscape. Keep form inputs above the fold or use a scroll strategy.
|
|
429
|
+
- Test with `(max-height: Xpx)` in addition to orientation queries for finer control.
|
|
430
|
+
|
|
431
|
+
## 14. Common Mistakes
|
|
112
432
|
|
|
113
|
-
- Hiding
|
|
114
|
-
- Using `vw` units for text without a `clamp()` minimum
|
|
115
|
-
- Horizontal
|
|
116
|
-
- Fixed
|
|
117
|
-
- Not testing
|
|
118
|
-
-
|
|
433
|
+
- **Hiding content on mobile**: Users expect the same information, just reorganized. Use progressive disclosure (expand/collapse) instead of `display: none`.
|
|
434
|
+
- **Unguarded `vw` text**: Using `vw` units for text without a `clamp()` minimum makes text unreadable on small screens and comically large on ultrawide.
|
|
435
|
+
- **Horizontal overflow**: Almost never acceptable on mobile. Test at 320px wide to catch it. Common culprits: tables, pre/code blocks, fixed-width images, long URLs.
|
|
436
|
+
- **Fixed elements hogging the viewport**: A fixed header + fixed bottom bar + cookie banner can consume over half the screen on a short phone.
|
|
437
|
+
- **Not testing real device widths**: 375px (iPhone SE), 390px (modern iPhone), 360px (common Android), 320px (stress test).
|
|
438
|
+
- **Ignoring the notch and safe areas**: On devices with notches or rounded corners, use `env(safe-area-inset-*)` for edge-to-edge layouts:
|
|
439
|
+
```css
|
|
440
|
+
.bottom-bar {
|
|
441
|
+
padding-bottom: env(safe-area-inset-bottom, 0px);
|
|
442
|
+
}
|
|
443
|
+
```
|
|
444
|
+
- **Breakpoint-only thinking**: If you find yourself writing more than three media queries for a single component, switch to container queries or fluid sizing.
|
|
445
|
+
- **Forgetting hover states are absent on touch**: Use `@media (hover: hover)` to scope hover effects so they do not get stuck on touch devices.
|
|
446
|
+
```css
|
|
447
|
+
@media (hover: hover) {
|
|
448
|
+
.card:hover { transform: translateY(-2px); }
|
|
449
|
+
}
|
|
450
|
+
```
|
|
451
|
+
- **Z-index wars on mobile**: Stacking contexts behave differently when fixed/sticky elements overlap modals and drawers. Establish a z-index scale in custom properties.
|
|
452
|
+
- **Viewport-height layouts with virtual keyboards**: On mobile, the virtual keyboard does not shrink the viewport in all browsers. Elements pinned to `100vh` can end up hidden. Use `100dvh` or listen for `visualViewport` resize events.
|