Composed variants
Composed variants
default and dark. Categories that declare a context also expose one colored variant per context value.The variant union
The compositor accepts three variant forms:
type ComposeVariant =
| 'default'
| 'dark'
| { kind: 'colored'; color: string } // color is #RRGGBB
Each resolves to three colors: the shape fill, the shape stroke, and the inner (symbol) color.
| Variant | Shape fill | Shape stroke | Inner color |
|---|---|---|---|
default | none (transparent) | #000 | #000 |
dark | #000 | #000 | #FFF |
{kind:'colored',color} | color | color | innerColorForShape(color) |
Why the split exists
default and dark are universal — every element renders equally well outlined (light UI) or filled (dark UI). Context-colored variants exist because each category can declare a context.values[] set whose members carry a color. An element can therefore render in any context value its category declares.
This keeps the color palette scoped to where it semantically belongs: a category's context, not the element itself.
Discovering valid variants
The build step materializes an icon_variants[] array onto every element. Read it via get_element or GET /schemas/:version/elements/:element_id:
{
"id": "purpose.example",
"icon_variants": ["default", "dark", "commercial", "civic"]
}
get_icon_url mirrors this array in its response for convenience.
The innerColor rule
For colored variants, the inner color is derived from the shape color via WCAG 2 relative luminance:
innerColor = relativeLuminance(shapeColor) >= 0.179 ? '#000' : '#FFF'
The 0.179 threshold matches the common "choose black or white text on a background" heuristic.
Worked example
Take a category with context.values[{id:'commercial', color:'#0052CC'}]:
shapeColor = #0052CC
rgb = (0, 82, 204)
linearized = (0.000, 0.0865, 0.6105)
luminance = 0.2126·0.000 + 0.7152·0.0865 + 0.0722·0.6105
= 0.106
0.106 < 0.179 → innerColor = #FFF
The commercial variant of an element in this category therefore renders with a #0052CC shape and white inner glyph.
Take a lighter context color, #FFDD00 (DTPR warning yellow):
luminance ≈ 0.81
0.81 >= 0.179 → innerColor = #000
The rule deliberately biases toward high-contrast symbol legibility at small sizes.
Output SVG
A composed icon is an inline-compact 36×36 SVG:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" width="36" height="36">
<path d="…shape path…" fill="…" stroke="…" stroke-width="2"/>
<g color="…innerColor…">
…stripped symbol inner…
</g>
</svg>
Identical inputs produce byte-identical output — no randomness, no timestamps, no environment-dependent behavior.
See also
- URLs — how the variant maps into a URL.
- Shapes, Symbols
- MCP
get_icon_url