Skip to main content
Glama

create_palette_html

Generate interactive HTML visualizations of color palettes with accessibility features and multiple layout options for design and development workflows.

Instructions

Generate interactive HTML visualizations of color palettes with accessibility features and multiple layout options

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • Main handler function that validates input parameters, processes color palette, generates interactive HTML visualization with accessibility features, and returns ToolResponse.
    async function createPaletteHtml(
      params: CreatePaletteHtmlParams
    ): Promise<ToolResponse | ErrorResponse> {
      const startTime = Date.now();
    
      try {
        // Validate parameters
        const { error, value } = createPaletteHtmlSchema.validate(params);
        if (error) {
          return {
            success: false,
            error: {
              code: 'INVALID_PARAMETERS',
              message: 'Invalid parameters provided',
              details: error.details,
              suggestions: [
                'Check that palette contains valid color strings',
                'Ensure layout is one of: horizontal, vertical, grid, circular, wave',
                'Verify custom_dimensions are provided when size is custom',
              ],
            },
            metadata: {
              execution_time: Date.now() - startTime,
              tool: 'create_palette_html',
              timestamp: new Date().toISOString(),
            },
          };
        }
    
        const validatedParams = value as CreatePaletteHtmlParams;
    
        // Parse and validate colors
        const colors: Array<{
          hex: string;
          rgb: string;
          hsl: string;
          name?: string;
          accessibility?: {
            contrastRatio: number;
            wcagAA: boolean;
            wcagAAA: boolean;
          };
        }> = [];
    
        const accessibilityNotes: string[] = [];
        const recommendations: string[] = [];
    
        for (let i = 0; i < validatedParams.palette.length; i++) {
          const colorInput = validatedParams.palette[i];
    
          if (!colorInput) {
            return {
              success: false,
              error: {
                code: 'INVALID_COLOR_FORMAT',
                message: `Color at index ${i} is undefined or null`,
                details: { index: i, color: colorInput },
                suggestions: [
                  'Ensure all palette entries are valid color strings',
                  'Check for undefined or null values in the palette array',
                ],
              },
              metadata: {
                execution_time: Date.now() - startTime,
                tool: 'create_palette_html',
                timestamp: new Date().toISOString(),
              },
            };
          }
    
          try {
            // Validate color format
            const colorValidation = validateColorInput(colorInput);
            if (!colorValidation.isValid) {
              return {
                success: false,
                error: {
                  code: 'INVALID_COLOR_FORMAT',
                  message: `Invalid color format at index ${i}: ${colorInput}`,
                  details: {
                    index: i,
                    color: colorInput,
                    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_palette_html',
                  timestamp: new Date().toISOString(),
                },
              };
            }
    
            let unifiedColor: UnifiedColor;
            try {
              unifiedColor = new UnifiedColor(colorInput);
            } catch (colorError) {
              throw new Error(
                `Failed to create UnifiedColor for "${colorInput}": ${colorError instanceof Error ? colorError.message : String(colorError)}`
              );
            }
    
            // Calculate accessibility information if requested
            let accessibility;
            if (validatedParams.accessibility_info) {
              // Calculate contrast against white and black backgrounds
              const whiteContrast = unifiedColor.getContrastRatio('#ffffff');
              const blackContrast = unifiedColor.getContrastRatio('#000000');
              const bestContrast = Math.max(whiteContrast, blackContrast);
    
              accessibility = {
                contrastRatio: bestContrast,
                wcagAA: bestContrast >= 4.5,
                wcagAAA: bestContrast >= 7.0,
              };
    
              // Add accessibility notes
              if (!accessibility.wcagAA) {
                accessibilityNotes.push(
                  `Color ${unifiedColor.hex} may not meet WCAG AA contrast requirements`
                );
              }
            }
    
            const colorName = unifiedColor.getName();
            colors.push({
              hex: unifiedColor.hex,
              rgb: unifiedColor.toFormat('rgb'),
              hsl: unifiedColor.toFormat('hsl'),
              ...(colorName && { name: colorName }),
              ...(accessibility && { accessibility }),
            });
          } catch (colorError) {
            return {
              success: false,
              error: {
                code: 'COLOR_PROCESSING_ERROR',
                message: `Failed to process color at index ${i}: ${colorInput}`,
                details: { index: i, color: colorInput, 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_palette_html',
                timestamp: new Date().toISOString(),
              },
            };
          }
        }
    
        // Generate recommendations
        if (colors.length > 10) {
          recommendations.push(
            'Consider using fewer colors for better visual clarity'
          );
        }
    
        if (validatedParams.layout === 'circular' && colors.length > 8) {
          recommendations.push('Circular layout works best with 8 or fewer colors');
        }
    
        if (validatedParams.accessibility_info) {
          const lowContrastColors = colors.filter(
            c => c.accessibility && !c.accessibility.wcagAA
          ).length;
          if (lowContrastColors > 0) {
            recommendations.push(
              `${lowContrastColors} colors may need contrast adjustment for accessibility`
            );
          }
        }
    
        // Prepare visualization data
        const options: HTMLGeneratorOptions = {
          ...(validatedParams.layout && { layout: validatedParams.layout }),
          ...(validatedParams.style && { style: validatedParams.style }),
          ...(validatedParams.size && { size: validatedParams.size }),
          ...(validatedParams.custom_dimensions && {
            customDimensions: validatedParams.custom_dimensions,
          }),
          ...(validatedParams.show_values !== undefined && {
            showValues: validatedParams.show_values,
          }),
          ...(validatedParams.show_names !== undefined && {
            showNames: validatedParams.show_names,
          }),
          ...(validatedParams.interactive !== undefined && {
            interactive: validatedParams.interactive,
          }),
          ...(validatedParams.export_formats && {
            exportFormats: validatedParams.export_formats,
          }),
          ...(validatedParams.accessibility_info !== undefined && {
            accessibilityInfo: validatedParams.accessibility_info,
          }),
          ...(validatedParams.theme && { theme: validatedParams.theme }),
        };
    
        const visualizationData: PaletteVisualizationData = {
          colors,
          options,
          metadata: {
            title: 'Color Palette Visualization',
            description: `Interactive color palette with ${colors.length} colors`,
            timestamp: new Date().toLocaleString(),
            colorCount: colors.length,
          },
        };
    
        // 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.generateEnhancedPaletteHTML(
            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> = {};
    
        if (validatedParams.export_formats?.includes('css')) {
          exportFormats['css'] = generateCSSExport(colors);
        }
    
        if (validatedParams.export_formats?.includes('json')) {
          exportFormats['json'] = {
            palette: colors.map(c => ({
              hex: c.hex,
              rgb: c.rgb,
              hsl: c.hsl,
              name: c.name,
            })),
            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_palette_html',
                  description: `Enhanced palette visualization with ${colors.length} 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: {
            colors: colors.map(c => ({
              hex: c.hex,
              rgb: c.rgb,
              hsl: c.hsl,
              name: c.name,
            })),
            layout: validatedParams.layout,
            color_count: colors.length,
            accessibility_compliant: validatedParams.accessibility_info
              ? colors.every(c => c.accessibility?.wcagAA)
              : undefined,
            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_palette_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',
            ],
            colorCount: colors.length,
          },
          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: `HTML visualization error: ${errorMessage}`,
            details: {
              errorMessage,
              errorStack,
              errorType: error?.constructor?.name || 'Unknown',
            },
            suggestions: [
              'Try with a smaller palette',
              'Verify all colors are in valid formats',
              'Check if the layout and style options are supported',
            ],
          },
          metadata: {
            execution_time: Date.now() - startTime,
            tool: 'create_palette_html',
            timestamp: new Date().toISOString(),
          },
        };
      }
    }
  • Joi validation schema defining input parameters for the create_palette_html tool.
    const createPaletteHtmlSchema = Joi.object({
      palette: Joi.array()
        .items(Joi.string().required())
        .min(1)
        .max(50)
        .required()
        .description('Array of colors in any supported format'),
    
      layout: Joi.string()
        .valid('horizontal', 'vertical', 'grid', 'circular', 'wave')
        .default('horizontal')
        .description('Layout style for the palette'),
    
      style: Joi.string()
        .valid('swatches', 'gradient', 'cards', 'minimal', 'detailed')
        .default('swatches')
        .description('Visual style of the palette'),
    
      size: Joi.string()
        .valid('small', 'medium', 'large', 'custom')
        .default('medium')
        .description('Size of color swatches'),
    
      custom_dimensions: Joi.array()
        .items(Joi.number().integer().min(50).max(2000))
        .length(2)
        .when('size', {
          is: 'custom',
          then: Joi.required(),
          otherwise: Joi.optional(),
        })
        .description('Custom dimensions [width, height] when size is custom'),
    
      show_values: Joi.boolean()
        .default(true)
        .description('Show color values on swatches'),
    
      show_names: Joi.boolean()
        .default(false)
        .description('Show color names if available'),
    
      interactive: Joi.boolean()
        .default(true)
        .description('Enable interactive features'),
    
      export_formats: Joi.array()
        .items(Joi.string().valid('hex', 'rgb', 'hsl', 'css', 'json'))
        .default(['hex', 'rgb', 'hsl'])
        .description('Available export formats'),
    
      accessibility_info: Joi.boolean()
        .default(false)
        .description('Show accessibility information'),
    
      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'),
    });
  • Tool registration/export defining the tool name, description, parameters schema, and handler reference.
    export const createPaletteHtmlTool: ToolHandler = {
      name: 'create_palette_html',
      description:
        'Generate interactive HTML visualizations of color palettes with accessibility features and multiple layout options',
      parameters: createPaletteHtmlSchema.describe(),
      handler: async (params: unknown) =>
        createPaletteHtml(params as CreatePaletteHtmlParams),
    };
  • Helper function to generate CSS export from processed colors.
    function generateCSSExport(
      colors: Array<{ hex: string; rgb: string; hsl: string; name?: string }>
    ): string {
      let css = ':root {\n';
      colors.forEach((color, index) => {
        const name = color.name
          ? color.name.toLowerCase().replace(/\s+/g, '-')
          : `color-${index + 1}`;
        css += `  --${name}: ${color.hex.toLowerCase()};\n`;
        css += `  --${name}-rgb: ${color.rgb};\n`;
        css += `  --${name}-hsl: ${color.hsl};\n`;
      });
      css += '}';
      return css;
    }
  • TypeScript interface defining the shape of input parameters.
    interface CreatePaletteHtmlParams {
      palette: string[];
      layout?: 'horizontal' | 'vertical' | 'grid' | 'circular' | 'wave';
      style?: 'swatches' | 'gradient' | 'cards' | 'minimal' | 'detailed';
      size?: 'small' | 'medium' | 'large' | 'custom';
      custom_dimensions?: [number, number];
      show_values?: boolean;
      show_names?: boolean;
      interactive?: boolean;
      export_formats?: string[];
      accessibility_info?: boolean;
      theme?: 'light' | 'dark' | 'auto';
      enable_background_controls?: boolean;
      enable_accessibility_testing?: boolean;
      include_keyboard_help?: boolean;
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It mentions 'interactive HTML visualizations' and 'accessibility features,' but fails to detail critical behaviors like output format (e.g., HTML string or file), error handling, performance characteristics, or any side effects. This leaves significant gaps for a tool with 15 parameters and complex functionality.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, well-structured sentence that efficiently conveys the core purpose and key features without unnecessary words. It is front-loaded with the main action and resource, making it easy to parse and understand quickly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (15 parameters, no annotations, no output schema), the description is insufficient. It omits details on output (e.g., HTML string, file path), behavioral traits (e.g., interactivity implementation, error handling), and usage scenarios, leaving the agent under-informed for effective tool invocation in a rich sibling tool environment.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description adds no parameter-specific information beyond what the input schema provides, which has 100% schema description coverage. It mentions 'multiple layout options' and 'accessibility features,' hinting at parameters like layout and accessibility_info, but offers no additional syntax, format details, or usage context. The baseline score of 3 reflects adequate schema coverage without description enhancement.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('Generate interactive HTML visualizations') and resource ('color palettes'), with additional features ('accessibility features and multiple layout options') that distinguish it from sibling tools like create_palette_png or create_color_wheel_html, which produce different output formats or visualizations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides no guidance on when to use this tool versus alternatives, such as create_palette_png for static images or create_gradient_html for gradient visualizations. It lacks explicit context, prerequisites, or exclusions, leaving the agent to infer usage from the tool name and parameters alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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