picasso-skill 2.4.0 → 2.6.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/agents/picasso.md +26 -542
- package/commands/godmode.md +3 -13
- package/commands/roast.md +3 -14
- package/commands/score.md +3 -18
- package/commands/steal.md +3 -31
- package/package.json +1 -1
- package/references/accessibility-wcag.md +3 -0
- package/references/code-typography.md +36 -166
- package/references/color-and-contrast.md +78 -345
- package/references/generative-art.md +49 -561
- package/references/modern-css-performance.md +46 -258
- package/references/motion-and-animation.md +225 -88
- package/references/navigation-patterns.md +29 -186
- package/references/performance-optimization.md +42 -678
- package/references/react-patterns.md +56 -216
- package/references/responsive-design.md +77 -379
- package/references/sensory-design.md +62 -263
- package/references/ux-writing.md +64 -354
- package/references/animation-performance.md +0 -244
- package/references/interaction-design.md +0 -162
|
@@ -3,30 +3,13 @@
|
|
|
3
3
|
## 1. Modern CSS Features (2024-2025)
|
|
4
4
|
|
|
5
5
|
### CSS Nesting (Baseline 2024)
|
|
6
|
-
Native nesting eliminates preprocessor dependency.
|
|
7
|
-
|
|
8
|
-
```css
|
|
9
|
-
.card {
|
|
10
|
-
padding: 1rem;
|
|
11
|
-
> h2:first-child { margin-block-start: 0; }
|
|
12
|
-
&:hover { box-shadow: 0 4px 12px rgb(0 0 0 / 0.1); }
|
|
13
|
-
@media (width >= 768px) { padding: 2rem; }
|
|
14
|
-
}
|
|
15
|
-
```
|
|
6
|
+
Native nesting eliminates preprocessor dependency. Nest with `>`, `&`, and `@media` directly inside rule blocks.
|
|
16
7
|
|
|
17
8
|
### Cascade Layers (@layer)
|
|
18
|
-
Control specificity ordering
|
|
19
|
-
|
|
20
|
-
```css
|
|
21
|
-
@layer reset, base, components, utilities;
|
|
22
|
-
@layer reset { *, *::before, *::after { box-sizing: border-box; margin: 0; } }
|
|
23
|
-
@layer base { body { font-family: system-ui; line-height: 1.6; } }
|
|
24
|
-
@layer components { .btn { padding: 0.5rem 1rem; border-radius: 0.375rem; } }
|
|
25
|
-
```
|
|
9
|
+
Control specificity ordering: `@layer reset, base, components, utilities;` -- later layers win regardless of selector specificity.
|
|
26
10
|
|
|
27
11
|
### :has() Selector
|
|
28
|
-
Style parents based on children
|
|
29
|
-
|
|
12
|
+
Style parents based on children:
|
|
30
13
|
```css
|
|
31
14
|
form:has(:invalid) { border-color: red; }
|
|
32
15
|
.card:has(img) { grid-template-rows: auto 1fr; }
|
|
@@ -34,128 +17,52 @@ body:has(dialog[open]) { overflow: hidden; }
|
|
|
34
17
|
```
|
|
35
18
|
|
|
36
19
|
### CSS Anchor Positioning
|
|
37
|
-
Position elements relative to other elements without JS.
|
|
38
|
-
|
|
39
|
-
```css
|
|
40
|
-
.trigger { anchor-name: --tooltip-anchor; }
|
|
41
|
-
.tooltip {
|
|
42
|
-
position: absolute;
|
|
43
|
-
position-anchor: --tooltip-anchor;
|
|
44
|
-
top: anchor(bottom);
|
|
45
|
-
left: anchor(center);
|
|
46
|
-
translate: -50% 0.5rem;
|
|
47
|
-
}
|
|
48
|
-
```
|
|
20
|
+
Position elements relative to other elements without JS. Use `anchor-name` on trigger, `position-anchor` + `anchor()` on positioned element.
|
|
49
21
|
|
|
50
22
|
### @scope
|
|
51
|
-
Restrict styles to a DOM subtree with optional lower boundary
|
|
52
|
-
|
|
23
|
+
Restrict styles to a DOM subtree with optional lower boundary:
|
|
53
24
|
```css
|
|
54
25
|
@scope (.card) to (.card-content) {
|
|
55
|
-
h2 { font-size: 1.25rem;
|
|
56
|
-
p { color: var(--muted); }
|
|
26
|
+
h2 { font-size: 1.25rem; }
|
|
57
27
|
}
|
|
58
28
|
```
|
|
59
29
|
|
|
60
30
|
### @property (Typed Custom Properties)
|
|
61
|
-
Register custom properties with type, initial value, and inheritance. Enables animating custom properties.
|
|
62
|
-
|
|
63
|
-
```css
|
|
64
|
-
@property --gradient-angle {
|
|
65
|
-
syntax: "<angle>";
|
|
66
|
-
initial-value: 0deg;
|
|
67
|
-
inherits: false;
|
|
68
|
-
}
|
|
69
|
-
.gradient-border {
|
|
70
|
-
--gradient-angle: 0deg;
|
|
71
|
-
border-image: conic-gradient(from var(--gradient-angle), #f06, #9f6, #06f) 1;
|
|
72
|
-
animation: spin 3s linear infinite;
|
|
73
|
-
}
|
|
74
|
-
@keyframes spin { to { --gradient-angle: 360deg; } }
|
|
75
|
-
```
|
|
31
|
+
Register custom properties with type, initial value, and inheritance. Enables animating custom properties (e.g., gradient angles).
|
|
76
32
|
|
|
77
33
|
### color-mix()
|
|
78
|
-
Blend colors in any color space at runtime.
|
|
79
|
-
|
|
80
|
-
```css
|
|
81
|
-
.button {
|
|
82
|
-
--brand: oklch(0.65 0.25 260);
|
|
83
|
-
background: var(--brand);
|
|
84
|
-
&:hover { background: color-mix(in oklch, var(--brand) 85%, white); }
|
|
85
|
-
&:active { background: color-mix(in oklch, var(--brand) 80%, black); }
|
|
86
|
-
}
|
|
87
|
-
```
|
|
34
|
+
Blend colors in any color space at runtime. Always specify `in oklch` for perceptual uniformity.
|
|
88
35
|
|
|
89
36
|
### Logical Properties
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
Key mappings: `margin-left` -> `margin-inline-start`, `padding-top` -> `padding-block-start`, `width` -> `inline-size`, `height` -> `block-size`.
|
|
93
|
-
|
|
94
|
-
```css
|
|
95
|
-
.sidebar { margin-inline-end: 2rem; padding-block: 1rem; border-inline-start: 3px solid var(--accent); }
|
|
96
|
-
```
|
|
37
|
+
Direction-agnostic layouts (LTR/RTL safe): `margin-inline-start`, `padding-block`, `inline-size`, `border-inline-start`.
|
|
97
38
|
|
|
98
39
|
### Subgrid
|
|
99
|
-
Child grids align to parent grid tracks.
|
|
100
|
-
|
|
101
|
-
```css
|
|
102
|
-
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
|
|
103
|
-
.grid > .card {
|
|
104
|
-
display: grid;
|
|
105
|
-
grid-row: span 3;
|
|
106
|
-
grid-template-rows: subgrid;
|
|
107
|
-
}
|
|
108
|
-
```
|
|
40
|
+
Child grids align to parent grid tracks: `grid-template-rows: subgrid` on a child spanning multiple rows.
|
|
109
41
|
|
|
110
42
|
### Popover API
|
|
111
|
-
Native popovers with light-dismiss, no JS
|
|
112
|
-
|
|
113
|
-
```html
|
|
114
|
-
<button popovertarget="info">Info</button>
|
|
115
|
-
<div popover id="info">Content here. Click outside to dismiss.</div>
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
```css
|
|
119
|
-
[popover] {
|
|
120
|
-
&::backdrop { background: rgb(0 0 0 / 0.25); }
|
|
121
|
-
opacity: 0; transition: opacity 0.2s, display 0.2s allow-discrete;
|
|
122
|
-
&:popover-open { opacity: 1; }
|
|
123
|
-
}
|
|
124
|
-
```
|
|
43
|
+
Native popovers with light-dismiss, no JS: `<button popovertarget="id">` + `<div popover id="id">`.
|
|
125
44
|
|
|
126
45
|
---
|
|
127
46
|
|
|
128
|
-
## 2. Core Web Vitals
|
|
47
|
+
## 2. Core Web Vitals
|
|
129
48
|
|
|
130
49
|
**Thresholds:** LCP < 2.5s | CLS < 0.1 | INP < 200ms
|
|
131
50
|
|
|
132
51
|
### LCP (Largest Contentful Paint)
|
|
133
|
-
- Preload hero images
|
|
134
|
-
-
|
|
135
|
-
-
|
|
136
|
-
- Use CDN, compress with Brotli.
|
|
52
|
+
- Preload hero images with `fetchpriority="high"`
|
|
53
|
+
- Inline critical CSS, eliminate render-blocking resources
|
|
54
|
+
- Use CDN + Brotli compression
|
|
137
55
|
|
|
138
56
|
### CLS (Cumulative Layout Shift)
|
|
139
|
-
- Always set `width`/`height` or `aspect-ratio` on images
|
|
140
|
-
- Reserve space for ads/embeds with `min-height
|
|
141
|
-
- Use `font-display: optional` (best CLS) or `swap` (best UX)
|
|
142
|
-
-
|
|
57
|
+
- Always set `width`/`height` or `aspect-ratio` on images/video
|
|
58
|
+
- Reserve space for ads/embeds with `min-height`
|
|
59
|
+
- Use `font-display: optional` (best CLS) or `swap` (best UX)
|
|
60
|
+
- Never insert content above the fold after load
|
|
143
61
|
|
|
144
62
|
### INP (Interaction to Next Paint)
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
button.addEventListener('click', () => {
|
|
149
|
-
button.classList.add('pressed'); // instant visual feedback
|
|
150
|
-
requestAnimationFrame(() => {
|
|
151
|
-
setTimeout(() => doHeavyWork(), 0); // yield to browser
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
- Break long tasks with `scheduler.yield()` (or `setTimeout(0)` fallback).
|
|
157
|
-
- Use `content-visibility: auto` for off-screen DOM.
|
|
158
|
-
- Avoid layout thrashing: batch reads, then batch writes.
|
|
63
|
+
- Provide instant visual feedback, defer heavy work with `scheduler.yield()` or `setTimeout(0)`
|
|
64
|
+
- Use `content-visibility: auto` for off-screen DOM
|
|
65
|
+
- Avoid layout thrashing: batch reads, then batch writes
|
|
159
66
|
|
|
160
67
|
---
|
|
161
68
|
|
|
@@ -168,180 +75,61 @@ button.addEventListener('click', () => {
|
|
|
168
75
|
| **SVG** | Icons, logos, illustrations | Infinitely scalable |
|
|
169
76
|
| **PNG** | Screenshots, pixel-precise | Lossless only |
|
|
170
77
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
```html
|
|
174
|
-
<picture>
|
|
175
|
-
<source srcset="hero.avif" type="image/avif">
|
|
176
|
-
<source srcset="hero.webp" type="image/webp">
|
|
177
|
-
<img src="hero.jpg"
|
|
178
|
-
srcset="hero-400.jpg 400w, hero-800.jpg 800w, hero-1200.jpg 1200w"
|
|
179
|
-
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 33vw"
|
|
180
|
-
alt="Hero" width="1200" height="675"
|
|
181
|
-
loading="lazy" decoding="async">
|
|
182
|
-
</picture>
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
**Rules:** Never lazy-load above-the-fold images (hurts LCP). Use `fetchpriority="high"` on LCP image. Always include `width`/`height` for CLS prevention.
|
|
186
|
-
|
|
187
|
-
### Blur-Up Placeholder
|
|
188
|
-
|
|
189
|
-
```css
|
|
190
|
-
.img-placeholder {
|
|
191
|
-
background: url('data:image/webp;base64,...') center/cover;
|
|
192
|
-
aspect-ratio: 16/9;
|
|
193
|
-
}
|
|
194
|
-
.img-placeholder img {
|
|
195
|
-
opacity: 0; transition: opacity 0.3s;
|
|
196
|
-
&.loaded { opacity: 1; }
|
|
197
|
-
}
|
|
198
|
-
```
|
|
78
|
+
**Rules:** Use `<picture>` with AVIF/WebP sources + JPEG fallback. Never lazy-load above-the-fold (hurts LCP). Use `fetchpriority="high"` on LCP image. Always include `width`/`height`. Use blur-up placeholder for perceived performance.
|
|
199
79
|
|
|
200
80
|
---
|
|
201
81
|
|
|
202
82
|
## 4. Font Performance
|
|
203
83
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
```css
|
|
211
|
-
@font-face {
|
|
212
|
-
font-family: 'Display';
|
|
213
|
-
src: url('/fonts/display.woff2') format('woff2');
|
|
214
|
-
font-weight: 100 900;
|
|
215
|
-
font-display: swap;
|
|
216
|
-
unicode-range: U+0000-00FF;
|
|
217
|
-
}
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### font-display Decision Guide
|
|
221
|
-
- **`swap`**: shows fallback immediately, swaps when loaded. Best for body text. Causes FOUT.
|
|
222
|
-
- **`optional`**: uses web font only if cached/instant. Best CLS score.
|
|
223
|
-
- **`fallback`**: 100ms blank, then fallback, short swap window. Good compromise.
|
|
224
|
-
- **`block`**: up to 3s invisible text (FOIT). Avoid for body text.
|
|
225
|
-
|
|
226
|
-
### Variable Fonts
|
|
227
|
-
One file replaces multiple weight/style files. Use when you need 3+ weights. A single variable font (~90KB) replaces 6 static files (360KB+).
|
|
228
|
-
|
|
229
|
-
### Subsetting
|
|
230
|
-
Strip unused glyphs with `pyftsubset` or `glyphhanger`. Can reduce 200KB+ files to 15-30KB.
|
|
84
|
+
- Preload primary font: `<link rel="preload" as="font" type="font/woff2" crossorigin>`
|
|
85
|
+
- Use `font-display: swap` (body text) or `optional` (best CLS)
|
|
86
|
+
- Variable fonts: one file replaces multiple weights (~90KB vs 360KB+)
|
|
87
|
+
- Subset with `pyftsubset` or `glyphhanger` (200KB+ down to 15-30KB)
|
|
88
|
+
- Use `unicode-range` to load only needed glyphs
|
|
231
89
|
|
|
232
90
|
---
|
|
233
91
|
|
|
234
92
|
## 5. Critical CSS & Resource Hints
|
|
235
93
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
<style>/* inlined above-the-fold styles, ~14KB max */</style>
|
|
241
|
-
<link rel="preload" href="/styles.css" as="style" onload="this.rel='stylesheet'">
|
|
242
|
-
<noscript><link rel="stylesheet" href="/styles.css"></noscript>
|
|
243
|
-
</head>
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
### Resource Hints
|
|
247
|
-
|
|
248
|
-
```html
|
|
249
|
-
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
250
|
-
<link rel="dns-prefetch" href="https://analytics.example.com">
|
|
251
|
-
<link rel="preload" href="/critical.woff2" as="font" crossorigin>
|
|
252
|
-
<link rel="prefetch" href="/next-page.js">
|
|
253
|
-
<link rel="modulepreload" href="/app.js">
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
**Build tools:** Use `critical` (npm) or `critters` (webpack/vite plugin) to auto-extract above-fold CSS at build time.
|
|
94
|
+
- Inline above-the-fold CSS (~14KB max) in `<head>`
|
|
95
|
+
- Preload remaining stylesheet with `onload="this.rel='stylesheet'"`
|
|
96
|
+
- Resource hints: `preconnect` (fonts, APIs), `dns-prefetch` (analytics), `prefetch` (next page), `modulepreload` (app JS)
|
|
97
|
+
- Auto-extract with `critical` (npm) or `critters` (webpack/vite)
|
|
257
98
|
|
|
258
99
|
---
|
|
259
100
|
|
|
260
101
|
## 6. Tailwind CSS v4
|
|
261
102
|
|
|
262
|
-
Released January 2025.
|
|
263
|
-
|
|
264
|
-
### CSS-First Configuration
|
|
265
|
-
|
|
266
|
-
```css
|
|
267
|
-
@import "tailwindcss";
|
|
268
|
-
|
|
269
|
-
@theme {
|
|
270
|
-
--color-brand: oklch(0.65 0.25 260);
|
|
271
|
-
--font-display: "Satoshi", sans-serif;
|
|
272
|
-
--breakpoint-3xl: 1920px;
|
|
273
|
-
--ease-fluid: cubic-bezier(0.3, 0, 0, 1);
|
|
274
|
-
}
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
No `tailwind.config.js` needed. All customization lives in CSS via `@theme`.
|
|
103
|
+
Released January 2025. Rust-based Oxide engine: full builds 3.8x faster, incremental 182x faster.
|
|
278
104
|
|
|
279
105
|
### Key Changes
|
|
280
|
-
-
|
|
281
|
-
-
|
|
282
|
-
-
|
|
283
|
-
-
|
|
284
|
-
-
|
|
285
|
-
-
|
|
106
|
+
- CSS-first config: `@import "tailwindcss"` + `@theme {}` (no `tailwind.config.js`)
|
|
107
|
+
- Automatic content detection (respects `.gitignore`)
|
|
108
|
+
- Built on `@layer`, `@property`, `color-mix()`
|
|
109
|
+
- Container queries: `@sm:`, `@md:` variants
|
|
110
|
+
- 3D transforms: `rotate-x-45 transform-3d perspective-distant`
|
|
111
|
+
- `@starting-style` for enter/exit transitions
|
|
112
|
+
- `not-*` variant: `not-hover:opacity-75`, `not-last:border-b`
|
|
286
113
|
|
|
287
114
|
---
|
|
288
115
|
|
|
289
116
|
## 7. Advanced Animation APIs
|
|
290
117
|
|
|
291
118
|
### View Transitions API
|
|
292
|
-
|
|
293
|
-
```css
|
|
294
|
-
@view-transition { navigation: auto; }
|
|
295
|
-
.hero-image { view-transition-name: hero; }
|
|
296
|
-
::view-transition-old(hero) { animation: fade-out 0.3s ease-out; }
|
|
297
|
-
::view-transition-new(hero) { animation: fade-in 0.3s ease-in; }
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
```js
|
|
301
|
-
document.startViewTransition(() => updateDOM());
|
|
302
|
-
```
|
|
119
|
+
Name elements with `view-transition-name`, style with `::view-transition-old/new`. Trigger with `document.startViewTransition(() => updateDOM())`. CSS-only for MPA: `@view-transition { navigation: auto; }`.
|
|
303
120
|
|
|
304
121
|
### Scroll-Driven Animations (No JS, Off Main Thread)
|
|
305
|
-
|
|
122
|
+
Bind animations to scroll or view progress:
|
|
306
123
|
```css
|
|
307
|
-
.progress-bar {
|
|
308
|
-
|
|
309
|
-
animation-timeline: scroll();
|
|
310
|
-
}
|
|
311
|
-
@keyframes grow-width { from { width: 0; } to { width: 100%; } }
|
|
312
|
-
|
|
313
|
-
.reveal {
|
|
314
|
-
animation: fade-slide-up linear both;
|
|
315
|
-
animation-timeline: view();
|
|
316
|
-
animation-range: entry 0% entry 100%;
|
|
317
|
-
}
|
|
318
|
-
@keyframes fade-slide-up {
|
|
319
|
-
from { opacity: 0; translate: 0 2rem; }
|
|
320
|
-
to { opacity: 1; translate: 0; }
|
|
321
|
-
}
|
|
124
|
+
.progress-bar { animation: grow linear; animation-timeline: scroll(); }
|
|
125
|
+
.reveal { animation: fade-up linear both; animation-timeline: view(); animation-range: entry 0% entry 100%; }
|
|
322
126
|
```
|
|
323
127
|
|
|
324
128
|
### Web Animations API (WAAPI)
|
|
325
|
-
|
|
326
|
-
```js
|
|
327
|
-
element.animate(
|
|
328
|
-
[{ transform: 'translateY(0)', opacity: 1 },
|
|
329
|
-
{ transform: 'translateY(-20px)', opacity: 0 }],
|
|
330
|
-
{ duration: 300, easing: 'ease-out', fill: 'forwards' }
|
|
331
|
-
);
|
|
332
|
-
```
|
|
129
|
+
`element.animate([keyframes], options)` for programmatic control with `duration`, `easing`, `fill`.
|
|
333
130
|
|
|
334
131
|
### GSAP ScrollTrigger
|
|
335
|
-
|
|
336
|
-
```js
|
|
337
|
-
gsap.to('.hero-title', {
|
|
338
|
-
scrollTrigger: {
|
|
339
|
-
trigger: '.hero', start: 'top top', end: 'bottom top',
|
|
340
|
-
scrub: true, pin: true
|
|
341
|
-
},
|
|
342
|
-
y: -100, opacity: 0, scale: 0.9
|
|
343
|
-
});
|
|
344
|
-
```
|
|
132
|
+
For complex scroll-linked animations with `scrub`, `pin`, and timeline control.
|
|
345
133
|
|
|
346
134
|
---
|
|
347
135
|
|