Cubic-bezier color interpolation
Know the exact color a transition shows at any moment of an eased curve: halfway from #ff6600 to #3366ff with the ease-in-out curve 0.42, 0, 0.58, 1 gives #996680. No animation has to play. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Color1
- #ff6600
- Color2
- #3366ff
- T
- 0.5
- X1
- 0.42
- Y1
- 0
- X2
- 0.58
- Eased t
- 0.5
- Hex
- #996680
Supply the start and end colors, a fraction from zero through one, and the same four control coordinates used by CSS cubic-bezier easing. The result includes the eased fraction, normalized colors, hexadecimal output, and RGB channels, making transitions reproducible in design tools, animation pipelines, tests, and generated assets without relying on a browser animation clock.
Separate timeline progress from visible color progress
A linear blend treats fifty percent of elapsed time as fifty percent of the distance between two colors. Real interfaces often need a different rhythm: a transition may begin gently, accelerate through its middle, and settle slowly near its destination. This capability applies a cubic-bezier timing curve before blending the RGB channels.
At timeline zero the starting color is returned, and at timeline one the ending color is returned. Because the operation receives explicit numbers and does not consult a clock, repeated requests with identical inputs produce identical output. This is useful when a renderer, design exporter, test suite, or build process must agree on a transition frame without running an animation or estimating what a browser displayed at a particular instant.
How the cubic-bezier fraction is solved
A CSS-style cubic-bezier curve starts at zero, ends at one, and has two caller-provided control points. The requested timeline fraction belongs to the curve's x-axis, so simply evaluating the y polynomial at that same number would be incorrect for most curves. The calculator first finds the internal curve parameter whose x coordinate matches the requested fraction.
It uses a bounded Newton search when the slope is suitable and a fixed bisection search as a stable fallback. It then evaluates the y coordinate at that solved parameter. The x control coordinates must stay from zero through one, which keeps time monotonic and gives a unique answer.
The y controls may range from negative ten through ten, allowing anticipation and overshoot curves. If easing goes outside zero through one, interpolated RGB channels are clamped to their valid byte range. Reported decimal easing is rounded consistently, while channel values use nearest-integer rounding.
These explicit rules remove dependence on browser engines, frame rates, and platform-specific animation sampling.
Choose inputs and use the returned color
Enter each color as three or six hexadecimal digits, optionally preceded by a hash. Short colors are expanded and every accepted color is returned in normalized lowercase six-digit form. Provide t between zero and one, then provide x1, y1, x2, and y2 in the familiar cubic-bezier order.
For example, the common ease-in-out shape uses 0.42, 0, 0.58, and 1. Use the hex value in CSS, SVG, design tokens, or image instructions; use the channel object where structured numeric data is preferable. Validation rejects malformed colors, non-finite numbers, fractions outside the timeline, non-monotonic x controls, and excessively large y controls, so an invalid configuration cannot silently generate a misleading transition sample.
What you can do with it
Generate deterministic animation frames
Sample an eased color transition at exact fractions for a renderer or asset pipeline without depending on wall-clock timing.
Test interface transition colors
Calculate the expected intermediate hex value for visual regression and component tests that use a documented cubic-bezier curve.
Build an eased design-token scale
Create a sequence of color tokens whose spacing follows the same acceleration and settling rhythm as an interface animation.
FAQ
Is this the same as a linear color mix?
No. A linear mix uses the supplied fraction directly; this operation transforms that fraction through the cubic-bezier curve first.
Why must x1 and x2 be between zero and one?
That constraint keeps timeline progress monotonic, matching CSS timing-function rules and ensuring the x coordinate can be inverted unambiguously.
Can the easing curve overshoot?
Yes. y1 and y2 may be outside zero through one. The eased fraction reports the overshoot, while resulting RGB channels are clamped to valid values.
Which color formats are accepted?
Three- and six-digit hexadecimal RGB colors are accepted, with or without a leading hash. Alpha channels and named colors are not accepted.
What color is halfway between orange and blue with ease-in-out?
From #ff6600 to #3366ff at the midpoint, with the curve 0.42, 0, 0.58, 1, the eased fraction stays at 0.5 and the color is #996680. Other curves move that midpoint earlier or later.
Related tools
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/bezier-interpolate \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"color1":"#ff6600","color2":"#3366ff","t":0.5,"x1":0.42,"y1":0,"x2":0.58,"y2":1}'const res = await fetch("https://api.kit.forhosting.com/color/bezier-interpolate", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"color1": "#ff6600",
"color2": "#3366ff",
"t": 0.5,
"x1": 0.42,
"y1": 0,
"x2": 0.58,
"y2": 1
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/color/bezier-interpolate",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"color1": "#ff6600",
"color2": "#3366ff",
"t": 0.5,
"x1": 0.42,
"y1": 0,
"x2": 0.58,
"y2": 1
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/color/bezier-interpolate", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"color1":"#ff6600","color2":"#3366ff","t":0.5,"x1":0.42,"y1":0,"x2":0.58,"y2":1}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"color1":"#ff6600","color2":"#3366ff","t":0.5,"x1":0.42,"y1":0,"x2":0.58,"y2":1}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/color/bezier-interpolate", 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": "#ff6600",
"color2": "#3366ff",
"t": 0.5,
"x1": 0.42,
"y1": 0,
"x2": 0.58,
"y2": 1
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "color.bezier_interpolate",
"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. |
Technical notes
Cubic-bezier color interpolation calculates the exact color reached between two hexadecimal endpoints after a timing curve reshapes the requested fraction.
Separate timeline progress from visible color progress
The input t remains the timeline fraction, while eased_t reports the color fraction produced by the curve. That distinction makes the result easy to inspect and reuse. Between those endpoints, the curve controls how quickly the channels advance.
Choose inputs and use the returned color
The response preserves the normalized endpoints and curve, exposes the calculated eased fraction, and supplies both a hexadecimal color and separate red, green, and blue channels. For a sequence of frames, call the operation with evenly spaced timeline fractions while keeping the endpoints and controls constant.
Technical questions
What does one request cost?
Each API request costs $0.002. The browser version can run locally without sending the calculation to the API.