π§Color Palette Generator
Generate beautiful color palettes with AI. Create harmonious color schemes from images, color theory, or random generation. Perfect for designers, artists, and developers.
π€ What Is a Color Palette Generator?
Think of a fashion stylist who always knows which colors look perfect together - that's a Color Palette Generator! It creates harmonious color schemes based on color theory, your images, or inspiration, giving designers and creatives perfectly matched colors for any project.
π² Random Generator
π¨ Color Wheel
πΈ From Image
π Gradient
Color Harmony Type
Drop an image here or click to upload
JPG, PNG, GIF up to 10MB
/* CSS will appear here */
π¨ Generated Color Palette
Generate a palette using one of the methods above
βΏ Accessibility Check
π€ Export Palette
Sample Text
${ratio.toFixed(2)}:1
${statusText}
`;
container.appendChild(contrastPair);
}
}
}
// Calculate contrast ratio
function calculateContrastRatio(color1, color2) {
const l1 = getRelativeLuminance(color1.r, color1.g, color1.b);
const l2 = getRelativeLuminance(color2.r, color2.g, color2.b);
const lighter = Math.max(l1, l2);
const darker = Math.min(l1, l2);
return (lighter + 0.05) / (darker + 0.05);
}
// Get relative luminance
function getRelativeLuminance(r, g, b) {
const [rs, gs, bs] = [r, g, b].map(c => {
c = c / 255;
return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
});
return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
}
// Export palette
function exportPalette(format) {
if (currentPalette.length === 0) {
showNotification('Generate a palette first', 'error');
return;
}
let content = '';
let filename = `palette-${Date.now()}`;
let mimeType = 'text/plain';
switch (format) {
case 'css':
content = generateCSSVariables();
filename += '.css';
mimeType = 'text/css';
break;
case 'scss':
content = generateSCSSVariables();
filename += '.scss';
mimeType = 'text/scss';
break;
case 'json':
content = generateJSONExport();
filename += '.json';
mimeType = 'application/json';
break;
case 'png':
exportAsPNG();
trackEvent('palette_exported', { format: 'png' });
return;
case 'ase':
showNotification('ASE export coming soon!', 'warning');
return;
case 'sketch':
showNotification('Sketch export coming soon!', 'warning');
return;
}
downloadFile(content, filename, mimeType);
trackEvent('palette_exported', { format });
}
// Generate CSS variables
function generateCSSVariables() {
let css = ':root {\n';
currentPalette.forEach((color, index) => {
css += ` --color-${index + 1}: ${color.hex};\n`;
css += ` --color-${index + 1}-rgb: ${color.r}, ${color.g}, ${color.b};\n`;
});
css += '}';
return css;
}
// Generate SCSS variables
function generateSCSSVariables() {
let scss = '';
currentPalette.forEach((color, index) => {
scss += `$color-${index + 1}: ${color.hex};\n`;
scss += `$color-${index + 1}-rgb: ${color.r}, ${color.g}, ${color.b};\n`;
});
return scss;
}
// Generate JSON export
function generateJSONExport() {
const data = {
palette: currentPalette.map((color, index) => ({
name: `color-${index + 1}`,
hex: color.hex,
rgb: [color.r, color.g, color.b],
hsl: color.hsl || ColorTheory.rgbToHsl(color.r, color.g, color.b)
})),
timestamp: new Date().toISOString()
};
return JSON.stringify(data, null, 2);
}
// Export as PNG
function exportAsPNG() {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 800;
canvas.height = 200;
const swatchWidth = canvas.width / currentPalette.length;
currentPalette.forEach((color, index) => {
ctx.fillStyle = color.hex;
ctx.fillRect(index * swatchWidth, 0, swatchWidth, canvas.height);
// Add color code text
ctx.fillStyle = getContrastColor(color);
ctx.font = '16px Arial';
ctx.textAlign = 'center';
ctx.fillText(color.hex, (index + 0.5) * swatchWidth, canvas.height / 2);
});
canvas.toBlob(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `palette-${Date.now()}.png`;
a.click();
URL.revokeObjectURL(url);
showNotification('Palette exported as PNG!', 'success');
});
}
// Get contrast color for text
function getContrastColor(color) {
const luminance = getRelativeLuminance(color.r, color.g, color.b);
return luminance > 0.5 ? '#000000' : '#ffffff';
}
// Download file
function downloadFile(content, filename, mimeType) {
const blob = new Blob([content], { type: mimeType });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
a.click();
URL.revokeObjectURL(url);
showNotification(`Exported as ${filename}!`, 'success');
}
// ========== UTILITY FUNCTIONS ==========
function showNotification(message, type = 'success') {
const toast = document.createElement('div');
toast.className = `toast ${type}`;
toast.textContent = message;
document.body.appendChild(toast);
setTimeout(() => toast.remove(), 3000);
}
function showOTA() {
const otaContainer = document.getElementById('otaContainer');
if (otaContainer && (otaContainer.style.display === 'none' || !otaContainer.style.display)) {
otaContainer.style.display = 'block';
}
}
function trackEvent(eventName, data = {}) {
if (typeof gtag !== 'undefined') {
gtag('event', eventName, {
'event_category': TOOL_CONFIG.category,
'event_label': TOOL_CONFIG.name,
...data
});
}
}
// ========== AI ASSISTANT FUNCTIONS ==========
function openAIModal() {
document.getElementById('aiModal').classList.add('show');
}
function closeAIModal() {
document.getElementById('aiModal').classList.remove('show');
}
function selectAI(aiType) {
const context = `I'm using a Color Palette Generator tool. I need help with color theory, design harmony, or creative color combinations.`;
let url;
switch(aiType) {
case 'chatgpt':
url = `https://chat.openai.com/?q=${encodeURIComponent(context)}`;
break;
case 'claude':
url = `https://claude.ai/chat?q=${encodeURIComponent(context)}`;
break;
case 'gemini':
url = `https://gemini.google.com/?q=${encodeURIComponent(context)}`;
break;
}
window.open(url, '_blank');
closeAIModal();
trackEvent('ai_selection', { ai_type: aiType });
}
// ========== EVENT LISTENERS ==========
document.addEventListener('DOMContentLoaded', function() {
// Tab switching
document.querySelectorAll('.generation-tab').forEach(tab => {
tab.addEventListener('click', function() {
const tabId = this.dataset.tab;
document.querySelectorAll('.generation-tab').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.generation-content').forEach(c => c.classList.remove('active'));
this.classList.add('active');
document.getElementById(`${tabId}-content`).classList.add('active');
});
});
// Color wheel interaction
const colorWheel = document.getElementById('colorWheel');
const pickerDot = document.getElementById('pickerDot');
colorWheel.addEventListener('click', function(e) {
const rect = this.getBoundingClientRect();
const centerX = rect.width / 2;
const centerY = rect.height / 2;
const x = e.clientX - rect.left - centerX;
const y = e.clientY - rect.top - centerY;
const angle = Math.atan2(y, x) * 180 / Math.PI;
selectedHue = (angle + 360) % 360;
const radius = Math.min(centerX, centerY) - 10;
const dotX = centerX + Math.cos(angle * Math.PI / 180) * radius;
const dotY = centerY + Math.sin(angle * Math.PI / 180) * radius;
pickerDot.style.left = dotX + 'px';
pickerDot.style.top = dotY + 'px';
pickerDot.style.backgroundColor = `hsl(${selectedHue}, 100%, 50%)`;
});
// Harmony button selection
document.querySelectorAll('.harmony-btn').forEach(btn => {
btn.addEventListener('click', function() {
document.querySelectorAll('.harmony-btn').forEach(b => b.classList.remove('active'));
this.classList.add('active');
});
});
// Image upload
const imageUpload = document.getElementById('imageUpload');
const imageInput = document.getElementById('imageInput');
const uploadedImage = document.getElementById('uploadedImage');
const extractBtn = document.getElementById('extractColorsBtn');
imageUpload.addEventListener('click', () => imageInput.click());
imageUpload.addEventListener('dragover', e => {
e.preventDefault();
imageUpload.classList.add('drag-over');
});
imageUpload.addEventListener('dragleave', () => {
imageUpload.classList.remove('drag-over');
});
imageUpload.addEventListener('drop', e => {
e.preventDefault();
imageUpload.classList.remove('drag-over');
const files = e.dataTransfer.files;
if (files.length > 0) {
handleImageUpload(files[0]);
}
});
imageInput.addEventListener('change', e => {
if (e.target.files.length > 0) {
handleImageUpload(e.target.files[0]);
}
});
function handleImageUpload(file) {
if (!file.type.startsWith('image/')) {
showNotification('Please upload an image file', 'error');
return;
}
const reader = new FileReader();
reader.onload = e => {
uploadedImage.src = e.target.result;
uploadedImage.classList.remove('hidden');
extractBtn.classList.remove('hidden');
imageUpload.style.display = 'none';
};
reader.readAsDataURL(file);
}
// AI modal events
document.getElementById('aiBtn').addEventListener('click', openAIModal);
document.getElementById('aiModal').addEventListener('click', e => {
if (e.target === e.currentTarget) closeAIModal();
});
document.addEventListener('keydown', e => {
if (e.key === 'Escape') closeAIModal();
});
// Initialize
updateCurrentYear();
updateToolCount();
trackEvent('page_view', { tool: TOOL_CONFIG.name, category: TOOL_CONFIG.category });
// Generate initial random palette
generateRandomPalette();
});
// ========== DYNAMIC TOOL COUNT ==========
async function updateToolCount() {
try {
const response = await fetch('/api/tool-count.php');
const data = await response.json();
document.querySelectorAll('.dynamic-tools-count').forEach(el => {
el.textContent = `${data.count}+ free online tools in 211 languages. No signup, no fees, just tools that work.`;
});
document.querySelectorAll('.dynamic-count').forEach(el => {
const prefix = el.getAttribute('data-text') || '';
const suffix = el.getAttribute('data-suffix') || '';
const icon = el.textContent.split(' ')[0] || '';
el.textContent = `${icon} ${prefix} ${data.count}+ ${suffix}`;
});
} catch (error) {
const fallbackCount = 333;
document.querySelectorAll('.dynamic-tools-count').forEach(el => {
el.textContent = `${fallbackCount}+ free online tools in 211 languages. No signup, no fees, just tools that work.`;
});
document.querySelectorAll('.dynamic-count').forEach(el => {
const prefix = el.getAttribute('data-text') || '';
const suffix = el.getAttribute('data-suffix') || '';
const icon = el.textContent.split(' ')[0] || '';
el.textContent = `${icon} ${prefix} ${fallbackCount}+ ${suffix}`;
});
}
}
function updateCurrentYear() {
const currentYear = new Date().getFullYear();
document.querySelectorAll('.current-year').forEach(el => {
el.textContent = currentYear;
});
}
// ========== ANALYTICS ==========
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXX');