Generate a triadic color palette from any hex color
Enter #336699 and get its two triadic companions, #993366 and #669933, rotated 120 and 240 degrees around the color wheel. Saturation and lightness stay the same, so the three colors read as one family. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Color
- #336699
- Base color
- #336699
- Triadic colors
- #993366, #669933
- Palette
- #336699, #993366, #669933
- Hue offsets
- 120, 240
This triadic color palette generator takes one hexadecimal color and finds the two hues positioned exactly 120 and 240 degrees away from it on the color wheel. It preserves the base color’s saturation and lightness, producing a balanced three-color family without random choices or manual wheel calculations. Enter a standard three-digit or six-digit hex value, with or without a leading hash. The result includes the normalized base, both generated companions, the complete palette, and explicit hue offsets. Invalid formats return a clear input error, making the tool suitable for interactive design work and automated pipelines alike.
How triadic palette generation works
A triadic palette contains three hues spaced evenly around a circular color model. Imagine placing the points of an equilateral triangle on a color wheel: moving from one point to the next covers 120 degrees, and the third point is another 120 degrees farther along. This generator begins by validating and normalizing the supplied hexadecimal color.
Three-character notation is expanded to six characters, so #369 becomes #336699, while letter case is normalized for predictable output. The red, green, and blue channels are then converted into hue, saturation, and lightness. Only the hue is rotated.
One companion receives a positive 120-degree rotation and the other receives a positive 240-degree rotation, with angles wrapping cleanly at 360 degrees. Saturation and lightness remain unchanged, which keeps the companions at the same general intensity and brightness as the base. Finally, both rotated HSL colors are converted back into six-digit hexadecimal notation.
The response keeps the two generated companions separate from the complete three-color palette, making it clear which values were calculated and which value was supplied. The calculation uses no randomness, network request, current date, or stored state, so identical inputs always produce identical results.
Choosing and using the generated colors
Start with a base color that already has a defined purpose, such as a brand primary, illustration anchor, chart series color, or interface accent. The generated colors are mathematically balanced, but equal spacing does not mean every member should occupy equal visual area. A practical composition often lets the base dominate, uses one companion for supporting elements, and reserves the other for small highlights or calls to action.
Check text contrast separately because hue harmony does not guarantee readable foreground and background pairs. Since all three colors retain the same HSL lightness, two members can have very different perceived brightness, especially around yellow and blue. Designers may therefore use the raw triad as a starting point and create lighter or darker tonal steps for states, surfaces, and accessible text.
If you begin with a gray color, the companions will also be gray because a color with zero saturation has no visible hue to rotate; that result accurately reflects the underlying color model rather than a failed calculation.
What you can do with it
Create brand accent candidates
Turn an established brand hex into two evenly spaced accent colors for campaigns, illustrations, and supporting identity elements.
Build interface color tokens
Generate deterministic secondary and tertiary token candidates from a primary interface color during theme scaffolding.
Prepare chart series colors
Create a clear three-hue starting palette for dashboards, then verify contrast and data-visualization accessibility requirements.
FAQ
What is a triadic color palette?
It is a set of three hues separated by 120 degrees on the color wheel, forming an evenly spaced color relationship.
Which color formats are accepted?
Use three-digit or six-digit hexadecimal notation, with or without a leading hash, such as #369 or 336699.
Why do gray inputs produce gray companions?
Gray has zero saturation, so rotating its mathematical hue does not produce a visible color difference.
Can I enter a color name such as red instead of a hex code?
No. Only three- or six-digit hex codes are accepted, with or without the hash, such as #f06 or #ff0066. Named colors, RGB or HSL notation and codes with transparency are refused with a clear message.
Why does the palette start with my own color?
The base color comes first, normalized, followed by the two companions at 120 and 240 degrees. For #336699 the full palette is #336699, #993366 and #669933, so your existing color stays untouched.
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/triadic-palette \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"color":"#336699"}'const res = await fetch("https://api.kit.forhosting.com/color/triadic-palette", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"color": "#336699"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/color/triadic-palette",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"color": "#336699"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/color/triadic-palette", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"color":"#336699"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"color":"#336699"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/color/triadic-palette", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"color": "#336699"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "color.triadic_palette",
"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
Choosing and using the generated colors
Developers can copy the palette array directly into design-token tooling, or read triadic_colors when an existing base token must remain untouched. The returned hue_offsets field documents the transformation and makes automated checks straightforward.
Accepted formats, errors, and automation
The accepted forms are exactly three or six hexadecimal digits with an optional leading hash, such as #f06, f06, #ff0066, or FF0066. Surrounding whitespace is removed before validation. Named CSS colors, RGB functions, HSL functions, alpha-bearing four-digit and eight-digit hex values, programming-style 0x prefixes, empty strings, numbers, and strings containing non-hexadecimal characters are rejected. When integrating it, validate contrast and product-specific semantics after generation; this capability establishes hue relationships, while accessibility, cultural meaning, and brand hierarchy remain decisions for the final design system. Provide the base through the color field as a JSON string. These strict rules prevent accidental interpretation and make validation behavior dependable in forms, build scripts, and API clients. A successful response returns base_color, triadic_colors, palette, and hue_offsets. The base value is expanded and normalized, triadic_colors contains exactly the two generated colors, and palette places the base first followed by its 120-degree and 240-degree companions. Invalid values are reported with the invalid_input code rather than producing a guessed palette. That distinction is valuable in batch operations because a caller can isolate malformed records without accepting misleading design data. Browser use is convenient for exploration, while API execution costs $0.002 per successful item and provides the same deterministic algorithm.
Technical questions
Does the result include my base color?
Yes. palette contains the normalized base and both companions, while triadic_colors contains only the two generated colors.
How much does an API call cost?
Each successful API item costs $0.002. The browser version runs the same deterministic color calculation locally.