@opendirectory.dev/skills 0.1.58 → 0.1.60

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.
@@ -0,0 +1,446 @@
1
+ # Animation Library — graphic-gif
2
+
3
+ 6 animation types for CSS-animated GIFs. All specs for 800×800px canvas (1vw = 8px).
4
+
5
+ Read this file before generating HTML in Step 3. Pick one animation type per GIF.
6
+
7
+ ---
8
+
9
+ ## 1. fade-in
10
+
11
+ Content fades in from transparent, with subtle upward drift.
12
+
13
+ **Best for:** Quotes, announcements, single-stat reveals, brand messages.
14
+
15
+ **Key technique:** `opacity: 0 → 1` + `translateY(12px → 0)` with smooth ease-out.
16
+
17
+ ```css
18
+ @keyframes fadeIn {
19
+ from {
20
+ opacity: 0;
21
+ transform: translateY(12px);
22
+ }
23
+ to {
24
+ opacity: 1;
25
+ transform: translateY(0);
26
+ }
27
+ }
28
+
29
+ .fade-item {
30
+ animation: fadeIn 0.8s cubic-bezier(0.22, 1, 0.36, 1) forwards;
31
+ opacity: 0; /* start hidden */
32
+ }
33
+ ```
34
+
35
+ **For staggered multi-element fade:**
36
+ Do NOT use `animation-delay`. Instead, structure the animation duration to reveal elements sequentially. Web Animations API will seek through the full timeline — each element needs its own named animation with different start points baked into its `@keyframes` percentages.
37
+
38
+ Example — 3 elements staggered within a 3s animation:
39
+ ```css
40
+ /* Element 1: reveals at 0–25% (0–750ms) */
41
+ @keyframes fadeEl1 {
42
+ 0% { opacity: 0; transform: translateY(12px); }
43
+ 25% { opacity: 1; transform: translateY(0); }
44
+ 100% { opacity: 1; transform: translateY(0); }
45
+ }
46
+ /* Element 2: reveals at 25–50% (750–1500ms) */
47
+ @keyframes fadeEl2 {
48
+ 0% { opacity: 0; transform: translateY(12px); }
49
+ 25% { opacity: 0; transform: translateY(12px); }
50
+ 50% { opacity: 1; transform: translateY(0); }
51
+ 100% { opacity: 1; transform: translateY(0); }
52
+ }
53
+ /* Element 3: reveals at 50–75% (1500–2250ms) */
54
+ @keyframes fadeEl3 {
55
+ 0% { opacity: 0; transform: translateY(12px); }
56
+ 50% { opacity: 0; transform: translateY(12px); }
57
+ 75% { opacity: 1; transform: translateY(0); }
58
+ 100% { opacity: 1; transform: translateY(0); }
59
+ }
60
+
61
+ .el1 { animation: fadeEl1 3s cubic-bezier(0.22, 1, 0.36, 1) forwards; }
62
+ .el2 { animation: fadeEl2 3s cubic-bezier(0.22, 1, 0.36, 1) forwards; }
63
+ .el3 { animation: fadeEl3 3s cubic-bezier(0.22, 1, 0.36, 1) forwards; }
64
+ ```
65
+
66
+ **HTML structure:**
67
+ ```html
68
+ <div class="canvas">
69
+ <div class="content">
70
+ <p class="el1 fade-item">Main message here</p>
71
+ <p class="el2 fade-item">Supporting line here</p>
72
+ <p class="el3 fade-item">Third element here</p>
73
+ </div>
74
+ </div>
75
+ ```
76
+
77
+ ---
78
+
79
+ ## 2. slide-in
80
+
81
+ Elements slide in from one edge with a spring overshoot effect.
82
+
83
+ **Best for:** Headlines, key stats, before/after comparisons, list reveals.
84
+
85
+ **Directions:** left (default), right, top, bottom.
86
+
87
+ **Key technique:** `translateX/Y` + spring cubic-bezier `(0.34, 1.56, 0.64, 1)` for overshoot.
88
+
89
+ ```css
90
+ /* Slide from left */
91
+ @keyframes slideInLeft {
92
+ from { opacity: 0; transform: translateX(-60px); }
93
+ to { opacity: 1; transform: translateX(0); }
94
+ }
95
+
96
+ /* Slide from right */
97
+ @keyframes slideInRight {
98
+ from { opacity: 0; transform: translateX(60px); }
99
+ to { opacity: 1; transform: translateX(0); }
100
+ }
101
+
102
+ /* Slide from bottom */
103
+ @keyframes slideInUp {
104
+ from { opacity: 0; transform: translateY(40px); }
105
+ to { opacity: 1; transform: translateY(0); }
106
+ }
107
+
108
+ .slide-item {
109
+ animation: slideInLeft 0.6s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
110
+ opacity: 0;
111
+ }
112
+ ```
113
+
114
+ **For sequential slide-in of multiple elements (bake stagger into keyframes):**
115
+ ```css
116
+ @keyframes slideEl1 {
117
+ 0% { opacity: 0; transform: translateX(-60px); }
118
+ 20% { opacity: 1; transform: translateX(0); }
119
+ 100% { opacity: 1; transform: translateX(0); }
120
+ }
121
+ @keyframes slideEl2 {
122
+ 0% { opacity: 0; transform: translateX(-60px); }
123
+ 20% { opacity: 0; transform: translateX(-60px); }
124
+ 40% { opacity: 1; transform: translateX(0); }
125
+ 100% { opacity: 1; transform: translateX(0); }
126
+ }
127
+ ```
128
+
129
+ ---
130
+
131
+ ## 3. typewriter
132
+
133
+ Text types out character by character. The most effective animation for revealing stats, insights, or hooks.
134
+
135
+ **Best for:** Single sentences, stat reveals, developer-audience content, hooks with tension.
136
+
137
+ **Key technique:** `steps(N, end)` with `overflow: hidden` and `width: 0 → 100%`. N = exact character count of the text string.
138
+
139
+ **Critical:** N MUST equal the exact character count of the text. Wrong N = wrong reveal speed.
140
+
141
+ ```css
142
+ .typewriter-text {
143
+ display: inline-block;
144
+ overflow: hidden;
145
+ white-space: nowrap;
146
+ border-right: 2px solid var(--accent);
147
+ animation:
148
+ typing 2.5s steps(N, end) forwards,
149
+ blink 0.75s step-end infinite;
150
+ width: 0;
151
+ max-width: 100%;
152
+ }
153
+
154
+ @keyframes typing {
155
+ from { width: 0; }
156
+ to { width: 100%; }
157
+ }
158
+
159
+ @keyframes blink {
160
+ from, to { border-color: transparent; }
161
+ 50% { border-color: var(--accent); }
162
+ }
163
+ ```
164
+
165
+ **Where N = character count:**
166
+ - Count spaces, punctuation, and numbers as characters
167
+ - "73% of buyers" → N = 14
168
+ - "Hello, World!" → N = 13
169
+
170
+ **For multi-line typewriter (sequential lines):**
171
+ Each line needs its own keyframe with percentage-baked timing:
172
+ ```css
173
+ /* Line 1: types from 0% to 40% of total duration */
174
+ @keyframes typeLine1 {
175
+ 0% { width: 0; }
176
+ 40% { width: 100%; }
177
+ 100% { width: 100%; }
178
+ }
179
+ /* Line 2: appears at 40%, types from 40% to 80% */
180
+ @keyframes typeLine2 {
181
+ 0% { width: 0; opacity: 0; }
182
+ 40% { width: 0; opacity: 0; }
183
+ 40.1%{ width: 0; opacity: 1; }
184
+ 80% { width: 100%; opacity: 1; }
185
+ 100% { width: 100%; opacity: 1; }
186
+ }
187
+
188
+ .line1 { animation: typeLine1 3s steps(N1, end) forwards; }
189
+ .line2 { animation: typeLine2 3s steps(N2, end) forwards; }
190
+ ```
191
+
192
+ **HTML structure:**
193
+ ```html
194
+ <div class="canvas">
195
+ <div class="typewriter-wrapper">
196
+ <span class="typewriter-text">Your text here exactly</span>
197
+ </div>
198
+ </div>
199
+ ```
200
+
201
+ ---
202
+
203
+ ## 4. counter
204
+
205
+ Numbers count up from 0 to a target value. Native CSS, no JavaScript.
206
+
207
+ **Best for:** Stats, metrics, growth numbers, percentages. High-impact for data-driven content.
208
+
209
+ **Key technique:** `@property --num` CSS custom property with integer interpolation. `counter-reset: num var(--num)` renders the integer as text via `::after { content: counter(num) }`.
210
+
211
+ **Critical:** Requires Chromium rendering (Playwright uses Chromium → works for GIF export).
212
+
213
+ ```css
214
+ @property --num {
215
+ syntax: '<integer>';
216
+ inherits: false;
217
+ initial-value: 0;
218
+ }
219
+
220
+ .counter {
221
+ animation: countUp var(--duration, 2s) linear forwards;
222
+ counter-reset: num var(--num);
223
+ }
224
+
225
+ .counter::after {
226
+ content: counter(num);
227
+ }
228
+
229
+ @keyframes countUp {
230
+ from { --num: 0; }
231
+ to { --num: var(--target); }
232
+ }
233
+ ```
234
+
235
+ **Usage (set target per element):**
236
+ ```html
237
+ <!-- Counts 0 → 73 over 2 seconds -->
238
+ <div class="counter" style="--target: 73; --duration: 2s;"></div>
239
+
240
+ <!-- Counts 0 → 500 over 3 seconds -->
241
+ <div class="counter" style="--target: 500; --duration: 3s;"></div>
242
+ ```
243
+
244
+ **For counter with suffix (%, K, etc.) — use ::before/::after wrappers:**
245
+ ```html
246
+ <div class="stat-block">
247
+ <span class="counter" style="--target: 73; --duration: 2s;"></span>
248
+ <span class="suffix">%</span>
249
+ </div>
250
+ ```
251
+
252
+ **For multiple counters with staggered start (bake into keyframes):**
253
+ ```css
254
+ /* Counter 1: counts during 0–60% of animation */
255
+ @keyframes count1 {
256
+ 0% { --num: 0; }
257
+ 60% { --num: 73; }
258
+ 100% { --num: 73; }
259
+ }
260
+ /* Counter 2: counts during 40–100% of animation */
261
+ @keyframes count2 {
262
+ 0% { --num: 0; }
263
+ 40% { --num: 0; }
264
+ 100% { --num: 250; }
265
+ }
266
+ ```
267
+
268
+ ---
269
+
270
+ ## 5. pulse
271
+
272
+ Pulsing / breathing scale or glow effect. Infinite loop by nature.
273
+
274
+ **Best for:** CTAs, icons, emphasis elements, "live" indicators, attention draws.
275
+
276
+ **Key technique:** `scale(1) → scale(1.06) → scale(1)` with `ease-in-out` and `animation-iteration-count: infinite`.
277
+
278
+ **Note:** Since this animation loops in CSS (`infinite`), the GIF frame capture simply captures `duration * fps` frames — the animation is already looping at the CSS level.
279
+
280
+ ```css
281
+ /* Scale pulse */
282
+ @keyframes pulse {
283
+ 0%, 100% { transform: scale(1); opacity: 1; }
284
+ 50% { transform: scale(1.06); opacity: 0.85; }
285
+ }
286
+
287
+ /* Glow pulse (for accent elements on dark backgrounds) */
288
+ @keyframes glowPulse {
289
+ 0%, 100% {
290
+ box-shadow: 0 0 0 0 rgba(var(--accent-rgb), 0.4);
291
+ transform: scale(1);
292
+ }
293
+ 50% {
294
+ box-shadow: 0 0 20px 8px rgba(var(--accent-rgb), 0.15);
295
+ transform: scale(1.04);
296
+ }
297
+ }
298
+
299
+ .pulse-item {
300
+ animation: pulse 1.5s ease-in-out infinite;
301
+ }
302
+
303
+ .cta-button {
304
+ animation: glowPulse 2s ease-in-out infinite;
305
+ /* define --accent-rgb as R,G,B values: e.g. 250,204,21 for #FACC15 */
306
+ }
307
+ ```
308
+
309
+ **Combining pulse with static content:**
310
+ ```css
311
+ /* Background stays still — only the CTA button pulses */
312
+ .static-content { /* no animation */ }
313
+ .cta-button { animation: pulse 2s ease-in-out infinite; }
314
+ ```
315
+
316
+ **HTML structure:**
317
+ ```html
318
+ <div class="canvas">
319
+ <div class="static-content">
320
+ <h1>Ready to reduce churn?</h1>
321
+ <p>See how DataPulse works</p>
322
+ </div>
323
+ <button class="cta-button pulse-item">Book a demo →</button>
324
+ </div>
325
+ ```
326
+
327
+ ---
328
+
329
+ ## 6. loop-scroll
330
+
331
+ Infinite scrolling ticker / marquee. Content scrolls continuously in one direction.
332
+
333
+ **Best for:** Feature lists, social proof, product attributes, news-style tickers, repeated keyword emphasis.
334
+
335
+ **Key technique:** Content is duplicated (`[items] [items]`). `translateX(0 → -50%)` with `linear` timing and `infinite` iteration — the second copy seamlessly takes over when the first exits.
336
+
337
+ **Critical:** Content MUST be duplicated exactly once. If 4 items, the HTML contains all 8 items (4 original + 4 copy). The GIF frame count covers one full scroll cycle = smooth loop.
338
+
339
+ ```css
340
+ .ticker-container {
341
+ width: 800px;
342
+ overflow: hidden;
343
+ /* Add a fade mask for polished edge effect */
344
+ -webkit-mask-image: linear-gradient(
345
+ to right,
346
+ transparent 0%,
347
+ black 8%,
348
+ black 92%,
349
+ transparent 100%
350
+ );
351
+ }
352
+
353
+ .ticker-track {
354
+ display: flex;
355
+ align-items: center;
356
+ white-space: nowrap;
357
+ /* Duration = number of original items × base speed */
358
+ animation: scrollLeft linear infinite;
359
+ animation-duration: calc(var(--item-count) * 1.5s);
360
+ }
361
+
362
+ @keyframes scrollLeft {
363
+ from { transform: translateX(0); }
364
+ to { transform: translateX(-50%); }
365
+ }
366
+
367
+ .ticker-item {
368
+ padding: 0 clamp(1.5rem, 4vw, 2.5rem);
369
+ font-size: clamp(1rem, 2vw, 1.4rem);
370
+ font-weight: 600;
371
+ flex-shrink: 0;
372
+ }
373
+
374
+ .ticker-sep {
375
+ color: var(--accent);
376
+ padding: 0 0.5rem;
377
+ flex-shrink: 0;
378
+ }
379
+ ```
380
+
381
+ **HTML structure (items duplicated):**
382
+ ```html
383
+ <div class="canvas">
384
+ <div class="ticker-container">
385
+ <div class="ticker-track" style="--item-count: 4;">
386
+ <!-- Original set -->
387
+ <span class="ticker-item">Reduce Churn</span>
388
+ <span class="ticker-sep">·</span>
389
+ <span class="ticker-item">Increase NRR</span>
390
+ <span class="ticker-sep">·</span>
391
+ <span class="ticker-item">Boost LTV</span>
392
+ <span class="ticker-sep">·</span>
393
+ <span class="ticker-item">Drive Expansion</span>
394
+ <span class="ticker-sep">·</span>
395
+ <!-- Duplicate set (exact copy) -->
396
+ <span class="ticker-item">Reduce Churn</span>
397
+ <span class="ticker-sep">·</span>
398
+ <span class="ticker-item">Increase NRR</span>
399
+ <span class="ticker-sep">·</span>
400
+ <span class="ticker-item">Boost LTV</span>
401
+ <span class="ticker-sep">·</span>
402
+ <span class="ticker-item">Drive Expansion</span>
403
+ <span class="ticker-sep">·</span>
404
+ </div>
405
+ </div>
406
+ </div>
407
+ ```
408
+
409
+ **For vertical scroll (top to bottom):**
410
+ ```css
411
+ @keyframes scrollUp {
412
+ from { transform: translateY(0); }
413
+ to { transform: translateY(-50%); }
414
+ }
415
+ .ticker-track-vertical {
416
+ display: flex;
417
+ flex-direction: column;
418
+ animation: scrollUp linear infinite;
419
+ }
420
+ ```
421
+
422
+ ---
423
+
424
+ ## Choosing the Right Animation
425
+
426
+ | Use case | Best animation |
427
+ |---|---|
428
+ | "Show a stat with impact" | counter or fade-in |
429
+ | "Reveal a quote or insight" | typewriter or fade-in |
430
+ | "Social media hook" | typewriter (terminal style) |
431
+ | "CTA / button emphasis" | pulse |
432
+ | "List of features/benefits" | loop-scroll |
433
+ | "Headline announcement" | slide-in |
434
+ | "Multiple stats together" | counter (multiple) |
435
+ | "Developer/tech audience" | typewriter (terminal style) |
436
+
437
+ ## File Size Guidance by Animation Type
438
+
439
+ | Animation | Typical size | Why |
440
+ |---|---|---|
441
+ | fade-in (1 element) | 100–400KB | Few color changes between frames |
442
+ | slide-in | 200–600KB | More color variation as element moves |
443
+ | typewriter (terminal) | 150–500KB | Dark bg + monochrome text = few colors |
444
+ | counter | 100–350KB | Static background, changing number only |
445
+ | pulse | 200–600KB | Repetitive frames compress well |
446
+ | loop-scroll | 400KB–1.5MB | Many unique positions = more frames |
@@ -0,0 +1,194 @@
1
+ # Style Presets — graphic-gif
2
+
3
+ 4 GIF-appropriate style presets. These are a subset of the full 9-preset library — chosen because they use simple, flat palettes that produce smaller GIF files and smoother loops.
4
+
5
+ **Why only 4?** GIF format is limited to 256 colors per frame. Styles with complex gradients, photographic backgrounds, or multiple gradient stops create color-banding artifacts and larger files. The 4 presets below use solid backgrounds and single accent colors.
6
+
7
+ **Rule:** Pick the preset that matches the tone and audience. Read all 4 before choosing.
8
+
9
+ ---
10
+
11
+ ## 1. clean-slate
12
+
13
+ **Character:** Professional. Clean. High-trust. No-noise.
14
+
15
+ ```css
16
+ :root {
17
+ /* Colors */
18
+ --bg: #FFFFFF;
19
+ --bg-elevated: #F8FAFC;
20
+ --text: #0F172A;
21
+ --text-muted: #64748B;
22
+ --accent: #0F172A;
23
+ --accent-light: #F1F5F9;
24
+ --divider: #E2E8F0;
25
+
26
+ /* Typography */
27
+ --font-display: 'Plus Jakarta Sans', sans-serif;
28
+ --font-body: 'Plus Jakarta Sans', sans-serif;
29
+
30
+ /* Font CDN */
31
+ /* <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600;700;800&display=swap" rel="stylesheet"> */
32
+ }
33
+ ```
34
+
35
+ **Design direction:**
36
+ - Background: white. Period. No gradients.
37
+ - Accent: near-black `#0F172A` — used sparingly (underlines, stats, borders)
38
+ - Typography: weight contrast is the design — 800 display vs 400 body
39
+ - Signature element: a thin 2px `--accent` underline or left border on key elements
40
+
41
+ **Use for:** Stat counters, professional quote reveals, LinkedIn-style social content. Any audience that expects polish without flair.
42
+
43
+ **File size:** Small. White bg + black text = ~16 colors per frame.
44
+
45
+ ---
46
+
47
+ ## 2. terminal
48
+
49
+ **Character:** Developer. Precise. Monochrome matrix. Mechanical.
50
+
51
+ ```css
52
+ :root {
53
+ /* Colors */
54
+ --bg: #0D1117;
55
+ --bg-elevated: #161B22;
56
+ --text: #C9D1D9;
57
+ --text-muted: #8B949E;
58
+ --accent: #00FF41;
59
+ --accent-light: #1A2332;
60
+ --divider: #21262D;
61
+
62
+ /* Typography */
63
+ --font-display: 'JetBrains Mono', monospace;
64
+ --font-body: 'JetBrains Mono', monospace;
65
+
66
+ /* Font CDN */
67
+ /* <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet"> */
68
+ }
69
+ ```
70
+
71
+ **Design direction:**
72
+ - Background: near-black `#0D1117` — GitHub dark mode reference
73
+ - Accent: matrix green `#00FF41` — for cursor, numbers, key terms
74
+ - Typography: monospace everywhere — even display headings
75
+ - Signature element: blinking cursor `|` using `animation: blink step-end infinite`
76
+ - Optional: scan-line overlay (`repeating-linear-gradient` with 1px transparent lines at 2px intervals, opacity 0.03)
77
+
78
+ **Scan-line recipe:**
79
+ ```css
80
+ .canvas::after {
81
+ content: '';
82
+ position: absolute;
83
+ inset: 0;
84
+ background: repeating-linear-gradient(
85
+ to bottom,
86
+ transparent,
87
+ transparent 1px,
88
+ rgba(0, 0, 0, 0.03) 1px,
89
+ rgba(0, 0, 0, 0.03) 2px
90
+ );
91
+ pointer-events: none;
92
+ }
93
+ ```
94
+
95
+ **Use for:** Typewriter effects (most effective), code reveals, developer stats, startup/tech metrics, anything aimed at builders.
96
+
97
+ **File size:** Very small. Dark bg + single-color text = ~8–12 colors per frame.
98
+
99
+ ---
100
+
101
+ ## 3. electric-burst
102
+
103
+ **Character:** Bold. Kinetic. Electric. High-contrast impact.
104
+
105
+ ```css
106
+ :root {
107
+ /* Colors */
108
+ --bg: #09090B;
109
+ --bg-elevated: #18181B;
110
+ --text: #FAFAFA;
111
+ --text-muted: #A1A1AA;
112
+ --accent: #FACC15;
113
+ --accent-light: #1C1917;
114
+ --divider: #27272A;
115
+
116
+ /* Typography */
117
+ --font-display: 'Space Grotesk', sans-serif;
118
+ --font-body: 'DM Sans', sans-serif;
119
+
120
+ /* Font CDN */
121
+ /* <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@600;700&family=DM+Sans:wght@400;500&display=swap" rel="stylesheet"> */
122
+ }
123
+ ```
124
+
125
+ **Design direction:**
126
+ - Background: near-black `#09090B` — darker than terminal, no green tint
127
+ - Accent: electric yellow `#FACC15` — for numbers, key words, CTA text
128
+ - Typography: `Space Grotesk` is chunky and geometric at large sizes
129
+ - Signature element: large accent-colored number or stat as the hero element, with `--text-muted` label below
130
+
131
+ **Accent usage rule:** Yellow only on the most important element per canvas (one stat, one CTA word, one key number). Everything else in white `#FAFAFA`. Yellow everywhere = no yellow.
132
+
133
+ **Use for:** Bold stat reveals, CTA buttons (pulse animation), product metric GIFs, high-energy social content.
134
+
135
+ **File size:** Small-medium. Dark bg + white text + 1 yellow element = ~20–30 colors per frame.
136
+
137
+ ---
138
+
139
+ ## 4. brutalist
140
+
141
+ **Character:** Raw. Confrontational. Typographic. Zero decoration.
142
+
143
+ ```css
144
+ :root {
145
+ /* Colors */
146
+ --bg: #FFFFFF;
147
+ --bg-elevated: #F5F5F5;
148
+ --text: #000000;
149
+ --text-muted: #666666;
150
+ --accent: #FF0000;
151
+ --accent-light: #FFF5F5;
152
+ --divider: #000000;
153
+
154
+ /* Typography */
155
+ --font-display: 'Space Mono', monospace;
156
+ --font-body: 'Space Mono', monospace;
157
+
158
+ /* Font CDN */
159
+ /* <link href="https://fonts.googleapis.com/css2?family=Space+Mono:wght@400;700&display=swap" rel="stylesheet"> */
160
+ }
161
+ ```
162
+
163
+ **Design direction:**
164
+ - Background: white. Nothing soft.
165
+ - Accent: pure red `#FF0000` — used for borders, tickers, 1–2 key words
166
+ - Typography: monospace everywhere — no humanist curves, no refinement
167
+ - Signature element: a thick `4px solid #000000` border or underline. Or a red separator.
168
+ - Layout: asymmetric, left-heavy. Text at extreme sizes. Oversized numbers.
169
+
170
+ **For loop-scroll tickers:** Red `--accent` separator dots (`·`) between items. Track background `--bg` white. Item font `Space Mono` 700.
171
+
172
+ **For slide-in:** Slide from left with `translateX(-100vw)` overshoot. Hard cubic-bezier: `cubic-bezier(0.87, 0, 0.13, 1)` (no spring — mechanical snap).
173
+
174
+ **Use for:** Loop-scroll tickers, bold feature lists, confrontational stat reveals, design-forward agencies, brands that want to stand out.
175
+
176
+ **File size:** Very small. White + black + occasional red = ~8–16 colors per frame.
177
+
178
+ ---
179
+
180
+ ## Styles to AVOID for GIFs
181
+
182
+ These styles from the full 9-preset library produce poor GIF output:
183
+
184
+ | Style | Problem |
185
+ |---|---|
186
+ | midnight-editorial | Complex gradient overlays = hundreds of colors = banding + large files |
187
+ | matt-gray | Multiple grey shades with subtle transitions = poor quantization |
188
+ | product-minimal | Gradient accents and backgrounds = too many colors |
189
+ | mint-pixel-corporate | Mint gradient + purple tones = complex palette |
190
+ | warm-earth | Warm texture/noise patterns = photographic complexity |
191
+ | magazine-red | Multiple brand colors + photographic intent = GIF banding |
192
+ | soft-cloud | Pastel gradients = smooth color transitions that GIF destroys |
193
+
194
+ **The rule:** If the style uses any `linear-gradient` as a background (not just borders), avoid it for GIFs. Flat solid colors only.