Manipulation
These functions change one color. They never convert it: the result keeps the input's space and
alpha, so plt_lighten(plt_hsl(...), 0.2) is still an hsl value. Each operation is only defined
for the spaces that have the component it acts on — an RGB space has no hue to rotate, and HSL has
no a/b axes — so the supported-space list differs per function.
A space that does not support the operation raises a query error that says which function failed and suggests converting first:
SELECT plt_saturate(plt_srgb(1, 0, 0), 0.2);
The fix is one plt_convert away:
SELECT plt_to_hex(plt_saturate(plt_convert(plt_srgb(1, 0, 0), 'hsl'), 0.2)) AS saturated;
Mixing
plt_mix(a, b, factor)
Signature: plt_mix(a plt_color, b plt_color, factor DOUBLE) -> plt_color
Linear interpolation in a's space: factor 0 gives a, 1 gives b, 0.5 the midpoint.
factor is clamped to 0..1. b is converted into a's space first, and alpha is interpolated
along with the components. Mixing is defined in all 44 spaces, including the hue spaces:
SELECT plt_to_hex(plt_mix(plt_srgb(1, 0, 0), plt_srgb(0, 0, 1), 0.5)) AS srgb_mid,
plt_to_hex(plt_mix(plt_convert(plt_srgb(1, 0, 0), 'oklab'),
plt_convert(plt_srgb(0, 0, 1), 'oklab'),
0.5)) AS oklab_mid;
SELECT plt_mix(plt_with_alpha(plt_srgb(1, 0, 0), 0),
plt_with_alpha(plt_srgb(1, 0, 0), 1),
0.25) AS quarter_alpha;
Lighten and darken
Both variants keep the space. The proportional form (plt_lighten, plt_darken) scales the
lightness towards the space's maximum or minimum; the fixed form (plt_lighten_fixed,
plt_darken_fixed) moves it by an absolute amount. Both take a value in 0..1; a value of 0 leaves
the color unchanged.
Supported spaces for all four: all 15 RGB variants, hsl, hsv, hwb, hsluv, lab, lch,
luv, lchuv, xyz, xyz_d50, yxy, luma, luma_linear, luma_gamma, oklab, oklch,
okhsl, okhsv, okhwb, cam16_ucs_jab and cam16_ucs_jmh.
plt_lighten(color, factor)
Signature: plt_lighten(color plt_color, factor DOUBLE) -> plt_color
SELECT plt_to_hex(plt_lighten(plt_srgb(1, 0, 0), 0.2)) AS lighter,
plt_to_hex(plt_lighten(plt_hsl(0, 1, 0.4), 0.2)) AS lighter_hsl,
plt_components(plt_lighten(plt_oklch(0.5, 0.1, 30), 0.2)) AS lighter_oklch;
plt_lighten_fixed(color, amount)
Signature: plt_lighten_fixed(color plt_color, amount DOUBLE) -> plt_color
SELECT plt_components(plt_lighten_fixed(plt_lab(50, 20, -30), 0.1)) AS raised_lab,
plt_to_hex(plt_lighten_fixed(plt_hsl(0, 1, 0.4), 0.2)) AS raised_hsl;
plt_darken(color, factor)
Signature: plt_darken(color plt_color, factor DOUBLE) -> plt_color
SELECT plt_to_hex(plt_darken(plt_srgb(1, 0, 0), 0.2)) AS darker,
plt_to_hex(plt_darken(plt_hsv(0, 1, 0.6), 0.3)) AS darker_hsv;
plt_darken_fixed(color, amount)
Signature: plt_darken_fixed(color plt_color, amount DOUBLE) -> plt_color
SELECT plt_components(plt_darken_fixed(plt_lab(50, 20, -30), 0.1)) AS lowered_lab;
plt_brighten(color, amount)
Signature: plt_brighten(color plt_color, amount DOUBLE) -> plt_color
Adds amount to every sRGB channel — a fraction of the full 0..1 range, not of the lightness — and
clamps at 1. This is tinycolor's brighten on the extension's 0..1 scale; plt_lighten scales the
space's own lightness instead. Every space is accepted, and the result keeps the input's space and
alpha.
SELECT plt_to_hex(plt_brighten(plt_srgb(0.2, 0.2, 0.2), 0.1)) AS brighter,
plt_to_hex(plt_brighten(plt_lab(50, 20, 30), 0.1)) AS brighter_lab,
plt_to_hex(plt_brighten(plt_srgb(0.9, 0.9, 0.9), 0.5)) AS clipped;
Grey, tint and shade
Three one-liners for the usual "make it grey / lighter / darker" requests. All of them accept every space and keep the input's space and alpha.
plt_greyscale(color)
Signature: plt_greyscale(color plt_color) -> plt_color
Drops the HSL saturation to zero, so the grey keeps the color's HSL lightness. This is the same
result as plt_desaturate on an HSL color, without having to convert.
SELECT plt_to_hex(plt_greyscale(plt_srgb(1, 0, 0))) AS red_grey,
plt_to_hex(plt_greyscale(plt_srgb(0.2, 0.6, 0.9))) AS blue_grey;
plt_tint(color, amount)
Signature: plt_tint(color plt_color, amount DOUBLE) -> plt_color
Mixes towards white in sRGB: 0 keeps the color, 1 makes it white. amount is clamped to 0..1.
SELECT plt_to_hex(plt_tint(plt_srgb(1, 0, 0), 0.25)) AS quarter,
plt_to_hex(plt_tint(plt_srgb(1, 0, 0), 0.5)) AS half,
plt_to_hex(plt_tint(plt_srgb(1, 0, 0), 1)) AS white;
plt_shade(color, amount)
Signature: plt_shade(color plt_color, amount DOUBLE) -> plt_color
Mixes towards black in sRGB: 0 keeps the color, 1 makes it black.
SELECT plt_to_hex(plt_shade(plt_srgb(1, 0, 0), 0.25)) AS quarter,
plt_to_hex(plt_shade(plt_srgb(1, 0, 0), 0.5)) AS half,
plt_to_hex(plt_shade(plt_srgb(1, 0, 0), 1)) AS black;
Saturation
The proportional form scales saturation or chroma towards the space's maximum
(plt_saturate) or minimum (plt_desaturate); the fixed form adds or subtracts an absolute
amount. The parameter is in 0..1 for both forms.
Supported spaces: hsl, hsv, hsluv, lch, lchuv, okhsl, okhsv and cam16_ucs_jmh.
oklch itself is not in that list — convert to lch when you want to scale CIE chroma, or stay in
okhsl / okhsv when you want to scale perceptual saturation.
plt_saturate(color, factor)
Signature: plt_saturate(color plt_color, factor DOUBLE) -> plt_color
SELECT plt_to_hex(plt_saturate(plt_hsl(0, 0.5, 0.5), 0.5)) AS more_saturated,
plt_components(plt_saturate(plt_lch(50, 20, 40), 0.5)) AS more_chroma;
plt_saturate_fixed(color, amount)
Signature: plt_saturate_fixed(color plt_color, amount DOUBLE) -> plt_color
SELECT plt_components(plt_saturate_fixed(plt_hsl(0, 0.4, 0.5), 0.2)) AS fixed_hsl,
plt_components(plt_saturate_fixed(plt_okhsl(0, 0.4, 0.5), 0.2)) AS fixed_okhsl;
plt_desaturate(color, factor)
Signature: plt_desaturate(color plt_color, factor DOUBLE) -> plt_color
SELECT plt_to_hex(plt_desaturate(plt_hsl(0, 0.8, 0.5), 0.5)) AS muted,
plt_to_hex(plt_desaturate(plt_convert(plt_srgb(1, 0, 0), 'hsl'), 1)) AS gray;
plt_desaturate_fixed(color, amount)
Signature: plt_desaturate_fixed(color plt_color, amount DOUBLE) -> plt_color
SELECT plt_components(plt_desaturate_fixed(plt_hsl(0, 0.8, 0.5), 0.3)) AS less_saturated;
Hue
plt_shift_hue(color, degrees)
Signature: plt_shift_hue(color plt_color, degrees DOUBLE) -> plt_color
Rotates the hue by any real number of degrees; the result wraps into 0..360.
SELECT plt_to_hex(plt_shift_hue(plt_hsl(120, 1, 0.5), 120)) AS shifted,
plt_to_hex(plt_shift_hue(plt_convert(plt_srgb(1, 0, 0), 'oklch'), -60)) AS backwards;
plt_with_hue(color, degrees)
Signature: plt_with_hue(color plt_color, degrees DOUBLE) -> plt_color
Sets the hue instead of adding to it.
SELECT plt_to_hex(plt_with_hue(plt_hsl(120, 1, 0.5), 240)) AS blue,
plt_components(plt_with_hue(plt_oklch(0.6, 0.1, 30), 200)) AS set_oklch;
plt_hue(color)
Signature: plt_hue(color plt_color) -> DOUBLE
The hue in degrees, 0..360. A gray color reports 0. This works in more spaces than the hue
mutators: every hue space, every RGB space, plus lab, luv and oklab, where the hue is the
angle of the a/b or u/v pair.
SELECT plt_hue(plt_srgb(1, 0, 0)) AS red,
plt_hue(plt_oklab(0.5, 0.1, 0.1)) AS oklab_angle,
plt_hue(plt_srgb(0.5, 0.5, 0.5)) AS gray;
Not every space has a hue; luma, xyz, lms and friends are rejected:
SELECT plt_hue(plt_luma(0.5));
Premultiplied alpha
plt_premultiply(color)
Signature: plt_premultiply(color plt_color) -> plt_color
Multiplies the components by alpha; alpha itself is unchanged. Alpha must be in 0..1.
SELECT plt_premultiply(plt_with_alpha(plt_srgb(1, 0.5, 0.25), 0.5)) AS premultiplied;
plt_unpremultiply(color)
Signature: plt_unpremultiply(color plt_color) -> plt_color
Divides the components by alpha. With alpha 0 the components come back as 0, which is palette's definition rather than an error.
SELECT plt_unpremultiply(plt_premultiply(plt_with_alpha(plt_srgb(1, 0.5, 0.25), 0.5))) AS round_trip,
plt_unpremultiply(plt_with_alpha(plt_srgb(1, 0.5, 0.25), 0)) AS zero_alpha;
Supported spaces for both: all 15 RGB variants, lab, luv, xyz, xyz_d50, yxy, luma,
luma_linear, luma_gamma, oklab, cam16_ucs_jab, lms and lms_von_kries.
SELECT plt_premultiply(plt_with_alpha(plt_srgb(1, 0, 0), 1.5));
SELECT plt_premultiply(plt_hsl(120, 0.5, 0.5));