install
source · Clone the upstream repo
git clone https://github.com/aiskillstore/marketplace
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/aiskillstore/marketplace "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/barnhardt-enterprises-inc/shadcn-framer" ~/.claude/skills/aiskillstore-marketplace-shadcn-framer && rm -rf "$T"
manifest:
skills/barnhardt-enterprises-inc/shadcn-framer/SKILL.mdsource content
ShadCN + Framer Motion
ShadCN Setup
pnpm dlx shadcn@latest init pnpm dlx shadcn@latest add button card dialog
Component Usage
import { Button } from '@/components/ui/button'; import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter, } from '@/components/ui/card'; export function UserCard({ user }: { user: User }) { return ( <Card> <CardHeader> <CardTitle>{user.name}</CardTitle> <CardDescription>{user.email}</CardDescription> </CardHeader> <CardContent> <p>{user.bio}</p> </CardContent> <CardFooter> <Button>View Profile</Button> </CardFooter> </Card> ); }
Framer Motion Basics
'use client'; import { motion } from 'framer-motion'; export function FadeIn({ children }: { children: React.ReactNode }) { return ( <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.3 }} > {children} </motion.div> ); }
Animated List
'use client'; import { motion, AnimatePresence } from 'framer-motion'; const container = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { staggerChildren: 0.1 }, }, }; const item = { hidden: { opacity: 0, x: -20 }, show: { opacity: 1, x: 0 }, }; export function AnimatedList({ items }: { items: Item[] }) { return ( <motion.ul variants={container} initial="hidden" animate="show"> <AnimatePresence> {items.map((i) => ( <motion.li key={i.id} variants={item} exit={{ opacity: 0, x: 20 }} layout > {i.name} </motion.li> ))} </AnimatePresence> </motion.ul> ); }
Page Transitions
// components/page-transition.tsx 'use client'; import { motion } from 'framer-motion'; export function PageTransition({ children }: { children: React.ReactNode }) { return ( <motion.div initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: -20 }} transition={{ duration: 0.2 }} > {children} </motion.div> ); }
Animated Dialog
'use client'; import { motion, AnimatePresence } from 'framer-motion'; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; export function AnimatedDialog({ open, onOpenChange, children, }: { open: boolean; onOpenChange: (open: boolean) => void; children: React.ReactNode; }) { return ( <Dialog open={open} onOpenChange={onOpenChange}> <AnimatePresence> {open && ( <DialogContent asChild> <motion.div initial={{ opacity: 0, scale: 0.95 }} animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, scale: 0.95 }} transition={{ duration: 0.15 }} > {children} </motion.div> </DialogContent> )} </AnimatePresence> </Dialog> ); }
Hover Effects
'use client'; import { motion } from 'framer-motion'; import { Card } from '@/components/ui/card'; export function HoverCard({ children }: { children: React.ReactNode }) { return ( <motion.div whileHover={{ scale: 1.02, y: -4 }} whileTap={{ scale: 0.98 }} transition={{ type: 'spring', stiffness: 300, damping: 20 }} > <Card className="cursor-pointer">{children}</Card> </motion.div> ); }
Loading Skeleton with Pulse
'use client'; import { motion } from 'framer-motion'; export function Skeleton({ className }: { className?: string }) { return ( <motion.div className={`bg-muted rounded ${className}`} animate={{ opacity: [0.5, 1, 0.5] }} transition={{ duration: 1.5, repeat: Infinity }} /> ); }