Interpolate two colors in HSL
Blend two colors by moving through HSL instead of averaging their red, green, and blue channels.
Run — free
Supply two hexadecimal colors and a fraction from zero through one, and this capability returns the point between them as normalized hex, RGB, and HSL values. Hue travels around the shorter side of the color wheel, including a fixed rule for exact half-turn ties, so the same request always produces the same result. Strict validation makes it suitable for design tools, token pipelines, animation keyframes, and repeatable tests.
How shortest-path HSL interpolation works
Each input begins as a three- or six-digit hexadecimal color, with or without a leading hash. The solver expands shorthand, normalizes letter case, converts the integer sRGB channels to HSL, and then treats hue as an angle rather than an ordinary linear number. That distinction matters near the boundary of the color wheel. A blend from 350 degrees to 10 degrees should travel twenty degrees through red, not sweep the long way through most other hues. The signed difference is therefore normalized into the half-open interval from minus 180 degrees through, but not including, plus 180 degrees. An exact 180-degree tie always takes the negative direction, making an otherwise ambiguous choice deterministic. Saturation and lightness are interpolated directly with the same fraction. The resulting HSL color is converted back to rounded integer RGB channels and a lowercase six-digit hex string. Reported HSL components and the signed hue delta are rounded to six decimal places to keep JSON stable while preserving useful precision. No network, random value, clock, or mutable state participates in the calculation.
Choose the fraction and interpret the response
Set t to zero to receive the starting color, one to receive the ending color, or a decimal between them for an intermediate point. A value of 0.25 moves one quarter of the way along every interpolated HSL component, while 0.5 selects the midpoint. The response echoes both normalized endpoint colors and the exact fraction, then provides hex, an rgb object with integer r, g, and b channels, and an hsl object whose h is in degrees and whose s and l are percentages. The hue_delta field exposes the complete signed angular journey selected before scaling by t. Its companion hue_path is increasing, decreasing, or none, which is useful when debugging gradients that cross zero degrees or when reproducing the path in another renderer. Grayscale endpoints have the conventional computed hue of zero because an achromatic RGB color has no visually defined hue. Interpolation remains deterministic in that case, but remember that introducing saturation between gray and a chromatic endpoint can reveal the conventional hue used for the gray endpoint. Send numeric JSON for t rather than a quoted number.
Use it safely in design and production workflows
This operation fits anywhere a system needs one reproducible color between two known stops. A theme builder can generate hover, pressed, or transitional tokens without bundling a color library. A chart service can request evenly spaced samples by calling the capability with fractions such as 0, 0.25, 0.5, 0.75, and 1. An animation pipeline can calculate keyframes whose hue does not unexpectedly traverse the long arc across green or blue. It is also practical for regression fixtures because normalized input and bounded rounding make output straightforward to compare. The endpoint deliberately accepts only hexadecimal RGB colors; alpha channels, CSS color names, rgb() strings, HSL strings, and wide-gamut color spaces are outside this focused contract. Invalid color lengths, non-hexadecimal characters, missing fields, non-finite fractions, and fractions outside zero through one fail validation. Successful API execution costs $0.002 per item, while the browser implementation uses the same pure solver. HSL interpolation is a mathematical convenience rather than a perceptually uniform blend, so choose a LAB-oriented tool when equal-looking visual steps matter more than familiar CSS-style hue behavior.
What you can do with it
Generate theme states
Create deterministic intermediate colors for hover, focus, active, and selected design tokens.
Build compact gradient samples
Evaluate a sequence of fractions to produce HSL-based stops that follow the shorter hue arc.
Create animation keyframes
Calculate stable color keyframes without accidental long rotations around the hue wheel.
FAQ
What does t mean?
t is the interpolation fraction: 0 returns the first color, 1 returns the second, and values between them return intermediate colors.
How is the hue direction selected?
Hue follows the shortest circular difference. If both directions are exactly 180 degrees, the decreasing direction is selected consistently.
Which color formats are accepted?
The two inputs accept three- or six-digit hexadecimal RGB colors, with an optional leading hash. Alpha, names, and CSS function strings are rejected.
Why can HSL blending differ from RGB blending?
HSL interpolates hue, saturation, and lightness, while RGB blending averages channel intensities. Their intermediate colors therefore follow different paths.
What does an API call cost?
A successful API call costs $0.002 per item. The same deterministic solver can run in the browser.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/color/interpolate-hsl \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"color1":"#ff0000","color2":"#0000ff","t":0.5}'const res = await fetch("https://api.kit.forhosting.com/color/interpolate-hsl", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"color1": "#ff0000",
"color2": "#0000ff",
"t": 0.5
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/color/interpolate-hsl",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"color1": "#ff0000",
"color2": "#0000ff",
"t": 0.5
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/color/interpolate-hsl", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"color1":"#ff0000","color2":"#0000ff","t":0.5}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"color1":"#ff0000","color2":"#0000ff","t":0.5}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/color/interpolate-hsl", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"color1": "#ff0000",
"color2": "#0000ff",
"t": 0.5
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "color.interpolate_hsl",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |