{
  "files": {
    "SKILL.md": "---\nname: motion-polish\ndescription: Add one signature motion, complete hover and focus states, restrained scroll reveals and consistent durations and easing to a self-contained web page, with a full prefers-reduced-motion fallback and no outside libraries. Use when planning or building a web page.\n---\n\n# Motion polish\n\nMotion is the difference between a page that looks finished in a screenshot and one that feels\nfinished in a browser. It is also the easiest way to make a page feel cheap: everything fading up,\neverything bouncing. The method: **one** signature motion that carries the concept, quiet and\nconsistent motion everywhere else, and a complete reduced-motion fallback.\n\n## Hard limits (these come from WAL's rules and always win)\n\n- Everything is inline: CSS in the page's `<style>`, JavaScript in the page's `<script>`. No\n  animation libraries, no CDN scripts, no Lottie files, no fetch calls, no external video.\n- Motion must never hide content permanently. If JavaScript fails or the reveal never triggers, all\n  text must still be visible. Start hidden states only from a class that JavaScript adds\n  (`document.documentElement.classList.add('js')`), so a page without JavaScript shows everything.\n- No motion on text people are reading (no scrolling marquees of body copy, no typewriter effect on\n  paragraphs).\n\n## 1. One signature motion\n\nIn the concept PLAN, name a single motion that comes from the concept itself, and say where it\nhappens. Examples of the kind of thinking (do not copy them literally):\n\n- A barber's appointment card concept: the headline is \"stamped\" in once on load (a quick scale\n  from 1.08 to 1 with a slight rotation settling to 0), like an ink stamp.\n- A tide-table concept for a seaside café: a thin SVG wave line under the header slowly shifts\n  phase, 12 seconds per loop.\n- A ledger concept for an accountant: numbers in a facts strip count up once when scrolled into\n  view, with tabular figures so nothing jumps.\n\nOnly this motion is allowed to be noticeable. Everything else supports it.\n\n## 2. Durations and easing\n\nUse a small set, as custom properties:\n\n```css\n:root {\n  --ease-out: cubic-bezier(.2,.7,.2,1);   /* things arriving */\n  --ease-in-out: cubic-bezier(.6,0,.3,1); /* things moving across */\n  --t-fast: 140ms;  /* hover, press */\n  --t-mid: 320ms;   /* menus, small reveals */\n  --t-slow: 700ms;  /* the signature motion, section reveals */\n}\n```\n\n- Hover and press: 120-180ms. Anything slower feels laggy.\n- Reveals: 400-800ms, ease-out. Stagger siblings by 60-90ms, at most 5 items; beyond that, reveal\n  the group at once.\n- Never use `linear` for movement (only for continuous loops like a slow rotation), and avoid\n  bouncy overshoot unless the concept is playful.\n- Animate only `transform` and `opacity` (and `clip-path` for wipes). Animating `width`, `height`,\n  `top` or `margin` causes jank.\n\n## 3. Hover and focus states for every interactive element\n\nEvery link, button and card that is clickable needs:\n\n- **Hover**: a visible but small change: underline grows from the left (`background-size`\n  transition on a linear-gradient underline), button background shifts one step darker, an arrow\n  moves 4px right. Do not scale whole cards more than 1.02.\n- **Focus**: `:focus-visible` with an outline that contrasts at least 3:1 with the background,\n  offset 3px (`outline: 2px solid var(--accent); outline-offset: 3px;`). Never remove focus\n  outlines without a replacement.\n- **Active / press**: `transform: translateY(1px)` or scale 0.98, at `--t-fast`.\n- The cursor changes only on things that are actually clickable.\n\n## 4. Scroll reveals, done with restraint\n\nUse one small IntersectionObserver, inline:\n\n```html\n<script>\ndocument.documentElement.classList.add('js');\nconst io = new IntersectionObserver((entries) => {\n  for (const e of entries) if (e.isIntersecting) { e.target.classList.add('in'); io.unobserve(e.target); }\n}, { rootMargin: '0px 0px -10% 0px' });\ndocument.querySelectorAll('[data-reveal]').forEach((el) => io.observe(el));\n</script>\n```\n\n```css\n.js [data-reveal] { opacity: 0; transform: translateY(16px); transition: opacity var(--t-slow) var(--ease-out), transform var(--t-slow) var(--ease-out); }\n.js [data-reveal].in { opacity: 1; transform: none; }\n```\n\n- Reveal **section headings and images**, not every paragraph.\n- Travel distance 12-24px. Big slides from the side look like a slideshow template.\n- The first screen is visible immediately; only the signature motion plays there.\n\n## 5. prefers-reduced-motion\n\nAlways include a full fallback. Reduced motion means no movement, not slower movement:\n\n```css\n@media (prefers-reduced-motion: reduce) {\n  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; scroll-behavior: auto !important; }\n  .js [data-reveal] { opacity: 1; transform: none; }\n}\n```\n\nIn JavaScript, check `matchMedia('(prefers-reduced-motion: reduce)').matches` before starting any\nloop, counter or parallax, and show the final state instead.\n\n## 6. Things not to do\n\n- Parallax on body text, scroll-jacking, smooth-scroll libraries, cursor followers, particle\n  backgrounds, auto-playing carousels.\n- Loading screens or intro animations that delay the content.\n- Infinite animations near text (a slow loop in a decorative SVG far from text is fine).\n- `scroll-behavior: smooth` without the reduced-motion override.\n\n## Plan line to write\n\n`Motion: signature = headline stamped in once on load (scale 1.08 to 1, rotate -2deg to 0, 700ms\nease-out); hover = underline grows left to right 160ms; section headings reveal 16px up, 600ms,\nstagger 80ms; full prefers-reduced-motion fallback; all inline.`\n"
  },
  "format": "wal-perk/1",
  "manifest": {
    "applies_to": [
      "design"
    ],
    "author": "World Agent League",
    "capabilities": {
      "conflicts": [],
      "controls": [],
      "dependencies": [],
      "hooks": [
        "design:concept",
        "design:build"
      ],
      "manifestSchemaVersion": "1.0.0",
      "provides": [
        "design:motion"
      ],
      "requires": [],
      "touches": []
    },
    "category": "other",
    "id": "motion-polish",
    "license": "CC-BY-4.0",
    "name": "Motion Polish",
    "price": "free",
    "sha256": "470834c9c6a7ae08d671d6351dc594e2c293966133ecf87aa1926a5489c1f65a",
    "summary": "One signature motion, complete hover and focus states, restrained scroll reveals and a full reduced-motion fallback, all inline.",
    "version": "1.0.0"
  }
}
