Skip to main content
Glama
analyzer.ts11.5 kB
import type { InterfaceType, DesignStyle, AnalysisResult } from '../utils/types.js'; import { INTERFACE_TEMPLATES } from '../resources/templates.js'; const INTERFACE_KEYWORDS: Record<InterfaceType, string[]> = { 'website-landing': ['landing', 'conversion', 'lead', 'signup', 'waitlist', 'launch', 'coming soon', 'one page', 'single page'], 'website-saas': ['saas', 'software', 'platform', 'subscription', 'b2b', 'startup', 'tool', 'service', 'pricing'], 'website-portfolio': ['portfolio', 'showcase', 'creative', 'agency', 'freelance', 'personal', 'work samples', 'projects'], 'website-ecommerce': ['shop', 'store', 'ecommerce', 'e-commerce', 'products', 'cart', 'checkout', 'buy', 'sell', 'marketplace'], 'dashboard': ['dashboard', 'analytics', 'metrics', 'data', 'charts', 'reports', 'monitoring', 'admin', 'statistics'], 'mobile-app': ['mobile', 'app', 'ios', 'android', 'native', 'phone', 'smartphone', 'tablet'], 'desktop-app': ['desktop', 'windows', 'mac', 'linux', 'electron', 'native app', 'software application'], 'cli-terminal': ['cli', 'terminal', 'command line', 'console', 'shell', 'command-line', 'text interface'], 'presentation': ['presentation', 'slides', 'deck', 'powerpoint', 'keynote', 'pitch', 'talk', 'slideshow'], 'admin-panel': ['admin', 'cms', 'backend', 'management', 'control panel', 'backoffice'], 'social-platform': ['social', 'community', 'network', 'feed', 'posts', 'messaging', 'chat', 'forum'], 'custom': [] }; const STYLE_KEYWORDS: Record<DesignStyle, string[]> = { 'minimalist': ['minimal', 'clean', 'simple', 'whitespace', 'less is more', 'elegant', 'understated'], 'bold-experimental': ['bold', 'experimental', 'creative', 'unique', 'innovative', 'avant-garde', 'cutting edge', 'unconventional'], 'corporate-professional': ['corporate', 'professional', 'business', 'enterprise', 'formal', 'trustworthy', 'serious'], 'playful-creative': ['playful', 'fun', 'colorful', 'vibrant', 'energetic', 'youthful', 'friendly', 'whimsical'], 'luxury-elegant': ['luxury', 'premium', 'elegant', 'sophisticated', 'high-end', 'exclusive', 'refined'], 'tech-futuristic': ['tech', 'futuristic', 'modern', 'digital', 'cyber', 'neon', 'sci-fi', 'advanced'], 'organic-natural': ['organic', 'natural', 'earthy', 'sustainable', 'eco', 'green', 'wellness', 'holistic'], 'brutalist': ['brutalist', 'raw', 'industrial', 'edgy', 'stark', 'unconventional', 'anti-design'], 'retro-vintage': ['retro', 'vintage', 'nostalgic', 'classic', '80s', '90s', 'throwback', 'old school'], 'glassmorphic': ['glass', 'frosted', 'transparent', 'blur', 'translucent', 'glassmorphism'], 'neumorphic': ['neumorphic', 'soft ui', 'soft shadows', '3d buttons', 'extruded'], 'custom': [] }; function detectInterfaceType(prompt: string): InterfaceType { const lowerPrompt = prompt.toLowerCase(); let bestMatch: InterfaceType = 'custom'; let highestScore = 0; for (const [type, keywords] of Object.entries(INTERFACE_KEYWORDS)) { const score = keywords.filter(kw => lowerPrompt.includes(kw)).length; if (score > highestScore) { highestScore = score; bestMatch = type as InterfaceType; } } return bestMatch; } function detectStyles(prompt: string): DesignStyle[] { const lowerPrompt = prompt.toLowerCase(); const detectedStyles: DesignStyle[] = []; for (const [style, keywords] of Object.entries(STYLE_KEYWORDS)) { if (keywords.some(kw => lowerPrompt.includes(kw))) { detectedStyles.push(style as DesignStyle); } } return detectedStyles.length > 0 ? detectedStyles : ['minimalist', 'bold-experimental']; } function extractKeyComponents(prompt: string, interfaceType: InterfaceType): string[] { const template = INTERFACE_TEMPLATES[interfaceType]; const baseComponents = [...template.keyComponents]; const additionalComponents: string[] = []; const componentPatterns = [ { pattern: /hero/i, component: 'Hero section' }, { pattern: /nav(igation)?/i, component: 'Navigation system' }, { pattern: /form/i, component: 'Form components' }, { pattern: /card/i, component: 'Card layouts' }, { pattern: /modal/i, component: 'Modal dialogs' }, { pattern: /table/i, component: 'Data tables' }, { pattern: /chart|graph/i, component: 'Data visualizations' }, { pattern: /search/i, component: 'Search functionality' }, { pattern: /filter/i, component: 'Filter controls' }, { pattern: /notification/i, component: 'Notification system' }, { pattern: /sidebar/i, component: 'Sidebar navigation' }, { pattern: /footer/i, component: 'Footer section' }, { pattern: /pricing/i, component: 'Pricing components' }, { pattern: /testimonial/i, component: 'Testimonial section' }, { pattern: /gallery/i, component: 'Image gallery' }, { pattern: /carousel|slider/i, component: 'Carousel/Slider' }, { pattern: /timeline/i, component: 'Timeline display' }, { pattern: /faq/i, component: 'FAQ accordion' }, { pattern: /contact/i, component: 'Contact form' }, { pattern: /auth|login|signup/i, component: 'Authentication flows' } ]; for (const { pattern, component } of componentPatterns) { if (pattern.test(prompt) && !baseComponents.includes(component)) { additionalComponents.push(component); } } return [...new Set([...baseComponents, ...additionalComponents])]; } function inferUserPersonas(prompt: string, interfaceType: InterfaceType): string[] { const personas: string[] = []; const lowerPrompt = prompt.toLowerCase(); const personaPatterns = [ { pattern: /developer|engineer|technical/i, persona: 'Technical professionals' }, { pattern: /business|enterprise|corporate/i, persona: 'Business decision-makers' }, { pattern: /creative|designer|artist/i, persona: 'Creative professionals' }, { pattern: /consumer|customer|shopper/i, persona: 'End consumers' }, { pattern: /student|learn|education/i, persona: 'Students and learners' }, { pattern: /admin|manager|operator/i, persona: 'System administrators' }, { pattern: /startup|founder|entrepreneur/i, persona: 'Startup founders' }, { pattern: /mobile|on.the.go/i, persona: 'Mobile-first users' }, { pattern: /professional|expert/i, persona: 'Industry professionals' } ]; for (const { pattern, persona } of personaPatterns) { if (pattern.test(lowerPrompt)) { personas.push(persona); } } if (personas.length === 0) { const defaultPersonas: Record<InterfaceType, string[]> = { 'website-landing': ['Potential customers', 'First-time visitors'], 'website-saas': ['Business users', 'Decision makers', 'End users'], 'website-portfolio': ['Potential clients', 'Recruiters', 'Collaborators'], 'website-ecommerce': ['Online shoppers', 'Price-conscious buyers'], 'dashboard': ['Data analysts', 'Managers', 'Power users'], 'mobile-app': ['Mobile users', 'On-the-go professionals'], 'desktop-app': ['Power users', 'Professional users'], 'cli-terminal': ['Developers', 'System administrators'], 'presentation': ['Conference attendees', 'Stakeholders'], 'admin-panel': ['Administrators', 'Content managers'], 'social-platform': ['Community members', 'Content creators'], 'custom': ['General users'] }; return defaultPersonas[interfaceType]; } return personas; } function suggestDesignPatterns(interfaceType: InterfaceType, styles: DesignStyle[]): string[] { const patterns: string[] = []; const typePatterns: Record<InterfaceType, string[]> = { 'website-landing': ['Hero with social proof', 'Feature grid', 'Testimonial carousel', 'Sticky CTA'], 'website-saas': ['Feature comparison', 'Pricing tiers', 'Integration showcase', 'Use case tabs'], 'website-portfolio': ['Project masonry', 'Case study template', 'Skills visualization', 'Contact CTA'], 'website-ecommerce': ['Product quick view', 'Filter sidebar', 'Cart drawer', 'Checkout stepper'], 'dashboard': ['Metric cards', 'Data tables', 'Chart widgets', 'Activity feed'], 'mobile-app': ['Tab navigation', 'Pull to refresh', 'Floating action button', 'Bottom sheets'], 'desktop-app': ['Multi-panel layout', 'Command palette', 'Context menus', 'Keyboard shortcuts'], 'cli-terminal': ['Progress indicators', 'Interactive prompts', 'Colored output', 'Help system'], 'presentation': ['Title patterns', 'Two-column layouts', 'Full-bleed images', 'Quote slides'], 'admin-panel': ['CRUD tables', 'Form wizards', 'Bulk actions', 'Audit logs'], 'social-platform': ['Infinite feed', 'Story carousels', 'Comment threads', 'Reaction system'], 'custom': ['Modular components', 'Flexible layouts'] }; patterns.push(...typePatterns[interfaceType]); if (styles.includes('glassmorphic')) { patterns.push('Frosted glass cards', 'Layered transparency'); } if (styles.includes('bold-experimental')) { patterns.push('Broken grid layouts', 'Overlapping elements', 'Custom cursor'); } if (styles.includes('minimalist')) { patterns.push('Generous whitespace', 'Type-focused hierarchy'); } return [...new Set(patterns)]; } function determineComplexity(prompt: string, components: string[]): 'simple' | 'moderate' | 'complex' | 'enterprise' { const componentCount = components.length; const wordCount = prompt.split(/\s+/).length; const complexityIndicators = [ /real.?time/i, /authentication/i, /multi.?tenant/i, /integration/i, /dashboard/i, /analytics/i, /notification/i, /search/i, /filter/i, /role.?based/i, /permission/i, /workflow/i, /automation/i ]; const complexityScore = complexityIndicators.filter(pattern => pattern.test(prompt)).length; if (componentCount > 15 || complexityScore > 5 || wordCount > 200) return 'enterprise'; if (componentCount > 10 || complexityScore > 3 || wordCount > 100) return 'complex'; if (componentCount > 5 || complexityScore > 1 || wordCount > 50) return 'moderate'; return 'simple'; } export function analyzeInterface(rawPrompt: string, providedType?: InterfaceType): AnalysisResult { const interfaceType = providedType || detectInterfaceType(rawPrompt); const suggestedStyles = detectStyles(rawPrompt); const keyComponents = extractKeyComponents(rawPrompt, interfaceType); const userPersonas = inferUserPersonas(rawPrompt, interfaceType); const designPatterns = suggestDesignPatterns(interfaceType, suggestedStyles); const complexity = determineComplexity(rawPrompt, keyComponents); return { interfaceType, suggestedStyles, keyComponents, userPersonas, designPatterns, complexity }; } export function generateAnalysisOutput(analysis: AnalysisResult, rawPrompt: string): string { return `# Interface Analysis ## Original Request "${rawPrompt}" ## Detected Interface Type **${analysis.interfaceType.replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase())}** ## Complexity Level **${analysis.complexity.charAt(0).toUpperCase() + analysis.complexity.slice(1)}** ## Suggested Design Styles ${analysis.suggestedStyles.map(s => `- ${s.replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase())}`).join('\n')} ## Key Components Identified ${analysis.keyComponents.map(c => `- ${c}`).join('\n')} ## Target User Personas ${analysis.userPersonas.map(p => `- ${p}`).join('\n')} ## Recommended Design Patterns ${analysis.designPatterns.map(p => `- ${p}`).join('\n')} --- *This analysis forms the foundation for the refined design prompt.* `; }

Implementation Reference

Latest Blog Posts

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/Nwabukin/mcp-ui-prompt-refiner'

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