Skip to main content
Glama

UI/UX MCP Server

by willem4130
animation.tsโ€ข6.36 kB
import { z } from 'zod'; const AnimationTimelineSchema = z.object({ library: z.enum(['framer-motion', 'gsap']).default('framer-motion'), animations: z.array(z.object({ target: z.string(), properties: z.record(z.any()), duration: z.number().optional(), delay: z.number().optional(), easing: z.string().optional() })) }); const AnimationPreviewSchema = z.object({ timeline: z.any(), format: z.enum(['gif', 'mp4', 'webm']).default('gif') }); export class AnimationTools { constructor() {} async createTimeline(args: any) { const params = AnimationTimelineSchema.parse(args); try { let timeline: any; if (params.library === 'framer-motion') { timeline = this.createFramerMotionTimeline(params.animations); } else { timeline = this.createGSAPTimeline(params.animations); } return { content: [ { type: 'text', text: JSON.stringify({ library: params.library, timeline, usage: this.getUsageExample(params.library), totalDuration: this.calculateTotalDuration(params.animations) }, null, 2) } ] }; } catch (error: any) { return { content: [ { type: 'text', text: `Error creating animation timeline: ${error.message}` } ], isError: true }; } } async preview(args: any) { const params = AnimationPreviewSchema.parse(args); try { // Simulate animation preview generation const previewData = { format: params.format, duration: this.getTimelineDuration(params.timeline), frames: params.format === 'gif' ? 30 : 60, size: { width: 800, height: 600 }, preview: { url: `preview_${Date.now()}.${params.format}`, message: 'Preview generated successfully (simulated)' } }; return { content: [ { type: 'text', text: JSON.stringify(previewData, null, 2) } ] }; } catch (error: any) { return { content: [ { type: 'text', text: `Error generating preview: ${error.message}` } ], isError: true }; } } private createFramerMotionTimeline(animations: any[]): any { const variants: any = {}; const sequence: any[] = []; animations.forEach((anim, index) => { const variantName = `step${index}`; variants[variantName] = { ...anim.properties, transition: { duration: anim.duration || 0.3, delay: anim.delay || 0, ease: this.convertToFramerEasing(anim.easing) } }; sequence.push({ target: anim.target, variant: variantName, at: anim.delay || index * 0.1 }); }); return { type: 'framer-motion', variants, sequence, code: this.generateFramerMotionCode(variants, sequence) }; } private createGSAPTimeline(animations: any[]): any { const timeline: any[] = []; animations.forEach((anim) => { timeline.push({ target: anim.target, vars: { ...anim.properties, duration: anim.duration || 0.3, delay: anim.delay || 0, ease: this.convertToGSAPEasing(anim.easing) } }); }); return { type: 'gsap', timeline, code: this.generateGSAPCode(timeline) }; } private convertToFramerEasing(easing?: string): string { const easingMap: any = { 'ease-in': 'easeIn', 'ease-out': 'easeOut', 'ease-in-out': 'easeInOut', 'linear': 'linear', 'bounce': [0.68, -0.55, 0.265, 1.55], 'elastic': [0.175, 0.885, 0.32, 1.275] }; return easingMap[easing || 'ease-in-out'] || 'easeInOut'; } private convertToGSAPEasing(easing?: string): string { const easingMap: any = { 'ease-in': 'power2.in', 'ease-out': 'power2.out', 'ease-in-out': 'power2.inOut', 'linear': 'none', 'bounce': 'bounce.out', 'elastic': 'elastic.out' }; return easingMap[easing || 'ease-in-out'] || 'power2.inOut'; } private generateFramerMotionCode(variants: any, sequence: any[]): string { return ` import { motion, useAnimation } from 'framer-motion'; const variants = ${JSON.stringify(variants, null, 2)}; function AnimatedComponent() { const controls = useAnimation(); const runAnimation = async () => { ${sequence.map(s => ` await controls.start('${s.variant}');`).join('')} }; return ( <motion.div variants={variants} animate={controls} onClick={runAnimation} > {/* Your content */} </motion.div> ); }`; } private generateGSAPCode(timeline: any[]): string { return ` import { gsap } from 'gsap'; import { useEffect, useRef } from 'react'; function AnimatedComponent() { const containerRef = useRef(null); useEffect(() => { const tl = gsap.timeline(); ${timeline.map(t => ` tl.to('${t.target}', ${JSON.stringify(t.vars, null, 2)});`).join('')} return () => tl.kill(); }, []); return ( <div ref={containerRef}> {/* Your content */} </div> ); }`; } private calculateTotalDuration(animations: any[]): number { let maxEndTime = 0; animations.forEach(anim => { const startTime = anim.delay || 0; const duration = anim.duration || 0.3; const endTime = startTime + duration; maxEndTime = Math.max(maxEndTime, endTime); }); return maxEndTime; } private getTimelineDuration(timeline: any): number { if (timeline?.type === 'framer-motion') { return Object.keys(timeline.variants || {}).length * 0.3; } else if (timeline?.type === 'gsap') { return (timeline.timeline || []).length * 0.3; } return 1; } private getUsageExample(library: string): string { if (library === 'framer-motion') { return 'npm install framer-motion\n// Import and use the generated code in your React component'; } else { return 'npm install gsap\n// Import and use the generated code in your component'; } } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/willem4130/ui-ux-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server