get-shit-pretty 0.5.0 → 0.5.2
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/.claude-plugin/plugin.json +1 -1
- package/README.md +1 -1
- package/bin/install.js +38 -19
- package/gsp/agents/gsp-accessibility-auditor.md +1 -4
- package/gsp/agents/gsp-ascii-artist.md +1 -1
- package/gsp/agents/gsp-brand-auditor.md +0 -2
- package/gsp/agents/gsp-brand-strategist.md +0 -2
- package/gsp/agents/gsp-brand-syncer.md +125 -0
- package/gsp/agents/gsp-builder.md +11 -14
- package/gsp/agents/gsp-campaign-director.md +0 -20
- package/gsp/agents/gsp-critic.md +15 -18
- package/gsp/agents/gsp-designer.md +6 -6
- package/gsp/agents/gsp-identity-designer.md +0 -4
- package/gsp/agents/{gsp-system-architect.md → gsp-pattern-architect.md} +5 -67
- package/gsp/agents/gsp-project-researcher.md +0 -21
- package/gsp/agents/gsp-researcher.md +0 -2
- package/gsp/agents/gsp-reviewer.md +4 -14
- package/gsp/agents/gsp-scoper.md +1 -22
- package/gsp/hooks/hooks.json +11 -0
- package/gsp/prompts/01-design-system-architect.md +0 -46
- package/gsp/prompts/02-brand-identity-creator.md +1 -14
- package/gsp/prompts/03-ui-ux-pattern-master.md +1 -21
- package/gsp/prompts/04-marketing-asset-factory.md +1 -14
- package/gsp/prompts/05-implementation-spec-expert.md +0 -27
- package/gsp/prompts/06-design-critique-partner.md +1 -17
- package/gsp/prompts/07-design-trend-synthesizer.md +2 -29
- package/gsp/prompts/08-accessibility-auditor.md +4 -19
- package/gsp/prompts/09-design-to-code-translator.md +21 -20
- package/gsp/prompts/10-project-scoper.md +2 -36
- package/gsp/prompts/11-deliverable-reviewer.md +1 -50
- package/gsp/prompts/12-project-researcher.md +0 -39
- package/gsp/references/anti-patterns.md +173 -0
- package/gsp/references/block-patterns.md +135 -0
- package/gsp/references/chunk-format.md +31 -0
- package/gsp/references/phase-transitions.md +78 -33
- package/gsp/references/style-preset-schema.md +63 -0
- package/gsp/references/visual-effects.md +475 -0
- package/gsp/references/visual-taste.md +120 -0
- package/gsp/skills/gsp-accessibility/SKILL.md +1 -1
- package/gsp/skills/gsp-brand-audit/SKILL.md +1 -3
- package/gsp/skills/gsp-brand-identity/SKILL.md +1 -4
- package/gsp/skills/gsp-brand-patterns/SKILL.md +30 -50
- package/gsp/skills/gsp-brand-research/SKILL.md +7 -4
- package/gsp/skills/gsp-brand-strategy/SKILL.md +1 -4
- package/gsp/skills/gsp-brand-sync/SKILL.md +101 -0
- package/gsp/skills/gsp-design-system/SKILL.md +1 -1
- package/gsp/skills/gsp-doctor/SKILL.md +7 -7
- package/gsp/skills/gsp-help/SKILL.md +2 -1
- package/gsp/skills/gsp-launch/SKILL.md +2 -3
- package/gsp/skills/gsp-project-brief/SKILL.md +7 -22
- package/gsp/skills/gsp-project-build/SKILL.md +108 -26
- package/gsp/skills/gsp-project-critique/SKILL.md +5 -33
- package/gsp/skills/gsp-project-design/SKILL.md +25 -26
- package/gsp/skills/gsp-project-research/SKILL.md +8 -17
- package/gsp/skills/gsp-project-review/SKILL.md +6 -37
- package/gsp/skills/gsp-start/SKILL.md +29 -12
- package/gsp/skills/gsp-style/SKILL.md +20 -223
- package/gsp/skills/gsp-typescale/SKILL.md +23 -319
- package/gsp/skills/gsp-update/SKILL.md +18 -10
- package/gsp/templates/branding/brief.md +13 -1
- package/gsp/templates/branding/roadmap.md +2 -2
- package/gsp/templates/branding/state.md +1 -1
- package/gsp/templates/phases/brief.md +1 -1
- package/gsp/templates/phases/{system.md → patterns.md} +3 -3
- package/gsp/templates/phases/review.md +1 -1
- package/package.json +1 -1
- package/scripts/gsp-context-recovery.sh +71 -0
- package/scripts/gsp-statusline.js +5 -1
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
# Visual Effects Reference — CSS Recipes
|
|
2
|
+
|
|
3
|
+
Production-ready CSS and Tailwind snippets for visual polish. Adapt values to the brand's tokens.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Depth & Shadows
|
|
8
|
+
|
|
9
|
+
### Layered shadows
|
|
10
|
+
|
|
11
|
+
```css
|
|
12
|
+
/* Subtle — cards, inputs */
|
|
13
|
+
shadow-sm: 0 1px 2px rgba(0,0,0,0.04), 0 1px 4px rgba(0,0,0,0.06);
|
|
14
|
+
|
|
15
|
+
/* Medium — elevated cards, dropdowns */
|
|
16
|
+
shadow-md: 0 4px 6px rgba(0,0,0,0.04), 0 10px 24px rgba(0,0,0,0.08);
|
|
17
|
+
|
|
18
|
+
/* Dramatic — modals, floating elements */
|
|
19
|
+
shadow-lg: 0 8px 16px rgba(0,0,0,0.08), 0 24px 48px rgba(0,0,0,0.12);
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Glow effects
|
|
23
|
+
|
|
24
|
+
```css
|
|
25
|
+
/* Primary color glow — CTAs, active states */
|
|
26
|
+
box-shadow: 0 0 20px rgba(var(--color-primary-rgb), 0.3), 0 0 40px rgba(var(--color-primary-rgb), 0.1);
|
|
27
|
+
|
|
28
|
+
/* Ambient glow — hero accents */
|
|
29
|
+
box-shadow: 0 0 80px 40px rgba(var(--color-accent-rgb), 0.15);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### Glassmorphism
|
|
33
|
+
|
|
34
|
+
```css
|
|
35
|
+
backdrop-filter: blur(16px) saturate(180%);
|
|
36
|
+
background: rgba(255, 255, 255, 0.08);
|
|
37
|
+
border: 1px solid rgba(255, 255, 255, 0.12);
|
|
38
|
+
/* Tailwind: backdrop-blur-xl backdrop-saturate-[180%] bg-white/[0.08] border border-white/[0.12] */
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
`@supports not (backdrop-filter: blur(1px))` — use solid bg with 90% opacity as fallback.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Backgrounds & Texture
|
|
46
|
+
|
|
47
|
+
### Gradient backgrounds
|
|
48
|
+
|
|
49
|
+
```css
|
|
50
|
+
/* Linear sweep — hero backgrounds */
|
|
51
|
+
background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-secondary) 100%);
|
|
52
|
+
|
|
53
|
+
/* Radial orb — decorative accent behind content */
|
|
54
|
+
background: radial-gradient(circle at 30% 20%, rgba(var(--color-accent-rgb), 0.25) 0%, transparent 60%);
|
|
55
|
+
|
|
56
|
+
/* Mesh gradient — layer 2-3 radial gradients */
|
|
57
|
+
background:
|
|
58
|
+
radial-gradient(at 20% 80%, rgba(var(--color-primary-rgb), 0.2) 0%, transparent 50%),
|
|
59
|
+
radial-gradient(at 80% 20%, rgba(var(--color-accent-rgb), 0.15) 0%, transparent 50%),
|
|
60
|
+
radial-gradient(at 50% 50%, rgba(var(--color-secondary-rgb), 0.1) 0%, transparent 60%);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Noise/grain texture
|
|
64
|
+
|
|
65
|
+
```css
|
|
66
|
+
/* SVG noise overlay — tactile surfaces */
|
|
67
|
+
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)' opacity='0.03'/%3E%3C/svg%3E");
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Grid/dot overlay
|
|
71
|
+
|
|
72
|
+
```css
|
|
73
|
+
/* Dot grid — tech/modern aesthetic, 3% opacity */
|
|
74
|
+
background-image: radial-gradient(circle, rgba(0,0,0,0.03) 1px, transparent 1px);
|
|
75
|
+
background-size: 24px 24px;
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## Motion & Animation
|
|
81
|
+
|
|
82
|
+
### Entrance animations
|
|
83
|
+
|
|
84
|
+
```css
|
|
85
|
+
/* Fade up — default content entrance */
|
|
86
|
+
@keyframes fade-up {
|
|
87
|
+
from { opacity: 0; transform: translateY(12px); }
|
|
88
|
+
to { opacity: 1; transform: translateY(0); }
|
|
89
|
+
}
|
|
90
|
+
.animate-fade-up { animation: fade-up 0.5s ease-out forwards; }
|
|
91
|
+
|
|
92
|
+
/* Stagger children — add delay per child */
|
|
93
|
+
.stagger > :nth-child(1) { animation-delay: 0ms; }
|
|
94
|
+
.stagger > :nth-child(2) { animation-delay: 80ms; }
|
|
95
|
+
.stagger > :nth-child(3) { animation-delay: 160ms; }
|
|
96
|
+
/* ... increment by 80ms */
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Hover transitions
|
|
100
|
+
|
|
101
|
+
```css
|
|
102
|
+
/* Lift + shadow shift — cards */
|
|
103
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
|
104
|
+
&:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
|
|
105
|
+
|
|
106
|
+
/* Scale + brighten — buttons */
|
|
107
|
+
transition: transform 0.15s ease, filter 0.15s ease;
|
|
108
|
+
&:hover { transform: scale(1.02); filter: brightness(1.1); }
|
|
109
|
+
|
|
110
|
+
/* Border glow — inputs, cards */
|
|
111
|
+
transition: box-shadow 0.2s ease;
|
|
112
|
+
&:hover { box-shadow: 0 0 0 2px rgba(var(--color-primary-rgb), 0.2); }
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Scroll-triggered reveals
|
|
116
|
+
|
|
117
|
+
```js
|
|
118
|
+
// Intersection Observer — add .visible class on scroll
|
|
119
|
+
const observer = new IntersectionObserver(
|
|
120
|
+
(entries) => entries.forEach(e => e.isIntersecting && e.target.classList.add('visible')),
|
|
121
|
+
{ threshold: 0.1 }
|
|
122
|
+
);
|
|
123
|
+
document.querySelectorAll('[data-animate]').forEach(el => observer.observe(el));
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Loading states
|
|
127
|
+
|
|
128
|
+
```css
|
|
129
|
+
/* Skeleton shimmer */
|
|
130
|
+
@keyframes shimmer {
|
|
131
|
+
0% { background-position: -200% 0; }
|
|
132
|
+
100% { background-position: 200% 0; }
|
|
133
|
+
}
|
|
134
|
+
.skeleton {
|
|
135
|
+
background: linear-gradient(90deg, var(--color-surface) 25%, var(--color-surface-hover) 50%, var(--color-surface) 75%);
|
|
136
|
+
background-size: 200% 100%;
|
|
137
|
+
animation: shimmer 1.5s infinite;
|
|
138
|
+
border-radius: var(--radius-sm);
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Typography Effects
|
|
145
|
+
|
|
146
|
+
### Gradient text
|
|
147
|
+
|
|
148
|
+
```css
|
|
149
|
+
background: linear-gradient(135deg, var(--color-primary), var(--color-accent));
|
|
150
|
+
-webkit-background-clip: text;
|
|
151
|
+
-webkit-text-fill-color: transparent;
|
|
152
|
+
background-clip: text;
|
|
153
|
+
/* Tailwind: bg-gradient-to-r from-primary to-accent bg-clip-text text-transparent */
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Text glow
|
|
157
|
+
|
|
158
|
+
```css
|
|
159
|
+
text-shadow: 0 0 20px rgba(var(--color-primary-rgb), 0.3);
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Component Polish
|
|
165
|
+
|
|
166
|
+
### Card hover
|
|
167
|
+
|
|
168
|
+
```css
|
|
169
|
+
/* Lift + shadow + subtle border */
|
|
170
|
+
.card {
|
|
171
|
+
transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
|
|
172
|
+
border: 1px solid transparent;
|
|
173
|
+
}
|
|
174
|
+
.card:hover {
|
|
175
|
+
transform: translateY(-4px);
|
|
176
|
+
box-shadow: var(--shadow-lg);
|
|
177
|
+
border-color: rgba(var(--color-primary-rgb), 0.1);
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Button state progression
|
|
182
|
+
|
|
183
|
+
```css
|
|
184
|
+
/* Rest → Hover → Active → Focus */
|
|
185
|
+
.btn {
|
|
186
|
+
transition: all 0.15s ease;
|
|
187
|
+
box-shadow: var(--shadow-sm);
|
|
188
|
+
}
|
|
189
|
+
.btn:hover { box-shadow: var(--shadow-md); transform: translateY(-1px); filter: brightness(1.05); }
|
|
190
|
+
.btn:active { box-shadow: var(--shadow-sm); transform: translateY(0); filter: brightness(0.95); }
|
|
191
|
+
.btn:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Image treatments
|
|
195
|
+
|
|
196
|
+
```css
|
|
197
|
+
/* Rounded + shadow — product images */
|
|
198
|
+
border-radius: var(--radius-lg); box-shadow: var(--shadow-md);
|
|
199
|
+
|
|
200
|
+
/* Hover zoom — gallery, cards */
|
|
201
|
+
.img-wrapper { overflow: hidden; border-radius: var(--radius-md); }
|
|
202
|
+
.img-wrapper img { transition: transform 0.3s ease; }
|
|
203
|
+
.img-wrapper:hover img { transform: scale(1.05); }
|
|
204
|
+
|
|
205
|
+
/* Gradient overlay — text over images */
|
|
206
|
+
background: linear-gradient(to top, rgba(0,0,0,0.7) 0%, transparent 60%);
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## Advanced Interactions
|
|
212
|
+
|
|
213
|
+
### Spotlight border cards
|
|
214
|
+
|
|
215
|
+
Mouse-tracking radial gradient on a pseudo-element, creating a glowing border that follows the cursor.
|
|
216
|
+
|
|
217
|
+
```css
|
|
218
|
+
.card { position: relative; border-radius: var(--radius-md); }
|
|
219
|
+
.card::before {
|
|
220
|
+
content: ''; position: absolute; inset: -1px; border-radius: inherit;
|
|
221
|
+
background: radial-gradient(600px circle at var(--x) var(--y),
|
|
222
|
+
rgba(var(--color-primary-rgb), 0.3), transparent 40%);
|
|
223
|
+
z-index: -1;
|
|
224
|
+
}
|
|
225
|
+
```
|
|
226
|
+
```js
|
|
227
|
+
card.addEventListener('mousemove', (e) => {
|
|
228
|
+
const r = card.getBoundingClientRect();
|
|
229
|
+
card.style.setProperty('--x', `${e.clientX - r.left}px`);
|
|
230
|
+
card.style.setProperty('--y', `${e.clientY - r.top}px`);
|
|
231
|
+
});
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**When to use:** Feature grids, pricing cards, portfolio tiles — anywhere cards need subtle life on hover.
|
|
235
|
+
|
|
236
|
+
### Parallax tilt cards
|
|
237
|
+
|
|
238
|
+
3D tilt effect tracking cursor position within the card bounds.
|
|
239
|
+
|
|
240
|
+
```css
|
|
241
|
+
.tilt-card {
|
|
242
|
+
perspective: 800px;
|
|
243
|
+
transform-style: preserve-3d;
|
|
244
|
+
transition: transform 0.1s ease-out;
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
```js
|
|
248
|
+
card.addEventListener('mousemove', (e) => {
|
|
249
|
+
const r = card.getBoundingClientRect();
|
|
250
|
+
const x = (e.clientX - r.left) / r.width - 0.5;
|
|
251
|
+
const y = (e.clientY - r.top) / r.height - 0.5;
|
|
252
|
+
card.style.transform = `rotateY(${x * 10}deg) rotateX(${y * -10}deg)`;
|
|
253
|
+
});
|
|
254
|
+
card.addEventListener('mouseleave', () => card.style.transform = 'none');
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
**When to use:** Product showcases, testimonial cards, image galleries where depth reinforces premium feel.
|
|
258
|
+
|
|
259
|
+
### Magnetic buttons
|
|
260
|
+
|
|
261
|
+
Element pulls toward cursor proximity using Framer Motion spring physics.
|
|
262
|
+
|
|
263
|
+
```tsx
|
|
264
|
+
const x = useMotionValue(0);
|
|
265
|
+
const y = useMotionValue(0);
|
|
266
|
+
function handleMouse(e: React.MouseEvent) {
|
|
267
|
+
const r = e.currentTarget.getBoundingClientRect();
|
|
268
|
+
x.set((e.clientX - r.left - r.width / 2) * 0.3);
|
|
269
|
+
y.set((e.clientY - r.top - r.height / 2) * 0.3);
|
|
270
|
+
}
|
|
271
|
+
<motion.button style={{ x, y }} onMouseMove={handleMouse}
|
|
272
|
+
onMouseLeave={() => { x.set(0); y.set(0); }}
|
|
273
|
+
transition={{ type: "spring", stiffness: 150, damping: 15 }} />
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Performance:** CRITICAL — use `useMotionValue`, never `useState` for continuous animation. useState triggers re-renders every frame.
|
|
277
|
+
**When to use:** Primary CTAs, nav icons, floating action buttons — sparingly, max 2-3 per viewport.
|
|
278
|
+
|
|
279
|
+
### Staggered orchestration
|
|
280
|
+
|
|
281
|
+
Cascade reveal for groups of elements entering the viewport.
|
|
282
|
+
|
|
283
|
+
```tsx
|
|
284
|
+
// Framer Motion — container orchestration
|
|
285
|
+
<motion.div variants={{ show: { transition: { staggerChildren: 0.08 } } }}
|
|
286
|
+
initial="hidden" whileInView="show" viewport={{ once: true }}>
|
|
287
|
+
{items.map(item => (
|
|
288
|
+
<motion.div key={item.id}
|
|
289
|
+
variants={{ hidden: { opacity: 0, y: 20 }, show: { opacity: 1, y: 0 } }} />
|
|
290
|
+
))}
|
|
291
|
+
</motion.div>
|
|
292
|
+
```
|
|
293
|
+
```css
|
|
294
|
+
/* CSS-only alternative */
|
|
295
|
+
.stagger-item { animation: fade-up 0.5s ease-out both;
|
|
296
|
+
animation-delay: calc(var(--index) * 80ms); }
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**When to use:** Feature lists, card grids, any repeated group entering on scroll. Limit to 6-8 items per stagger group.
|
|
300
|
+
|
|
301
|
+
### Spring physics defaults
|
|
302
|
+
|
|
303
|
+
Standard spring configurations for interactive elements. Never use linear easing for UI motion.
|
|
304
|
+
|
|
305
|
+
```tsx
|
|
306
|
+
// Interactive elements (buttons, toggles, cards)
|
|
307
|
+
transition={{ type: "spring", stiffness: 100, damping: 20 }}
|
|
308
|
+
|
|
309
|
+
// Snappy micro-interactions (checkboxes, switches)
|
|
310
|
+
transition={{ type: "spring", stiffness: 300, damping: 25 }}
|
|
311
|
+
|
|
312
|
+
// Gentle layout shifts (expanding panels, modals)
|
|
313
|
+
transition={{ type: "spring", stiffness: 60, damping: 18 }}
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
**Performance:** Spring physics self-resolve — no need to specify duration. Overdamped (damping > 2√stiffness) prevents oscillation.
|
|
317
|
+
**When to use:** Every animated element. Springs feel organic; linear/ease-in-out feel mechanical.
|
|
318
|
+
|
|
319
|
+
### Scroll-driven reveals
|
|
320
|
+
|
|
321
|
+
Native CSS scroll-driven animations or IntersectionObserver class toggling for entrance effects.
|
|
322
|
+
|
|
323
|
+
```css
|
|
324
|
+
/* CSS scroll-driven (modern browsers) */
|
|
325
|
+
@keyframes reveal { from { opacity: 0; translate: 0 30px; } }
|
|
326
|
+
.scroll-reveal {
|
|
327
|
+
animation: reveal linear both;
|
|
328
|
+
animation-timeline: view();
|
|
329
|
+
animation-range: entry 0% entry 40%;
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
```css
|
|
333
|
+
/* IO fallback — toggle class */
|
|
334
|
+
.reveal { opacity: 0; transform: translateY(20px); transition: all 0.6s ease-out; }
|
|
335
|
+
.reveal.visible { opacity: 1; transform: translateY(0); }
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
**Performance:** CSS `animation-timeline: view()` is compositor-driven — zero JS cost. Use IO fallback for Safari < 18.
|
|
339
|
+
**When to use:** Default entrance pattern for all below-fold content. Prefer CSS scroll-driven where supported.
|
|
340
|
+
|
|
341
|
+
### Sticky scroll stacking
|
|
342
|
+
|
|
343
|
+
Sections with `position: sticky` that stack as user scrolls, creating a layered card deck effect.
|
|
344
|
+
|
|
345
|
+
```css
|
|
346
|
+
.stack-section {
|
|
347
|
+
position: sticky;
|
|
348
|
+
top: calc(var(--index) * 40px);
|
|
349
|
+
height: 80vh;
|
|
350
|
+
border-radius: var(--radius-lg);
|
|
351
|
+
transition: scale 0.3s ease;
|
|
352
|
+
}
|
|
353
|
+
.stack-section:not(:last-child) { scale: calc(1 - var(--index) * 0.02); }
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**Performance:** Use `will-change: transform` on sticky elements. Limit to 4-6 stacking sections.
|
|
357
|
+
**When to use:** Case studies, feature deep-dives, storytelling sequences where layered reveal adds narrative weight.
|
|
358
|
+
|
|
359
|
+
### Horizontal scroll hijack
|
|
360
|
+
|
|
361
|
+
Vertical scroll input translates to horizontal gallery panning.
|
|
362
|
+
|
|
363
|
+
```css
|
|
364
|
+
.h-scroll-wrapper { overflow-x: scroll; scroll-snap-type: x mandatory; }
|
|
365
|
+
.h-scroll-wrapper > * {
|
|
366
|
+
scroll-snap-align: start; flex-shrink: 0; width: 80vw;
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
```js
|
|
370
|
+
// Alternative: translateX driven by scrollY
|
|
371
|
+
const x = useTransform(scrollY, [sectionTop, sectionBottom],
|
|
372
|
+
['0%', `-${(items.length - 1) * 100}%`]);
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
**Performance:** CSS `scroll-snap` is GPU-composited. JS transform approach needs `useMotionValue` for frame budgets.
|
|
376
|
+
**When to use:** Image galleries, timelines, portfolio showcases — when horizontal layout serves content better than vertical.
|
|
377
|
+
|
|
378
|
+
### Text mask reveal
|
|
379
|
+
|
|
380
|
+
Large typography with media showing through the text shape.
|
|
381
|
+
|
|
382
|
+
```css
|
|
383
|
+
.text-mask {
|
|
384
|
+
font-size: clamp(4rem, 12vw, 10rem);
|
|
385
|
+
font-weight: 900;
|
|
386
|
+
background: url('video-or-gradient.mp4') center/cover;
|
|
387
|
+
-webkit-background-clip: text;
|
|
388
|
+
background-clip: text;
|
|
389
|
+
-webkit-text-fill-color: transparent;
|
|
390
|
+
}
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
**Performance:** `background-clip: text` with video is paint-heavy — limit to one instance per page.
|
|
394
|
+
**When to use:** Hero headlines, section dividers, brand moments where type IS the visual.
|
|
395
|
+
|
|
396
|
+
### Kinetic marquee
|
|
397
|
+
|
|
398
|
+
Infinite horizontal text scroll, with hover pause or direction reversal.
|
|
399
|
+
|
|
400
|
+
```css
|
|
401
|
+
.marquee { overflow: hidden; white-space: nowrap; }
|
|
402
|
+
.marquee-inner {
|
|
403
|
+
display: inline-flex; gap: 2rem;
|
|
404
|
+
animation: scroll-x 20s linear infinite;
|
|
405
|
+
}
|
|
406
|
+
.marquee:hover .marquee-inner { animation-direction: reverse; }
|
|
407
|
+
@keyframes scroll-x { to { transform: translateX(-50%); } }
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
**Performance:** Duplicate content so the strip is 2× viewport width. `translateX` is compositor-only.
|
|
411
|
+
**When to use:** Logo walls, social proof tickers, decorative text bands between sections.
|
|
412
|
+
|
|
413
|
+
### Directional hover
|
|
414
|
+
|
|
415
|
+
Detect which side the cursor enters and animate a fill from that direction.
|
|
416
|
+
|
|
417
|
+
```js
|
|
418
|
+
function getDirection(e, el) {
|
|
419
|
+
const { top, left, width, height } = el.getBoundingClientRect();
|
|
420
|
+
const x = (e.clientX - left - width / 2) / width;
|
|
421
|
+
const y = (e.clientY - top - height / 2) / height;
|
|
422
|
+
return Math.round((Math.atan2(y, x) * (180 / Math.PI) + 180) / 90) % 4;
|
|
423
|
+
}
|
|
424
|
+
// Set CSS custom property: --enter-from: top|right|bottom|left
|
|
425
|
+
```
|
|
426
|
+
```css
|
|
427
|
+
.dir-hover::before {
|
|
428
|
+
transition: transform 0.3s ease;
|
|
429
|
+
transform: translateY(calc(var(--dir-y, 0) * 100%)) translateX(calc(var(--dir-x, 0) * 100%));
|
|
430
|
+
}
|
|
431
|
+
.dir-hover:hover::before { transform: translate(0, 0); }
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
**When to use:** Nav links, card overlays, image hover reveals — adds spatial awareness to interactions.
|
|
435
|
+
|
|
436
|
+
### Liquid glass refraction
|
|
437
|
+
|
|
438
|
+
Beyond basic glassmorphism — simulating realistic glass edge refraction and depth.
|
|
439
|
+
|
|
440
|
+
```css
|
|
441
|
+
.liquid-glass {
|
|
442
|
+
backdrop-filter: blur(20px) saturate(200%);
|
|
443
|
+
background: rgba(255, 255, 255, 0.05);
|
|
444
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
445
|
+
box-shadow:
|
|
446
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.1), /* top edge highlight */
|
|
447
|
+
inset 0 -1px 0 rgba(0, 0, 0, 0.05), /* bottom edge shadow */
|
|
448
|
+
0 8px 32px rgba(0, 0, 0, 0.12);
|
|
449
|
+
border-radius: var(--radius-lg);
|
|
450
|
+
}
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
**Performance:** `backdrop-filter` triggers compositing — avoid stacking multiple blurred layers.
|
|
454
|
+
**When to use:** Floating toolbars, modal overlays, nav bars over dynamic backgrounds — upgrade from flat glassmorphism.
|
|
455
|
+
|
|
456
|
+
---
|
|
457
|
+
|
|
458
|
+
## Accessibility
|
|
459
|
+
|
|
460
|
+
All visual effects must degrade gracefully:
|
|
461
|
+
|
|
462
|
+
```css
|
|
463
|
+
@media (prefers-reduced-motion: reduce) {
|
|
464
|
+
*, *::before, *::after {
|
|
465
|
+
animation-duration: 0.01ms !important;
|
|
466
|
+
animation-iteration-count: 1 !important;
|
|
467
|
+
transition-duration: 0.01ms !important;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
- Glow/shadow: ensure text contrast meets WCAG AA without effects
|
|
473
|
+
- Backdrop-blur: `@supports not (backdrop-filter: blur(1px))` solid bg fallback
|
|
474
|
+
- Gradient text: test contrast ratio of gradient endpoints, not just midpoint
|
|
475
|
+
- Hover transforms: keep magnitude small (2-4px translate, 1.02-1.05 scale) to avoid disorientation
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Visual Taste Evaluation Framework
|
|
2
|
+
|
|
3
|
+
Companion to `nielsen-heuristics.md`. Nielsen measures usability (/50); this measures visual quality (/75). Both are evaluated independently during critique — a design can score high on one and low on the other.
|
|
4
|
+
|
|
5
|
+
## What Taste Means
|
|
6
|
+
|
|
7
|
+
Taste is intentionality in every decision. It's the difference between assembling parts and composing an experience.
|
|
8
|
+
|
|
9
|
+
- **Signal vs noise** — knowing what deserves emphasis and what should fade
|
|
10
|
+
- **Visual coherence** — all elements speaking the same design language
|
|
11
|
+
- **Confidence in constraints** — doing less with more intention
|
|
12
|
+
- **The gap between "it works" and "it feels right"**
|
|
13
|
+
- **Not decoration** — it's the absence of things that shouldn't be there
|
|
14
|
+
|
|
15
|
+
Taste cannot be added at the end. It's a quality that emerges when every decision — type, color, spacing, motion, content — serves the same story.
|
|
16
|
+
|
|
17
|
+
## Sophistication Scale
|
|
18
|
+
|
|
19
|
+
| Level | Name | Description | Examples |
|
|
20
|
+
|-------|------|-------------|----------|
|
|
21
|
+
| 1 | Default | Browser defaults, no styling intention. Looks like a homework assignment. | Unstyled HTML, Craigslist |
|
|
22
|
+
| 2 | Functional | Styled but generic. Could be any product. Uses a component library without customization. | Default Bootstrap site, early-stage SaaS with Tailwind defaults |
|
|
23
|
+
| 3 | Polished | Consistent, professional, follows best practices. Looks like a well-made product. | Notion, Slack, most well-funded SaaS products |
|
|
24
|
+
| 4 | Refined | Intentional details, personality showing through. You notice the craft. | Raycast, Arc Browser, Lottie |
|
|
25
|
+
| 5 | Distinctive | Unmistakably this brand. Memorable. You'd recognize it without the logo. | Linear, Stripe, Vercel |
|
|
26
|
+
|
|
27
|
+
## Taste Evaluation Checklist
|
|
28
|
+
|
|
29
|
+
Score each item 1-5. Total: X/75.
|
|
30
|
+
|
|
31
|
+
### 1. Typography personality
|
|
32
|
+
Does the type choice have character beyond the default? Score 1 if Inter/system font with no hierarchy. Score 5 if a distinctive pairing embodies brand personality with clear weight and size hierarchy.
|
|
33
|
+
|
|
34
|
+
### 2. Color intentionality
|
|
35
|
+
Is the palette considered or default? Score 1 if random, oversaturated, or too many hues. Score 5 if a cohesive system with clear semantic hierarchy and tinted neutrals.
|
|
36
|
+
|
|
37
|
+
### 3. Spacing rhythm
|
|
38
|
+
Does whitespace feel intentional or arbitrary? Score 1 if inconsistent padding with no scale. Score 5 if a clear vertical rhythm creates breathing room and content grouping.
|
|
39
|
+
|
|
40
|
+
### 4. Shadow & depth
|
|
41
|
+
Are surfaces creating meaningful hierarchy? Score 1 if flat or generic `box-shadow: 0 2px 4px rgba(0,0,0,.1)`. Score 5 if tinted shadows with consistent light direction communicate z-layers.
|
|
42
|
+
|
|
43
|
+
### 5. Motion personality
|
|
44
|
+
Does animation match the brand's energy? Score 1 if no motion or linear easing. Score 5 if spring physics, choreographed entrances, and exit animations match brand character.
|
|
45
|
+
|
|
46
|
+
### 6. Content authenticity
|
|
47
|
+
Does copy feel real or templated? Score 1 if Lorem Ipsum, "Welcome to our platform," or AI cliches. Score 5 if specific, voice-consistent, believable content throughout.
|
|
48
|
+
|
|
49
|
+
### 7. Component individuality
|
|
50
|
+
Are components styled to brand or default? Score 1 if stock library defaults (default Radix, unstyled shadcn). Score 5 if radius, color, shadow, and motion are customized to match brand DNA.
|
|
51
|
+
|
|
52
|
+
### 8. Layout confidence
|
|
53
|
+
Does the layout make bold choices or play it safe? Score 1 if generic centered single-column symmetry. Score 5 if intentional asymmetry, creative grid usage, or distinctive composition that serves the content.
|
|
54
|
+
|
|
55
|
+
### 9. Visual coherence
|
|
56
|
+
Do all elements speak the same design language? Score 1 if mixing incompatible styles (glassmorphism + neubrutalism + flat). Score 5 if every element reinforces one visual story.
|
|
57
|
+
|
|
58
|
+
### 10. Surface texture
|
|
59
|
+
Is there tactile quality or is it flat? Score 1 if pure flat vectors with no material quality. Score 5 if subtle grain, glass refraction, or tinted shadows create physical presence appropriate to brand.
|
|
60
|
+
|
|
61
|
+
### 11. State completeness
|
|
62
|
+
Are all interaction states designed? Score 1 if hover, active, loading, empty, and error states are missing or unstyled. Score 5 if every state feels intentional with smooth transitions between them.
|
|
63
|
+
|
|
64
|
+
### 12. Responsive craft
|
|
65
|
+
Is mobile a first-class experience? Score 1 if "it fits on mobile" is the only consideration. Score 5 if mobile has its own considered layout with touch-appropriate sizing and gestures.
|
|
66
|
+
|
|
67
|
+
### 13. Icon consistency
|
|
68
|
+
Unified family, weight, style? Score 1 if mixed icon sets, inconsistent weights, or mismatched sizing. Score 5 if one curated set with consistent stroke width and optical alignment throughout.
|
|
69
|
+
|
|
70
|
+
### 14. Image direction
|
|
71
|
+
Do images match brand personality? Score 1 if stock photos, broken URLs, or placeholder boxes. Score 5 if imagery style (photography, illustration, generative, CSS-only) is a deliberate brand choice.
|
|
72
|
+
|
|
73
|
+
### 15. Overall impression
|
|
74
|
+
Does it feel like a $150k agency build? Score 1 if it looks AI-generated or template-derived. Score 5 if someone would ask "who designed this?"
|
|
75
|
+
|
|
76
|
+
## Scoring
|
|
77
|
+
|
|
78
|
+
**X/75 total**, mapped to sophistication levels:
|
|
79
|
+
|
|
80
|
+
- **15-25**: Level 1-2 (Default/Functional) — needs significant visual work
|
|
81
|
+
- **26-40**: Level 3 (Polished) — professional but not distinctive
|
|
82
|
+
- **41-55**: Level 4 (Refined) — shows craft and personality
|
|
83
|
+
- **56-75**: Level 5 (Distinctive) — agency-quality, memorable
|
|
84
|
+
|
|
85
|
+
## How to Improve Each Level
|
|
86
|
+
|
|
87
|
+
### Level 2 → 3 (Functional → Polished)
|
|
88
|
+
|
|
89
|
+
- Swap default fonts for a considered pairing
|
|
90
|
+
- Establish a consistent spacing scale (4/8px or similar)
|
|
91
|
+
- Add hover states and transitions to all interactive elements
|
|
92
|
+
- Use one accent color consistently with tinted neutrals
|
|
93
|
+
- Add loading and empty states
|
|
94
|
+
|
|
95
|
+
### Level 3 → 4 (Polished → Refined)
|
|
96
|
+
|
|
97
|
+
- Customize component library beyond defaults (radius, shadows, colors)
|
|
98
|
+
- Add subtle texture (noise grain, tinted shadows, soft gradients)
|
|
99
|
+
- Introduce spring physics for interactive motion
|
|
100
|
+
- Use staggered entrances instead of instant mounting
|
|
101
|
+
- Make responsive layouts feel native to each breakpoint
|
|
102
|
+
|
|
103
|
+
### Level 4 → 5 (Refined → Distinctive)
|
|
104
|
+
|
|
105
|
+
- Create signature visual patterns unique to this brand
|
|
106
|
+
- Use advanced interactions (spotlight borders, magnetic elements, scroll choreography)
|
|
107
|
+
- Ensure every surface, shadow, and animation reinforces brand personality
|
|
108
|
+
- Content feels authored — specific voice, real data, believable context
|
|
109
|
+
- Someone could identify the brand from a screenshot without the logo
|
|
110
|
+
|
|
111
|
+
## How to Use
|
|
112
|
+
|
|
113
|
+
This reference is loaded by the critique agent alongside `references/nielsen-heuristics.md`. During critique:
|
|
114
|
+
|
|
115
|
+
1. Score each of the 15 taste items 1-5 with specific examples from the design
|
|
116
|
+
2. Calculate total and map to sophistication level
|
|
117
|
+
3. Write taste evaluation as a section in `critique.md`
|
|
118
|
+
4. Include taste-specific fixes in `prioritized-fixes.md`
|
|
119
|
+
|
|
120
|
+
Usability (Nielsen's, /50) and Taste (/75) are evaluated separately. A design can be highly usable but lack taste, or be visually stunning but have usability problems. Both dimensions must be addressed.
|
|
@@ -117,7 +117,7 @@ Convert hex to relative luminance (sRGB linearization), then:
|
|
|
117
117
|
Read token and palette files from the brand/project:
|
|
118
118
|
- `{BRAND_PATH}/identity/palettes.json`
|
|
119
119
|
- `{BRAND_PATH}/identity/color-system.md`
|
|
120
|
-
- `{BRAND_PATH}/
|
|
120
|
+
- `{BRAND_PATH}/patterns/tokens.json`
|
|
121
121
|
- `{BRAND_PATH}/identity/typography.md`
|
|
122
122
|
|
|
123
123
|
If files don't exist, report which are missing and stop.
|
|
@@ -85,7 +85,5 @@ Update `evolution_scope` in `{BRAND_PATH}/config.json` with confirmed decisions.
|
|
|
85
85
|
|
|
86
86
|
Update `{BRAND_PATH}/STATE.md`: set Phase 0 (Audit) to `complete`.
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
- **Continue to research** — "validate brand position against the market"
|
|
90
|
-
- **Done for now** — "pick up later with /gsp:start"
|
|
88
|
+
Render phase transition (see `references/phase-transitions.md`).
|
|
91
89
|
</process>
|
|
@@ -124,8 +124,5 @@ Use `AskUserQuestion`:
|
|
|
124
124
|
|
|
125
125
|
Update `{BRAND_PATH}/STATE.md`: set Phase 3 (Identity) to `complete`, Prettiness Level to 80%.
|
|
126
126
|
|
|
127
|
-
Render phase transition
|
|
128
|
-
- **Continue to patterns** — "build tokens and components"
|
|
129
|
-
- **View progress** — "see the full dashboard"
|
|
130
|
-
- **Done for now** — "pick up later with /gsp:start"
|
|
127
|
+
Render phase transition (see `references/phase-transitions.md`).
|
|
131
128
|
</process>
|