Skill: viperrcrypto/picasso (version 2.0.3)

--- name: picasso version: 2.0.2 description: > The ultimate frontend design and UI engineering skill. Use this whenever the user asks to build, design, style, or improve any web interface, component, page, application, dashboard, landing page, artifact, poster, or visual output. Covers typography, color systems, spatial design, motion/animation, interaction design, responsive layouts, sound design, haptic feedback, icon systems, generative art, theming, React best practices, and DESIGN.md system generation. Also use when the user asks to audit, critique, polish, simplify, animate, or normalize a frontend. Triggers on any mention of "make it look good," "fix the design," "UI," "UX," "frontend," "component," "landing page," "dashboard," "artifact," "poster," "design system," "theme," "animation," "responsive," or any request to improve visual quality. Use this skill even when the user does not explicitly ask for design help but the task involves producing a visual interface. metadata: openclaw: always: false skillKey: picasso emoji: "\U0001F3A8" homepage: https://github.com/viperrcrypto/picasso --- # Picasso The ultimate design skill for producing distinctive, production-grade frontend interfaces, visual artifacts, and design systems. This skill consolidates best practices from Anthropic's frontend-design, canvas-design, algorithmic-art, and theme-factory skills, Impeccable's 7-domain reference system, VoltAgent's DESIGN.md format, Vercel's React and typography standards, and specialized libraries for sound, haptics, icons, and text animation. Every output should look like it was built by a senior design engineer who spent days refining it, not generated by an AI in seconds. --- ## Configurable Settings These three dials (1-10) control the overall character of the output. Adjust based on what is being built. The user can set these explicitly or they can be inferred from context. - **DESIGN_VARIANCE** (default: 6) — How experimental the layout is. 1-3: clean, centered, conventional. 4-6: considered asymmetry, intentional breaks. 7-10: avant-garde, overlapping elements, unconventional grids. - **MOTION_INTENSITY** (default: 5) — How much animation is present. 1-3: hover states and fades only. 4-6: staggered reveals, scroll-triggered, text morphing. 7-10: magnetic cursors, parallax, complex choreography. - **VISUAL_DENSITY** (default: 5) — How much content fits on one screen. 1-3: spacious, luxury, breathing room. 4-6: balanced, structured whitespace. 7-10: dense dashboards, data-heavy, compact. When the user says "make it premium" or "luxury feel," drop VISUAL_DENSITY to 2-3 and MOTION_INTENSITY to 4-5. When they say "dashboard" or "admin panel," raise VISUAL_DENSITY to 7-8. When they say "make it pop" or "wow factor," raise DESIGN_VARIANCE and MOTION_INTENSITY to 7-8. --- ## Quick Start (30 seconds) New to Picasso? Here's the minimum viable workflow: 1. **Pick a font** that isn't Inter, Roboto, or Arial. Try: Satoshi, Cabinet Grotesk, Outfit, General Sans, Clash Display. 2. **Pick a color** in OKLCH. Not Tailwind's default indigo. Try: `oklch(0.65 0.25 25)` (warm red), `oklch(0.55 0.20 160)` (teal), `oklch(0.60 0.22 300)` (violet). 3. **Tint your grays** toward your accent hue. Never use pure `#808080` or `#000`. 4. **Break the center.** Left-align content. Use asymmetric grids (2:1, 3:2). Only center heroes and CTAs. 5. **Read `references/anti-patterns.md`** before writing any code. It's the most important file. Then follow the full workflow below. Skip nothing. --- ## Step 0: Read the Right References Before writing any code, read the reference files relevant to the task. Each covers a domain in depth with rules, examples, and anti-patterns. Load only what you need. | Reference File | When to Read | |---|---| | `references/typography.md` | Any task involving text, fonts, headings, or type hierarchy | | `references/color-and-contrast.md` | Color palettes, dark mode, accessibility, tinted neutrals | | `references/spatial-design.md` | Layout, spacing, grids, visual hierarchy, whitespace | | `references/depth-and-elevation.md` | Dual shadows, layering technique, shadow scale, z-index, hover patterns | | `references/motion-and-animation.md` | Transitions, scroll effects, text morphing, micro-interactions | | `references/interaction-design.md` | Forms, focus states, loading, empty states, error handling | | `references/responsive-design.md` | Mobile-first, fluid, container queries, touch targets | | `references/sensory-design.md` | UI sound effects, haptic feedback, multi-sensory interfaces | | `references/react-patterns.md` | React/Next.js component architecture, hooks, performance | | `references/anti-patterns.md` | Explicit list of what NOT to do (the most important reference) | | `references/design-system.md` | Generating DESIGN.md files, theming, systematic tokens | | `references/generative-art.md` | Algorithmic art, p5.js, seeded randomness, flow fields | | `references/component-patterns.md` | Standard component naming, taxonomy, and state patterns | | `references/navigation-patterns.md` | Breadcrumbs, sidebar, tabs, bottom bar, mega menus, skip links | | `references/tables-and-forms.md` | Sortable tables, inline editing, multi-step forms, validation | | `references/loading-and-states.md` | Skeletons, spinners, empty states, error boundaries, offline | | `references/dark-mode.md` | Preference hierarchy, surface elevation, transitions, testing | | `references/images-and-media.md` | Format selection, responsive images, favicons, OG images | | `references/micro-interactions.md` | Scroll animations, page transitions, gestures, magnetic effects | | `references/i18n-visual-patterns.md` | RTL, logical properties, text expansion, CJK, number formatting | | `references/brand-and-identity.md` | Logo sizing, brand color usage, consistency, lockup variants | | `references/animation-performance.md` | Compositor-only props, will-change, layout thrashing, contain | | `references/code-typography.md` | Monospace fonts, syntax highlighting, code blocks, diff views | | `references/accessibility-wcag.md` | WCAG 2.2, ARIA patterns, keyboard nav, screen reader testing | | `references/conversion-design.md` | Landing pages, CTAs, pricing tables, friction reduction | | `references/data-visualization.md` | Chart selection matrix, dashboard patterns, accessible charts | | `references/modern-css-performance.md` | CSS nesting, :has(), View Transitions, Tailwind v4, container queries | | `references/performance-optimization.md` | Core Web Vitals, Lighthouse, image optimization, 45 Vercel rules | | `references/style-presets.md` | 22 curated design presets with exact OKLCH values and font pairings | | `references/tools-catalog.md` | Tool recommendations: torph, soundcn, Lucide, Facehash, better-icons | | `references/ux-psychology.md` | Gestalt principles, Fitts's Law, Hick's Law, cognitive load, heuristics | | `references/ux-writing.md` | Error messages, microcopy, terminology, voice and tone, CTAs | --- ## Step 0.5: Anti-Slop Gate (MANDATORY — before ANY code) This step is non-negotiable. It takes 30 seconds and prevents hours of rework. 1. **Read `references/anti-patterns.md`** — specifically the AI Slop Fingerprint section and Professional Alternatives table. Actually read it, don't skip. 2. **Write out your commitments** — before touching code, declare: - Font: [exact name, not a banned default] - Layout strategy: [specific — not "centered everything"] - Accent color: [exact value in OKLCH — not Tailwind default indigo] - What makes this unforgettable: [one specific, memorable design choice] - What you're explicitly rejecting: [the obvious/generic approach for this type of product] 3. **Run the 3-Second Test** — picture the finished design. Would a designer say "AI-generated" in 3 seconds? If yes, change your commitments. 4. **Check for slop combinations** — if 3+ of these are true, STOP and redesign: - Centered vertical layout - Default Tailwind accent color - Uniform card grid - Generic sans-serif font - Same spacing everywhere - Three equal-width items in a row **HALT CONDITION:** If you cannot fill out the commitments above with specific, non-default values, you MUST NOT proceed to Step 1. Go back to the references. Read anti-patterns.md. Try again. There is no "just do it" bypass for this step. The gate exists because without it, every output converges to the same generic AI aesthetic. This is not optional. No code until commitments are written. --- ## Step 1: Design Thinking Before writing a single line of code, answer these questions internally: **Purpose.** What problem does this interface solve? Who uses it? What is the single most important action? **Tone.** Commit to a specific aesthetic direction. Not "clean and modern" (that is meaningless). Pick something with teeth: brutalist, editorial, retro-terminal, luxury serif, toy-like, industrial, organic, Swiss grid, art deco, vaporwave, newspaper broadsheet, scientific journal, or something entirely original. The direction should be informed by the content, not applied generically. **Differentiation.** What makes this unforgettable? What is the one thing someone will remember after closing the tab? If there is no answer, the design is not ready. **Constraints.** Framework requirements, accessibility targets, performance budgets, existing design tokens. --- ## Step 2: Aesthetic Execution ### Typography Choose fonts that are distinctive, not default. Never use Inter, Roboto, Arial, or system fonts as primary choices. Pair a display font with a body font. Use a modular type scale (1.25 or 1.333 ratio). Set line heights between 1.4 and 1.6 for body text. Use OpenType features (ligatures, tabular numbers, small caps) when the font supports them. See `references/typography.md` for the full system. ### Color Build palettes with intention. Use OKLCH for perceptually uniform color manipulation. Always tint neutrals (never use pure gray or pure black). Dominant color with sharp accent outperforms evenly distributed palettes. Test contrast ratios: 4.5:1 minimum for body text, 3:1 for large text and UI elements. See `references/color-and-contrast.md`. ### Spatial Composition Use a spacing scale (4px base: 4, 8, 12, 16, 24, 32, 48, 64, 96). Asymmetric layouts, overlapping elements, diagonal flow, and grid-breaking moments create visual interest. Generous negative space communicates confidence. Dense layouts need careful rhythm. See `references/spatial-design.md`. ### Backgrounds and Visual Depth Never default to flat solid colors. Create atmosphere with gradient meshes, noise textures, geometric patterns, layered transparencies, dramatic shadows, grain overlays, or subtle backdrop filters. Depth comes from elevation systems: consistent shadow scales, surface hierarchy, and z-index discipline. ### Motion One well-orchestrated page load with staggered reveals (using animation-delay) creates more impact than scattered micro-interactions. Use CSS transitions for simple state changes. Use `framer-motion` or the Motion library for React when choreography matters. Never use bounce or elastic easing (it looks dated). Respect `prefers-reduced-motion`. See `references/motion-and-animation.md`. ### Text Animation For text morphing effects (counters, status changes, tab labels), use `torph` (dependency-free, works with React/Vue/Svelte). Import as `import { TextMorph } from 'torph/react'` and wrap any text that changes dynamically. ### Sound For UI sound feedback (clicks, notifications, transitions), use the soundcn pattern: inline base64 audio data URIs with a `useSound` hook via Web Audio API. Zero dependencies. See `references/sensory-design.md`. ### Haptics For mobile web, use the WebHaptics pattern via the Vibration API (`navigator.vibrate()`) to provide tactile feedback on button presses, toggles, and destructive actions. Always gate behind feature detection and user preference. See `references/sensory-design.md`. ### Icons Use Lucide React as the default icon library (`lucide-react`). For broader searches across 200K+ icons from 150+ collections, use the `better-icons` CLI pattern: search by keyword, retrieve SVG, sync to project. Prefer outline style for UI, solid for emphasis. ### Avatars and Identity For deterministic avatar generation from strings (usernames, emails, UUIDs), use the Facehash pattern: a React component that generates unique face avatars. Same input always produces the same face. Zero external assets. --- ## Step 3: Implementation Standards ### Single-File Artifacts When building for claude.ai artifacts (HTML or React), everything goes in one file. No external CSS files, no separate JS. Inline everything. For HTML artifacts, import external scripts only from `https://cdnjs.cloudflare.com`. For React artifacts, use only available libraries (lucide-react, recharts, d3, Three.js r128, Tone, shadcn/ui, Tailwind core utilities, lodash, mathjs, papaparse, Chart.js). ### React Best Practices Follow these rules (see `references/react-patterns.md` for details): - Server Components by default, `'use client'` only when needed - Colocate state with the component that uses it - Prefer composition over prop drilling - Use `Suspense` boundaries with meaningful fallbacks - Never store derived state, compute it during render - Use semantic HTML elements, not `div` soup - Memoize expensive computations, not everything - Default export for page/route components, named exports for utilities ### CSS Variables for Theming Always define a CSS variable system for colors, spacing, typography, and shadows. This makes themes swappable and dark mode trivial. ```css :root { --color-surface: #fafaf9; --color-text: #1c1917; --color-accent: #dc2626; --radius: 8px; --shadow-sm: 0 1px 2px oklch(0% 0 0 / 0.05); } ``` ### Accessibility Defaults Every interface must include: visible focus indicators (never `outline: none` without replacement), sufficient color contrast, keyboard navigability, ARIA labels on interactive elements without visible text, and `alt` text on meaningful images. Do not treat accessibility as optional. --- ## Step 4: Audit and Polish Before delivering any interface, run this mental checklist: 1. **Typography audit.** Is there a clear type hierarchy? Are fonts loaded and rendering? Is body text readable at default zoom? 2. **Color audit.** Does the palette feel cohesive? Do accents draw the eye to the right places? Does it work in both light and dark contexts? 3. **Spatial audit.** Is spacing consistent? Are elements aligned to an invisible grid? Is there breathing room? 4. **Interaction audit.** Do all interactive elements have hover, focus, and active states? Are transitions smooth? Is there loading feedback? 5. **Responsive audit.** Does it work on 375px wide screens? Does it scale gracefully to ultrawide? 6. **Motion audit.** Does the page load feel choreographed? Are transitions purposeful? Does `prefers-reduced-motion` disable non-essential animation? 7. **Accessibility audit.** Can you tab through the entire interface? Are contrast ratios sufficient? Do screen readers make sense of the structure? --- ## Step 5: Design System Generation When asked to create a design system or DESIGN.md, follow the VoltAgent/Stitch format. See `references/design-system.md` for the complete template covering: visual theme and atmosphere, color palette with semantic roles, typography hierarchy, component styling (buttons, cards, inputs, navigation with states), layout principles, depth and elevation system, explicit dos and don'ts, responsive behavior, and an agent prompt guide. --- ## Step 6: Generative and Canvas Art When the task involves algorithmic art, generative visuals, or static poster/print design, see `references/generative-art.md`. The process: write an algorithmic philosophy (4-6 paragraphs), then express it through p5.js code with seeded randomness, parameter controls, and seed navigation. --- ## Commands These optional directives can be used to steer design refinement: | Command | Effect | |---|---| | `/audit` | Technical quality check: accessibility, performance, responsive | | `/critique` | UX design review: hierarchy, clarity, emotional resonance | | `/polish` | Final pass: refine spacing, transitions, copy | | `/simplify` | Strip to essence, remove visual noise | | `/animate` | Add purposeful motion and transitions | | `/bolder` | Amplify timid designs with stronger visual choices | | `/quieter` | Tone down overly aggressive designs | | `/normalize` | Align with design system standards | | `/theme` | Generate or apply a color/font theme | | `/sound` | Add UI sound effects to interactions | | `/haptics` | Add haptic feedback for mobile web | | `/redesign` | Audit an existing project, identify design problems, fix them systematically | | `/soft` | Apply premium soft aesthetic: generous whitespace, depth, smooth spring animations | | `/minimalist` | Apply editorial minimalism: monochrome, crisp borders, inspired by Linear/Notion | | `/brutalist` | Apply raw mechanical aesthetic: Swiss typography meets CRT terminal | | `/stitch` | Generate a Google Stitch-compatible DESIGN.md for the current project | --- ## What Makes Design Feel Designed The anti-slop gate catches what NOT to do. This section describes what good design feels like -- the positive traits to aim for. - **Intentional asymmetry.** Not everything centered. A sidebar heavier than the main content. A grid where one card spans two rows. Deliberate imbalance creates visual interest. - **Typographic personality.** The font choice says something about the product. A fintech app using Clash Display feels different from one using Instrument Serif. The choice is the message. - **Color restraint with one brave moment.** A monochromatic palette with a single saturated accent on the primary CTA. The accent earns attention because everything else is quiet. - **Depth as information architecture.** Shadows and elevation are not decoration. They tell the user what is interactive, what is background, and what demands attention right now. - **Motion that teaches.** A staggered reveal shows the user where to look first, second, third. A hover lift says "this is clickable." Animation is communication. - **Whitespace as confidence.** Generous spacing says the product is not desperate for attention. It trusts the content to speak for itself. If you can describe these qualities in the output you are building, the design is probably good. If you cannot, revisit Step 1. --- ## Gotchas (Real Failure Points) These are not best practices. These are things that actually break in production and that AI agents get wrong repeatedly. Each one has burned real time. 1. **Font loading race condition.** Google Fonts `@import` in CSS blocks rendering. The page flashes in the system font, then shifts when the custom font loads. Fix: use `<link rel="preload" as="font">` in the `<head>`, add `font-display: swap`, and always declare a fallback stack with similar metrics. If you skip this, your type scale is wrong for the first 500ms. 2. **Dark mode contrast passes WCAG but is unreadable.** OKLCH `0.55 0.02 230` on `0.11 0.02 230` passes the 4.5:1 ratio check but looks washed out on cheap laptop screens. Always test with a screenshot on an actual dark background, not just the contrast calculator. Text below `0.60` lightness in OKLCH needs extra chroma or a bump to `0.65+`. 3. **`transition: all` causes invisible layout jank.** It transitions `width`, `height`, `padding` -- properties that trigger reflow. The page looks fine at 60fps on your M-series Mac but stutters on a 2019 Chromebook. Always specify exact properties: `transition: opacity 0.2s, transform 0.3s`. 4. **Staggered animations fire on every re-render.** CSS `animation-delay` on child elements replays every time React re-renders the parent. Either use `animation-fill-mode: both` with a one-shot class that gets removed, or gate the animation behind a `data-entered` attribute set once on mount. 5. **Responsive "works at breakpoints" but breaks between them.** Testing at 375px and 768px looks fine, but at 520px the layout collapses because you used fixed `grid-template-columns: repeat(2, 1fr)` instead of `repeat(auto-fill, minmax(280px, 1fr))`. Always test at 480px and 600px too -- these are the kill zones. 6. **Tailwind class strings over 200 characters.** Once a class string hits 200+ characters the component is unmaintainable. Extract to a CSS class with `@apply`, or better yet, use a `cn()` utility with conditional objects. This isn't a style preference -- it's a readability threshold. 7. **Icon SVGs without `aria-hidden="true"`.** Every inline SVG icon announces itself to screen readers as "image" with no label. Decorative icons need `aria-hidden="true"`. Icons that ARE the only content (icon-only buttons) need `aria-label` on the button instead. 8. **`forced-colors` mode breaks custom design.** Windows High Contrast mode (`@media (forced-colors: active)`) overrides custom focus rings, tinted neutrals, and subtle borders. Test with it. Custom focus indicators need `forced-color-adjust: none` or a `Highlight` system color fallback. 9. **Missing `width`/`height` on images causes CLS.** Every `<img>` without explicit dimensions (or `aspect-ratio`) causes Cumulative Layout Shift when it loads. Always set dimensions or use `aspect-ratio` as a fallback. This is the #1 CLS offender in production. 10. **Autofill styling overrides your inputs.** Browsers apply their own background color to autofilled inputs, ignoring your dark mode or custom input styles. Fix with `input:-webkit-autofill { -webkit-box-shadow: 0 0 0 1000px var(--surface-1) inset; }`. 11. **`backdrop-filter: blur()` fails with `overflow: hidden` parent.** In some browsers (notably older Safari), `backdrop-filter` does not render if any ancestor has `overflow: hidden`. Move the blurred element outside the clipping context or restructure the DOM. 12. **`position: fixed` breaks inside `transform` parents.** A `transform` on any ancestor creates a new containing block, making `position: fixed` behave like `position: absolute`. Move fixed elements to a body-level portal or remove the ancestor transform. 13. **`content-visibility: auto` breaks `position: sticky`.** The `content-visibility: auto` optimization creates a new layout containment context that prevents `position: sticky` children from working. Either skip `content-visibility` on sticky containers or restructure the nesting. 14. **`scroll-behavior: smooth` on `html` interferes with programmatic scrolling.** Setting `scroll-behavior: smooth` globally makes `scrollTo()`, `scrollIntoView()`, and anchor navigation all animate, which breaks instant programmatic jumps. Apply `scroll-behavior: smooth` per-container instead of on `<html>`. 15. **Preset style exceptions are not contradictions.** Some presets (e.g., Swiss Modern using Archivo, or a retro terminal preset using monospace) intentionally use fonts that appear on the banned list. Presets are scoped exceptions with a clear aesthetic rationale. Do not flag them as anti-slop violations. --- ## The Non-Negotiables 1. No design should ever look like "AI made this." No purple gradients on white. No Inter font. No centered everything. No cards nested in cards. No gray text on colored backgrounds. 2. Every design must have a clear aesthetic point of view. If it could belong to any product, it belongs to none. 3. Match implementation complexity to vision. Maximalist designs need elaborate code. Minimalist designs need surgical precision. Both require the same level of care. 4. Text is always a design element, never an afterthought. 5. Every detail matters. The shadow radius, the letter spacing, the hover transition duration, the border color in dark mode. These are not small decisions. 6. **The Anti-Slop Gate (Step 0.5) must be completed before writing any design code.** No exceptions. If you cannot articulate specific, non-default commitments for font, color, layout, and differentiation, you are not ready to design. Go back to the references. 7. **Transformation means transformation.** When asked to redesign or improve a site, the result must be visually unrecognizable from the original. Changing CSS variables and swapping fonts is engineering, not design. A redesign changes the spatial logic, the visual hierarchy, the emotional register, and the layout structure. If someone could confuse the before and after, the redesign failed.

path: references/animation-performance.md
content: # Animation Performance Reference

## Table of Contents
1. Compositor-Only Properties
2. Will-Change Best Practices
3. Layout Thrashing
4. IntersectionObserver vs Scroll Events
5. Web Animations API
6. Performance Measurement
7. Testing on Low-End Devices
8. Contain Property
9. Common Mistakes

---

## 1. Compositor-Only Properties

Only two CSS properties can be animated without triggering layout or paint: **transform** and **opacity**. Everything else causes reflow.

| Property | Layout | Paint | Composite | Animate? |
|---|---|---|---|---|
| `transform` | No | No | Yes | **Yes** |
| `opacity` | No | No | Yes | **Yes** |
| `filter` | No | Yes | Yes | Carefully |
| `background-color` | No | Yes | No | Avoid |
| `width`, `height` | Yes | Yes | No | **Never** |
| `top`, `left` | Yes | Yes | No | **Never** |
| `margin`, `padding` | Yes | Yes | No | **Never** |
| `border-radius` | No | Yes | No | Avoid |

```css
/* Good: compositor-only */
.slide-in {
  transform: translateX(-100%);
  opacity: 0;
  transition: transform 300ms var(--ease-out), opacity 300ms var(--ease-out);
}
.slide-in.active {
  transform: translateX(0);
  opacity: 1;
}

/* Bad: triggers layout on every frame */
.slide-in-bad {
  left: -100%;
  transition: left 300ms ease;
}
```

---

## 2. Will-Change Best Practices

`will-change` promotes an element to its own compositor layer. This speeds up animation but consumes GPU memory.

Rules:
- Add `will-change` BEFORE the animation starts (e.g., on hover, not in the animation itself).
- Remove it AFTER the animation completes.
- Never use `will-change: all` — it promotes everything.
- Never apply it to more than 10 elements simultaneously.
- Don't put it in your stylesheet permanently.

```js
// Good: apply before, remove after
element.addEventListener('mouseenter', () => {
  element.style.willChange = 'transform';
});
element.addEventListener('transitionend', () => {
  element.style.willChange = 'auto';
});
```

```css
/* Acceptable: for elements that are ALWAYS animated (e.g., loading spinners) */
.spinner { will-change: transform; }

/* Bad: permanent will-change on static elements */
.card { will-change: transform, opacity; } /* don't do this */
```

---

## 3. Layout Thrashing

Reading layout properties then writing them in a loop forces the browser to recalculate layout on every iteration.

```js
// BAD: layout thrashing (read-write-read-write)
elements.forEach(el => {
  const height = el.offsetHeight;    // READ — forces layout
  el.style.height = height + 10 + 'px'; // WRITE — invalidates layout
});

// GOOD: batch reads, then batch writes
const heights = elements.map(el => el.offsetHeight); // all reads first
elements.forEach((el, i) => {
  el.style.height = heights[i] + 10 + 'px'; // all writes after
});
```

Properties that trigger forced layout when read: `offsetHeight`, `offsetWidth`, `getBoundingClientRect()`, `scrollTop`, `clientHeight`, `getComputedStyle()`.

---

## 4. IntersectionObserver vs Scroll Events

| | `scroll` event | IntersectionObserver |
|---|---|---|
| Performance | Fires every pixel, blocks main thread | Async, fires on threshold crossing |
| Throttling | Manual (requestAnimationFrame) | Built-in |
| Use case | Scroll-linked animation (position) | Visibility detection (enter/exit) |
| Recommendation | Almost never | Almost always |

```js
// Good: IntersectionObserver for reveal animations
const observer = new IntersectionObserver(
  (entries) => {
    entries.forEach(entry => {
      entry.target.classList.toggle('visible', entry.isIntersecting);
    });
  },
  { threshold: 0.1 }
);
```

For scroll-linked animations where you need exact scroll position, use the Scroll-Driven Animations API:

```css
@keyframes fade-in {
  from { opacity: 0; transform: translateY(20px); }
  to { opacity: 1; transform: translateY(0); }
}

.scroll-reveal {
  animation: fade-in linear;
  animation-timeline: view();
  animation-range: entry 0% entry 100%;
}
```

---

## 5. Web Animations API

For complex JS-driven animations, use WAAPI instead of manual `requestAnimationFrame`:

```js
element.animate(
  [
    { transform: 'translateY(20px)', opacity: 0 },
    { transform: 'translateY(0)', opacity: 1 }
  ],
  {
    duration: 300,
    easing: 'cubic-bezier(0.16, 1, 0.3, 1)',
    fill: 'forwards'
  }
);
```

Benefits over CSS: programmable, cancellable, can read progress, can reverse.

---

## 6. Performance Measurement

```js
// Measure animation frame rate
let frames = 0;
let lastTime = performance.now();

function countFrames() {
  frames++;
  const now = performance.now();
  if (now - lastTime >= 1000) {
    console.log(`FPS: ${frames}`);
    frames = 0;
    lastTime = now;
  }
  requestAnimationFrame(countFrames);
}
requestAnimationFrame(countFrames);
```

Chrome DevTools:
1. Performance tab → Record → interact with animations → Stop
2. Look for long frames (> 16ms) in the flame chart
3. Rendering tab → Paint flashing (green = repaint, should be minimal)
4. Rendering tab → Layer borders (orange = composited layers)

Target: 60fps = 16.67ms per frame. If ANY frame takes > 33ms, users perceive jank.

---

## 7. Testing on Low-End Devices

Your M-series Mac is not representative. Test with:
- **Chrome DevTools CPU throttling:** Performance tab → CPU → 6x slowdown
- **Network throttling:** Slow 3G preset to test loading animations
- **Real device:** Test on a 3-year-old Android phone if possible

If an animation stutters at 6x CPU throttle, reduce:
1. Number of concurrent animations
2. Element count being animated
3. Complexity of each animation

---

## 8. Contain Property

`contain` tells the browser what NOT to recalculate when an element changes.

```css
/* Isolate layout/paint to this element */
.card {
  contain: layout paint;
}

/* Full isolation — best for off-screen or independent components */
.widget {
  contain: strict; /* = size + layout + paint + style */
}

/* Content containment — layout + paint + style (most common) */
.list-item {
  contain: content;
}
```

Use `contain: content` on repeated elements (list items, cards) to prevent layout changes from propagating to siblings.

---

## 9. Common Mistakes

- **Animating `width`/`height`/`top`/`left`.** Use `transform: translate/scale` instead.
- **`will-change` on everything.** Max 10 elements. Remove after animation completes.
- **`addEventListener('scroll')` for visibility.** Use IntersectionObserver.
- **Reading layout properties in animation loops.** Batch reads before writes.
- **Testing only on fast hardware.** Use Chrome CPU throttling at 6x.
- **No frame budget awareness.** 16ms per frame. If your JS takes 20ms, you drop frames.
- **CSS `transition: all`.** Transitions every property including layout triggers.
- **Forgetting `contain` on repeated elements.** One card's layout change recalculates the entire list.
- **`requestAnimationFrame` without cancellation.** Always store the ID and `cancelAnimationFrame` on cleanup.


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (MEDIUM)