Color Composition

Turn individual colors into palettes, harmonies, gradients, and complete themes.

Repair palette harmony

Align an existing palette to a chosen hue relationship while preserving lightness, chroma, alpha, names, and order.

Explore Palette repair

Detect palette harmony

Compare palette hue angles with named harmony patterns and inspect the heuristic confidence score.

Explore Harmony detection
<?php

use PhpColor\Color\Color;
use PhpColor\Color\Palette\Harmony\HarmonyDetector;
use PhpColor\Color\Palette\Harmony\HarmonyGenerator;
use PhpColor\Color\Palette\Harmony\HarmonyPattern;

$palette = (new HarmonyGenerator())->generate(
    Color::parse('oklch(0.68 0.14 30)'),
    HarmonyPattern::Triadic,
);
$result = (new HarmonyDetector())->detect($palette);
use PhpColor\Color\Color; use PhpColor\Color\Palette\Harmony\HarmonyDetector; use PhpColor\Color\Palette\Harmony\HarmonyGenerator; use PhpColor\Color\Palette\Harmony\HarmonyPattern; $palette = (new HarmonyGenerator())->generate( Color::parse('oklch(0.68 0.14 30)'), HarmonyPattern::Triadic, ); $result = (new HarmonyDetector())->detect($palette);

Repair palette contrast

Adjust failing palette colors against one background while retaining names and order.

Explore Palette contrast
<?php

use PhpColor\Color\Palette\ColorPalette;
use PhpColor\Color\Palette\Fixer\ContrastFixer;

$palette = ColorPalette::parse([
    'primary' => '#3b82f6',
    'muted' => '#64748b',
]);
$fixed = (new ContrastFixer())->fix($palette, [
    'background_color' => '#ffffff',
    'min_contrast' => 4.5,
]);
use PhpColor\Color\Palette\ColorPalette; use PhpColor\Color\Palette\Fixer\ContrastFixer; $palette = ColorPalette::parse([ 'primary' => '#3b82f6', 'muted' => '#64748b', ]); $fixed = (new ContrastFixer())->fix($palette, [ 'background_color' => '#ffffff', 'min_contrast' => 4.5, ]);

Find the nearest palette color

Select the palette entry with the shortest implemented Oklab distance to a target color.

Explore Nearest color
<?php

use PhpColor\Color\Color;
use PhpColor\Color\Palette\ColorPalette;

$palette = ColorPalette::parse([
    'ink' => '#111827',
    'muted' => '#64748b',
    'accent' => '#7c3aed',
]);
$closest = $palette->closest(Color::parse('#6d45c4'));
use PhpColor\Color\Color; use PhpColor\Color\Palette\ColorPalette; $palette = ColorPalette::parse([ 'ink' => '#111827', 'muted' => '#64748b', 'accent' => '#7c3aed', ]); $closest = $palette->closest(Color::parse('#6d45c4'));

Filter a color palette

Keep palette entries that match an explicit predicate without losing their keys or order.

Explore Filtering
<?php

use PhpColor\Color\Palette\ColorPalette;

$palette = ColorPalette::parse([
    'ink' => '#111827',
    'paper' => '#f8fafc',
    'accent' => '#7c3aed',
]);
$dark = $palette->filter(
    static fn ($color): bool => $color->isDark(),
);
use PhpColor\Color\Palette\ColorPalette; $palette = ColorPalette::parse([ 'ink' => '#111827', 'paper' => '#f8fafc', 'accent' => '#7c3aed', ]); $dark = $palette->filter( static fn ($color): bool => $color->isDark(), );

Merge color palettes

Append two unnamed palettes into one ordered collection with an explicit named-palette boundary.

Explore Merging
<?php

use PhpColor\Color\Palette\ColorPalette;

$dark = ColorPalette::parse(['#111827', '#475569']);
$light = ColorPalette::parse(['#f8fafc']);
$merged = $dark->merge($light);
use PhpColor\Color\Palette\ColorPalette; $dark = ColorPalette::parse(['#111827', '#475569']); $light = ColorPalette::parse(['#f8fafc']); $merged = $dark->merge($light);

Convert a complete palette

Convert every palette entry to one color space while preserving names and order.

Explore Conversion
<?php

use PhpColor\Color\Palette\ColorPalette;

$palette = ColorPalette::parse([
    'ink' => '#111827',
    'paper' => '#f8fafc',
    'accent' => '#7c3aed',
]);
$oklch = $palette->to('oklch');
use PhpColor\Color\Palette\ColorPalette; $palette = ColorPalette::parse([ 'ink' => '#111827', 'paper' => '#f8fafc', 'accent' => '#7c3aed', ]); $oklch = $palette->to('oklch');

Transform a complete palette

Apply one immutable color operation to every palette entry while preserving names and order.

Explore Palette transformation
<?php

use PhpColor\Color\Palette\ColorPalette;

$palette = ColorPalette::parse([
    'primary' => '#7c3aed',
    'secondary' => '#0ea5e9',
    'accent' => '#f59e0b',
]);
$shifted = $palette->rotateHue(24.0);
use PhpColor\Color\Palette\ColorPalette; $palette = ColorPalette::parse([ 'primary' => '#7c3aed', 'secondary' => '#0ea5e9', 'accent' => '#f59e0b', ]); $shifted = $palette->rotateHue(24.0);

Reorder a color palette

Reverse or select an ordered range from an unnamed palette without changing its colors.

Explore Reordering
<?php

use PhpColor\Color\Palette\ColorPalette;

$palette = ColorPalette::parse([
    '#111827', '#475569', '#f8fafc',
]);
$reversed = $palette->reverse();
$middle = $palette->slice(1, 2);
use PhpColor\Color\Palette\ColorPalette; $palette = ColorPalette::parse([ '#111827', '#475569', '#f8fafc', ]); $reversed = $palette->reverse(); $middle = $palette->slice(1, 2);

Build named color palettes

Keep application color names attached while transforming and exporting the complete collection.

Explore Palettes

Build controlled color scales

Generate an exact number of ordered lightness steps from one source color and an explicit range.

Explore Scales

Interpolate a color palette

Generate an exact number of colors between two endpoints in a declared interpolation space.

Explore Palette interpolation
<?php

use PhpColor\Color\Color;
use PhpColor\Color\Palette\ColorPalette;

$palette = ColorPalette::interpolate(
    Color::parse('#7c3aed'),
    Color::parse('#f59e0b'),
    steps: 7,
    space: 'oklab',
);
use PhpColor\Color\Color; use PhpColor\Color\Palette\ColorPalette; $palette = ColorPalette::interpolate( Color::parse('#7c3aed'), Color::parse('#f59e0b'), steps: 7, space: 'oklab', );

Sample a color scale

Read a color at any normalized position by interpolating between neighboring palette entries.

Explore Scale sampling
<?php

use PhpColor\Color\Palette\ColorPalette;

$scale = ColorPalette::parse([
    '#111827', '#7c3aed', '#f8fafc',
]);
$sample = $scale->at(0.2);
use PhpColor\Color\Palette\ColorPalette; $scale = ColorPalette::parse([ '#111827', '#7c3aed', '#f8fafc', ]); $sample = $scale->at(0.2);

Generate color harmonies

Derive a named hue relationship from one anchor without calculating each rotation yourself.

Explore Harmonies

Build and sample gradients

Compose linear, radial, and conic gradients with explicit interpolation.

Explore Gradients

Derive a dark-mode palette

Transform a named light palette into a dark counterpart while keeping its keys aligned.

Explore Dark mode

Derive a light-mode palette

Transform a named dark palette into a light counterpart while retaining role keys and order.

Explore Light mode
<?php

use PhpColor\Color\Palette\ColorPalette;
use PhpColor\Color\Palette\Transformer\LightModeColorPaletteTransformer;

$dark = ColorPalette::parse([
    'background' => '#0b0c0e',
    'text' => '#c0cde7',
    'accent' => '#4f88fc',
]);
$light = (new LightModeColorPaletteTransformer())
    ->transform($dark);
use PhpColor\Color\Palette\ColorPalette; use PhpColor\Color\Palette\Transformer\LightModeColorPaletteTransformer; $dark = ColorPalette::parse([ 'background' => '#0b0c0e', 'text' => '#c0cde7', 'accent' => '#4f88fc', ]); $light = (new LightModeColorPaletteTransformer()) ->transform($dark);

Keep building

Grow one color into a complete system