| import React from 'react'; | |
| import { motion } from 'framer-motion'; | |
| export function BoundingBoxDemo() { | |
| return ( | |
| <div className="relative w-full max-w-md mx-auto aspect-video bg-gradient-to-br from-slate-800 to-slate-900 rounded-2xl overflow-hidden border border-white/10"> | |
| {/* Simulated Image */} | |
| <div className="absolute inset-0 flex items-center justify-center"> | |
| <div className="text-6xl">π</div> | |
| </div> | |
| {/* Animated Bounding Box */} | |
| <motion.div | |
| className="absolute border-4 border-cyan-400 rounded-lg" | |
| initial={{ opacity: 0, scale: 0.8 }} | |
| animate={{ | |
| opacity: [0, 1, 1, 1], | |
| scale: [0.8, 1, 1, 1], | |
| }} | |
| transition={{ duration: 2, repeat: Infinity, repeatDelay: 1 }} | |
| style={{ | |
| top: '25%', | |
| left: '30%', | |
| width: '40%', | |
| height: '50%' | |
| }} | |
| > | |
| <motion.div | |
| className="absolute -top-8 left-0 bg-cyan-400 text-slate-900 px-3 py-1 rounded-lg text-sm font-bold" | |
| initial={{ opacity: 0, y: 10 }} | |
| animate={{ opacity: [0, 1, 1, 0], y: [10, 0, 0, -10] }} | |
| transition={{ duration: 2, repeat: Infinity, repeatDelay: 1, delay: 0.3 }} | |
| > | |
| Car 98% | |
| </motion.div> | |
| {/* Corner markers */} | |
| {[ | |
| { top: -4, left: -4 }, | |
| { top: -4, right: -4 }, | |
| { bottom: -4, left: -4 }, | |
| { bottom: -4, right: -4 } | |
| ].map((pos, i) => ( | |
| <motion.div | |
| key={i} | |
| className="absolute w-3 h-3 bg-cyan-400 rounded-full" | |
| style={pos} | |
| animate={{ scale: [1, 1.3, 1] }} | |
| transition={{ duration: 1, repeat: Infinity, delay: i * 0.1 }} | |
| /> | |
| ))} | |
| </motion.div> | |
| </div> | |
| ); | |
| } | |
| export function PoseSkeletonDemo() { | |
| const keypoints = [ | |
| { id: 'head', x: 50, y: 10, label: 'Head' }, | |
| { id: 'neck', x: 50, y: 22 }, | |
| { id: 'lshoulder', x: 35, y: 25 }, | |
| { id: 'rshoulder', x: 65, y: 25 }, | |
| { id: 'lelbow', x: 25, y: 40 }, | |
| { id: 'relbow', x: 75, y: 40 }, | |
| { id: 'lwrist', x: 20, y: 55 }, | |
| { id: 'rwrist', x: 80, y: 55 }, | |
| { id: 'hip', x: 50, y: 50 }, | |
| { id: 'lhip', x: 40, y: 52 }, | |
| { id: 'rhip', x: 60, y: 52 }, | |
| { id: 'lknee', x: 38, y: 70 }, | |
| { id: 'rknee', x: 62, y: 70 }, | |
| { id: 'lankle', x: 35, y: 90 }, | |
| { id: 'rankle', x: 65, y: 90 }, | |
| ]; | |
| const bones = [ | |
| ['head', 'neck'], | |
| ['neck', 'lshoulder'], | |
| ['neck', 'rshoulder'], | |
| ['lshoulder', 'lelbow'], | |
| ['rshoulder', 'relbow'], | |
| ['lelbow', 'lwrist'], | |
| ['relbow', 'rwrist'], | |
| ['neck', 'hip'], | |
| ['hip', 'lhip'], | |
| ['hip', 'rhip'], | |
| ['lhip', 'lknee'], | |
| ['rhip', 'rknee'], | |
| ['lknee', 'lankle'], | |
| ['rknee', 'rankle'], | |
| ]; | |
| const getPoint = (id) => keypoints.find(k => k.id === id); | |
| return ( | |
| <div className="relative w-full max-w-sm mx-auto aspect-[3/4] bg-gradient-to-br from-purple-900/50 to-pink-900/50 rounded-2xl overflow-hidden border border-white/10"> | |
| <svg className="w-full h-full" viewBox="0 0 100 100"> | |
| {/* Bones */} | |
| {bones.map(([from, to], i) => { | |
| const p1 = getPoint(from); | |
| const p2 = getPoint(to); | |
| return ( | |
| <motion.line | |
| key={i} | |
| x1={p1.x} | |
| y1={p1.y} | |
| x2={p2.x} | |
| y2={p2.y} | |
| stroke="url(#boneGradient)" | |
| strokeWidth="2" | |
| strokeLinecap="round" | |
| initial={{ pathLength: 0, opacity: 0 }} | |
| animate={{ pathLength: 1, opacity: 1 }} | |
| transition={{ duration: 0.5, delay: i * 0.05 }} | |
| /> | |
| ); | |
| })} | |
| {/* Keypoints */} | |
| {keypoints.map((point, i) => ( | |
| <motion.circle | |
| key={point.id} | |
| cx={point.x} | |
| cy={point.y} | |
| r="3" | |
| fill="#EC4899" | |
| initial={{ scale: 0 }} | |
| animate={{ scale: [1, 1.3, 1] }} | |
| transition={{ | |
| scale: { duration: 1, repeat: Infinity, delay: i * 0.1 }, | |
| default: { delay: i * 0.05 } | |
| }} | |
| /> | |
| ))} | |
| <defs> | |
| <linearGradient id="boneGradient" x1="0%" y1="0%" x2="100%" y2="100%"> | |
| <stop offset="0%" stopColor="#8B5CF6" /> | |
| <stop offset="100%" stopColor="#EC4899" /> | |
| </linearGradient> | |
| </defs> | |
| </svg> | |
| </div> | |
| ); | |
| } | |
| export function EmotionFaceDemo() { | |
| const emotions = [ | |
| { emoji: 'π', label: 'Happy', color: 'from-yellow-400 to-orange-400' }, | |
| { emoji: 'π’', label: 'Sad', color: 'from-blue-400 to-indigo-400' }, | |
| { emoji: 'π ', label: 'Angry', color: 'from-red-400 to-rose-400' }, | |
| { emoji: 'π²', label: 'Surprise', color: 'from-purple-400 to-pink-400' }, | |
| { emoji: 'π', label: 'Neutral', color: 'from-gray-400 to-slate-400' }, | |
| ]; | |
| const [currentEmotion, setCurrentEmotion] = React.useState(0); | |
| React.useEffect(() => { | |
| const interval = setInterval(() => { | |
| setCurrentEmotion((prev) => (prev + 1) % emotions.length); | |
| }, 2000); | |
| return () => clearInterval(interval); | |
| }, []); | |
| const emotion = emotions[currentEmotion]; | |
| return ( | |
| <div className="relative w-full max-w-sm mx-auto"> | |
| <motion.div | |
| key={currentEmotion} | |
| initial={{ scale: 0.8, opacity: 0 }} | |
| animate={{ scale: 1, opacity: 1 }} | |
| exit={{ scale: 0.8, opacity: 0 }} | |
| className="aspect-square bg-gradient-to-br from-slate-800 to-slate-900 rounded-3xl border border-white/10 flex flex-col items-center justify-center" | |
| > | |
| <motion.div | |
| className="text-8xl mb-4" | |
| animate={{ scale: [1, 1.1, 1] }} | |
| transition={{ duration: 1, repeat: Infinity }} | |
| > | |
| {emotion.emoji} | |
| </motion.div> | |
| <motion.div | |
| className={`px-6 py-2 rounded-full bg-gradient-to-r ${emotion.color} text-white font-bold text-lg`} | |
| initial={{ y: 20, opacity: 0 }} | |
| animate={{ y: 0, opacity: 1 }} | |
| transition={{ delay: 0.2 }} | |
| > | |
| {emotion.label} | |
| </motion.div> | |
| </motion.div> | |
| {/* Confidence Bars */} | |
| <div className="mt-6 space-y-2"> | |
| {emotions.map((e, i) => ( | |
| <div key={i} className="flex items-center gap-3"> | |
| <span className="text-xl w-8">{e.emoji}</span> | |
| <div className="flex-1 h-3 bg-white/10 rounded-full overflow-hidden"> | |
| <motion.div | |
| className={`h-full bg-gradient-to-r ${e.color}`} | |
| initial={{ width: 0 }} | |
| animate={{ width: i === currentEmotion ? '95%' : `${Math.random() * 30 + 5}%` }} | |
| transition={{ duration: 0.5 }} | |
| /> | |
| </div> | |
| <span className="text-white/60 text-sm w-12 text-right"> | |
| {i === currentEmotion ? '95%' : `${Math.floor(Math.random() * 20 + 5)}%`} | |
| </span> | |
| </div> | |
| ))} | |
| </div> | |
| </div> | |
| ); | |
| } |