Skip to main content
Glama

create_theme_preview_html

Generate HTML mockups to visualize color themes in realistic UI contexts like websites, mobile apps, and dashboards for design validation.

Instructions

Generate HTML theme preview mockups showing colors in realistic UI contexts

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • Core handler function executing the tool logic: validates inputs, processes theme colors with accessibility checks, generates interactive HTML preview mockups, handles exports, and file saving.
    async function createThemePreviewHtml( params: CreateThemePreviewHtmlParams ): Promise<ToolResponse | ErrorResponse> { const startTime = Date.now(); try { // Validate parameters const { error, value } = createThemePreviewHtmlSchema.validate(params); if (error) { return { success: false, error: { code: 'INVALID_PARAMETERS', message: 'Invalid parameters provided', details: error.details, suggestions: [ 'Ensure theme_colors is an object with color name keys and color value strings', 'Check that preview_type is one of: website, mobile_app, dashboard, components', 'Verify components array contains valid component names', ], }, metadata: { execution_time: Date.now() - startTime, tool: 'create_theme_preview_html', timestamp: new Date().toISOString(), }, }; } const validatedParams = value as CreateThemePreviewHtmlParams; // Validate and process theme colors const processedThemeColors: Record< string, { hex: string; rgb: string; hsl: string; name: string; accessibility?: { contrastRatio: number; wcagAA: boolean; wcagAAA: boolean; }; } > = {}; const accessibilityNotes: string[] = []; const recommendations: string[] = []; // Required semantic colors for different preview types const requiredColors = getRequiredColorsForPreviewType( validatedParams.preview_type || 'website' ); const missingColors: string[] = []; for (const [colorName, colorValue] of Object.entries( validatedParams.theme_colors )) { if (!colorValue || typeof colorValue !== 'string') { return { success: false, error: { code: 'INVALID_COLOR_VALUE', message: `Invalid color value for "${colorName}": ${colorValue}`, details: { colorName, colorValue }, suggestions: [ 'Ensure all color values are valid color strings', 'Use hex format like #FF0000', 'Use RGB format like rgb(255, 0, 0)', 'Use HSL format like hsl(0, 100%, 50%)', ], }, metadata: { execution_time: Date.now() - startTime, tool: 'create_theme_preview_html', timestamp: new Date().toISOString(), }, }; } try { // Validate color format const colorValidation = validateColorInput(colorValue); if (!colorValidation.isValid) { return { success: false, error: { code: 'INVALID_COLOR_FORMAT', message: `Invalid color format for "${colorName}": ${colorValue}`, details: { colorName, colorValue, reason: colorValidation.error, }, suggestions: [ 'Use hex format like #FF0000', 'Use RGB format like rgb(255, 0, 0)', 'Use HSL format like hsl(0, 100%, 50%)', 'Check the color format documentation', ], }, metadata: { execution_time: Date.now() - startTime, tool: 'create_theme_preview_html', timestamp: new Date().toISOString(), }, }; } const unifiedColor = new UnifiedColor(colorValue); // Calculate accessibility information let accessibility; if (colorName === 'text' || colorName === 'primary') { // Calculate contrast against background colors const backgroundColors = ['background', 'surface']; let bestContrast = 0; for (const bgColorName of backgroundColors) { if (validatedParams.theme_colors[bgColorName]) { try { const bgColor = new UnifiedColor( validatedParams.theme_colors[bgColorName] ); const contrast = unifiedColor.getContrastRatio(bgColor.hex); bestContrast = Math.max(bestContrast, contrast); } catch { // Ignore errors for background color processing } } } if (bestContrast > 0) { accessibility = { contrastRatio: bestContrast, wcagAA: bestContrast >= 4.5, wcagAAA: bestContrast >= 7.0, }; if (!accessibility.wcagAA) { accessibilityNotes.push( `Color "${colorName}" may not meet WCAG AA contrast requirements (${bestContrast.toFixed(2)}:1)` ); } } } processedThemeColors[colorName] = { hex: unifiedColor.hex, rgb: unifiedColor.toFormat('rgb'), hsl: unifiedColor.toFormat('hsl'), name: colorName, ...(accessibility && { accessibility }), }; } catch (colorError) { return { success: false, error: { code: 'COLOR_PROCESSING_ERROR', message: `Failed to process color "${colorName}": ${colorValue}`, details: { colorName, colorValue, error: colorError }, suggestions: [ 'Verify the color format is supported', 'Check for typos in color values', 'Try a different color format', ], }, metadata: { execution_time: Date.now() - startTime, tool: 'create_theme_preview_html', timestamp: new Date().toISOString(), }, }; } } // Check for missing required colors for (const requiredColor of requiredColors) { if (!processedThemeColors[requiredColor]) { missingColors.push(requiredColor); } } if (missingColors.length > 0) { recommendations.push( `Consider adding these semantic colors for better ${validatedParams.preview_type} preview: ${missingColors.join(', ')}` ); } // Generate additional recommendations const colorCount = Object.keys(processedThemeColors).length; if (colorCount < 3) { recommendations.push( 'Consider adding more semantic colors (background, text, primary, secondary) for a complete theme' ); } if ( validatedParams.preview_type === 'dashboard' && !processedThemeColors['sidebar'] ) { recommendations.push( 'Dashboard previews work best with a sidebar color defined' ); } // Prepare visualization data const visualizationData: ThemePreviewVisualizationData = { themeColors: processedThemeColors, previewType: validatedParams.preview_type || 'website', components: validatedParams.components || [ 'header', 'content', 'buttons', ], interactive: validatedParams.interactive !== false, responsive: validatedParams.responsive !== false, theme: validatedParams.theme || 'light', metadata: { title: 'Theme Preview', description: `${validatedParams.preview_type || 'Website'} preview with ${colorCount} theme colors`, timestamp: new Date().toLocaleString(), colorCount, previewType: validatedParams.preview_type || 'website', }, }; // Generate enhanced HTML with background controls let result: EnhancedVisualizationResult; try { const enhancedOptions: EnhancedHTMLOptions = { interactive: true, // Enable interactive features including JavaScript backgroundControls: { enableToggle: validatedParams.enable_background_controls ?? true, enableColorPicker: validatedParams.enable_background_controls ?? true, defaultBackground: validatedParams.theme === 'dark' ? 'dark' : 'light', }, enableAccessibilityTesting: validatedParams.enable_accessibility_testing ?? true, includeKeyboardHelp: validatedParams.include_keyboard_help ?? true, }; result = await enhancedHTMLGenerator.generateEnhancedThemePreviewHTML( visualizationData, enhancedOptions ); } catch (htmlError) { throw new Error( `Failed to generate enhanced HTML: ${htmlError instanceof Error ? htmlError.message : String(htmlError)}` ); } // Prepare export formats const exportFormats: Record<string, string | object> = {}; exportFormats['css'] = generateThemeCSSExport(processedThemeColors); exportFormats['scss'] = generateThemeSCSSExport(processedThemeColors); exportFormats['json'] = { theme_colors: Object.fromEntries( Object.entries(processedThemeColors).map(([name, color]) => [ name, { hex: color.hex, rgb: color.rgb, hsl: color.hsl, accessibility: color.accessibility, }, ]) ), preview_type: validatedParams.preview_type, components: validatedParams.components, metadata: visualizationData.metadata, }; const executionTime = Date.now() - startTime; // Try to save file using enhanced file output manager let visualizationResult; try { await enhancedFileOutputManager.initialize(); // If we have HTML content, save it using the enhanced file output manager if (result.htmlContent) { visualizationResult = await enhancedFileOutputManager.saveHTMLVisualization( result.htmlContent, { toolName: 'create_theme_preview_html', description: `Enhanced theme preview with ${colorCount} colors`, } ); } } catch (fileError) { // If file saving fails, we'll fall back to returning HTML content directly logger.warn('Failed to save HTML file, falling back to content', { error: fileError as Error, }); } return { success: true, data: { theme_colors: Object.fromEntries( Object.entries(processedThemeColors).map(([name, color]) => [ name, color.hex, ]) ), preview_type: validatedParams.preview_type || 'website', components: validatedParams.components || [ 'header', 'content', 'buttons', ], color_count: colorCount, accessibility_compliant: Object.values(processedThemeColors).every( color => !color.accessibility || color.accessibility.wcagAA ), file_path: result.filePath, file_name: result.fileName, file_size: result.fileSize, background_controls_enabled: result.backgroundControlsEnabled, accessibility_features: result.accessibilityFeatures, }, metadata: { execution_time: executionTime, tool: 'create_theme_preview_html', timestamp: new Date().toISOString(), color_space_used: 'sRGB', accessibility_notes: accessibilityNotes, recommendations: [ ...recommendations, 'HTML file saved with interactive background controls', 'Use Alt+T to toggle background theme', 'Use Alt+C to open color picker', ], }, visualizations: { html: result.htmlContent || `File saved: ${result.filePath}`, ...(visualizationResult?.html_file && { html_file: visualizationResult.html_file, }), }, export_formats: exportFormats, }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); const errorStack = error instanceof Error ? error.stack : undefined; return { success: false, error: { code: 'INTERNAL_ERROR', message: `Theme preview HTML generation error: ${errorMessage}`, details: { errorMessage, errorStack, errorType: error?.constructor?.name || 'Unknown', }, suggestions: [ 'Verify all theme colors are in valid formats', 'Check that the preview type and components are supported', 'Try with a simpler theme color set', ], }, metadata: { execution_time: Date.now() - startTime, tool: 'create_theme_preview_html', timestamp: new Date().toISOString(), }, }; } }
  • Joi schema defining input parameters including theme_colors, preview_type, components, and various options.
    const createThemePreviewHtmlSchema = Joi.object({ theme_colors: Joi.object() .pattern(Joi.string(), Joi.string()) .required() .description('Semantic color mapping object'), preview_type: Joi.string() .valid('website', 'mobile_app', 'dashboard', 'components') .default('website') .description('Preview type'), components: Joi.array() .items( Joi.string().valid( 'header', 'sidebar', 'content', 'footer', 'buttons', 'forms', 'cards' ) ) .default(['header', 'content', 'buttons']) .description('Components to show'), interactive: Joi.boolean().default(true).description('Enable interactivity'), responsive: Joi.boolean().default(true).description('Responsive design'), theme: Joi.string() .valid('light', 'dark', 'auto') .default('light') .description('Color theme for the visualization'), enable_background_controls: Joi.boolean() .default(true) .description('Enable interactive background controls'), enable_accessibility_testing: Joi.boolean() .default(true) .description('Enable accessibility testing and warnings'), include_keyboard_help: Joi.boolean() .default(true) .description('Include keyboard shortcuts help'), });
  • ToolHandler export that defines the tool name, description, parameters schema, and handler wrapper.
    export const createThemePreviewHtmlTool: ToolHandler = { name: 'create_theme_preview_html', description: 'Generate HTML theme preview mockups showing colors in realistic UI contexts', parameters: createThemePreviewHtmlSchema.describe(), handler: async (params: unknown) => createThemePreviewHtml(params as CreateThemePreviewHtmlParams), };
  • Central import and registration of the tool into the ToolRegistry singleton.
    import { createThemePreviewHtmlTool } from './create-theme-preview-html'; // Import and register PNG generation tools import { createPalettePngTool } from './create-palette-png'; import { createGradientPngTool } from './create-gradient-png'; import { createColorComparisonPngTool } from './create-color-comparison-png'; // Import and register theme generation tools import { generateThemeTool } from './generate-theme'; import { generateSemanticColorsTool } from './generate-semantic-colors'; // Import color utility tools import { mixColorsTool } from './mix-colors'; import { generateColorVariationsTool } from './generate-color-variations'; import { sortColorsTool } from './sort-colors'; import { analyzeColorCollectionTool } from './analyze-color-collection'; // Import export format tools import { exportCssTool } from './export-css'; import { exportScssTool } from './export-scss'; import { exportTailwindTool } from './export-tailwind'; import { exportJsonTool } from './export-json'; // Register conversion tools toolRegistry.registerTool(convertColorTool); // Register analysis tools toolRegistry.registerTool(analyzeColorTool); toolRegistry.registerTool(checkContrastTool); // Register accessibility tools toolRegistry.registerTool(simulateColorblindnessTool); toolRegistry.registerTool(optimizeForAccessibilityTool); // Register palette generation tools toolRegistry.registerTool(generateHarmonyPaletteTool); // Register gradient generation tools toolRegistry.registerTool(generateLinearGradientTool); toolRegistry.registerTool(generateRadialGradientTool); // Register visualization tools toolRegistry.registerTool(createPaletteHtmlTool); toolRegistry.registerTool(createColorWheelHtmlTool); toolRegistry.registerTool(createGradientHtmlTool); toolRegistry.registerTool(createThemePreviewHtmlTool);
  • Helper function determining required semantic colors for different preview types (website, mobile_app, etc.).
    function getRequiredColorsForPreviewType(previewType: string): string[] { const baseColors = ['background', 'text', 'primary']; switch (previewType) { case 'website': return [...baseColors, 'surface', 'secondary']; case 'mobile_app': return [...baseColors, 'surface', 'accent']; case 'dashboard': return [ ...baseColors, 'surface', 'sidebar', 'accent', 'success', 'warning', 'error', ]; case 'components': return [ ...baseColors, 'secondary', 'success', 'warning', 'error', 'info', ]; default: return baseColors; } }

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/keyurgolani/ColorMcp'

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