import type { DesignSkill } from "./design-skill.js"; export const motionFrames: DesignSkill = { name: "motion-frames", scenario: "creative", description: "CSS animation and motion design frames. Keyframe-driven animations, scroll-triggered reveals, staggered lists, loading states, and page transitions — all CSS-only where possible.", outputKind: "html", workflow: `# Motion Frames Skill Produce a motion design showcase as a single HTML file. CSS keyframe animations, scroll-triggered effects, and subtle micro-interactions — no JavaScript libraries. ## Phase 1 — Animation Vocabulary ### Entrance Animations \`\`\`css /* Fade up */ @keyframes fadeUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } /* Scale in */ @keyframes scaleIn { from { opacity: 0; transform: scale(0.9); } to { opacity: 1; transform: scale(1); } } /* Slide from left */ @keyframes slideLeft { from { opacity: 0; transform: translateX(-30px); } to { opacity: 1; transform: translateX(0); } } /* Reveal by clip-path */ @keyframes clipReveal { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } } \`\`\` ### Scroll-Triggered Reveals \`\`\`css /* Use scroll-driven animations (modern browsers) */ .reveal { animation: fadeUp 0.6s ease-out; animation-timeline: view(); animation-range: entry 20% cover 40%; } /* Fallback: use Intersection Observer pattern in a small script */ .reveal-on-scroll { opacity: 0; transform: translateY(24px); transition: opacity 0.6s ease-out, transform 0.6s ease-out; } .reveal-on-scroll.visible { opacity: 1; transform: translateY(0); } \`\`\` ### Staggered Lists \`\`\`css .stagger-list > * { opacity: 0; animation: fadeUp 0.4s ease-out forwards; } .stagger-list > *:nth-child(1) { animation-delay: 0ms; } .stagger-list > *:nth-child(2) { animation-delay: 80ms; } .stagger-list > *:nth-child(3) { animation-delay: 160ms; } .stagger-list > *:nth-child(4) { animation-delay: 240ms; } .stagger-list > *:nth-child(5) { animation-delay: 320ms; } .stagger-list > *:nth-child(6) { animation-delay: 400ms; } /* Continue pattern: delay = (n-1) * 80ms up to n=20 */ \`\`\` ### Loading States \`\`\`css /* Spinner */ @keyframes spin { to { transform: rotate(360deg); } } .spinner { width: 24px; height: 24px; border: 3px solid var(--border); border-top-color: var(--accent); border-radius: 50%; animation: spin 0.6s linear infinite; } /* Skeleton pulse */ @keyframes shimmer { 0% { background-position: -200% 0; } 100% { background-position: 200% 0; } } .skeleton { background: linear-gradient(90deg, var(--surface) 25%, color-mix(in oklab, var(--surface) 50%, var(--bg)) 50%, var(--surface) 75%); background-size: 200% 100%; animation: shimmer 1.5s ease-in-out infinite; border-radius: 4px; } /* Progress bar */ @keyframes progress { from { width: 0%; } to { width: 100%; } } .progress-bar { height: 4px; background: var(--surface); border-radius: 2px; overflow: hidden; } .progress-bar-fill { height: 100%; background: var(--accent); border-radius: 2px; animation: progress 2s ease-out forwards; } \`\`\` ### Hover Micro-Interactions \`\`\`css /* Subtle card lift */ .card-hover { transition: transform 0.2s ease, box-shadow 0.2s ease; } .card-hover:hover { transform: translateY(-2px); box-shadow: 0 8px 24px rgba(0,0,0,0.1); } /* Button press */ .btn-press { transition: transform 0.1s ease; } .btn-press:active { transform: scale(0.97); } /* Link underline slide */ .link-slide { position: relative; text-decoration: none; } .link-slide::after { content: ""; position: absolute; bottom: -1px; left: 0; width: 0; height: 1.5px; background: var(--accent); transition: width 0.3s ease; } .link-slide:hover::after { width: 100%; } /* Image zoom */ .img-zoom { overflow: hidden; border-radius: 8px; } .img-zoom img { transition: transform 0.3s ease; } .img-zoom:hover img { transform: scale(1.05); } \`\`\` ### Page Transitions (View Transitions API) \`\`\`css /* Add to :root for cross-fade transitions */ ::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.4s; } /* Named transitions for specific elements */ .hero-title { view-transition-name: hero-title; } .hero-image { view-transition-name: hero-image; } \`\`\` ## Phase 2 — Showcase Layout Build a single HTML page demonstrating each animation category: 1. **Entrance section** — cards/stats that animate in on load 2. **Scroll reveal section** — content that appears as you scroll 3. **Staggered list** — feature list with cascading reveal 4. **Loading section** — skeleton screens next to real content 5. **Hover gallery** — cards with different hover treatments 6. **Interactive section** — buttons and links with micro-interactions ## Phase 3 — Motion Design Rules - **Duration**: 150-400ms for micro-interactions; 400-800ms for entrances; DON'T use values above 1s - **Easing**: ease-out for entrances (fast start, settle gracefully); ease-in-out for continuous animations - **Stagger**: 60-100ms between children; maximum 20 items in a stagger - **Performance**: animate transform and opacity only (no width/height/margin animations) - **Respect reduced motion**: wrap animations in @media (prefers-reduced-motion: no-preference) - **No animation on every element** — pick 2-3 key moments per page - **Animation should communicate** — loading state, new content arriving, affordance — not just decoration`, };