Library / SDK
Ogeon/palette avatar
Ogeon/palette

palette: a Rust colour library that puts colour spaces in the type system

A Rust library for linear color calculations and conversion

841 stars73 forksRustApache-2.0

At a glance

What is it?
palette is a Rust library for linear colour calculation and conversion, built around the argument that the type system should stop you mixing up colour spaces. It covers a wide range of spaces including user-defined variants, splits its maths and its derive macros into separate crates, and is licensed Apache-2.0 or MIT at your option.
Who is it for?
Adopt palette when you are doing colour work in Rust and want the compiler to stop you converting between incompatible spaces by accident, especially with linear and perceptual workflows in the same codebase. Do not adopt it for a one-off hex to RGB conversion.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 48 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What the library claims to solve

palette describes itself as a colour management and conversion library that focuses on maintaining correctness, flexibility and ease of use. The three claims are worth separating, because each one implies something different about the design.

Correctness comes first, and it is a specific kind of correctness rather than numerical accuracy in the usual sense. Most colour bugs are not a rounding error, they are a mistake about which space a number lives in. A value of 0.5 means something different in sRGB, in linear sRGB and in Oklab, and a library that lets you pass one where the other is expected will produce plausible-looking wrong results rather than an error.

Flexibility is the second claim, and it covers both the range of colour spaces and the integration story. The README says the library supports a wide range of colour spaces including user defined variants, and offers different ways of integrating with other libraries. Both halves matter: the colour space coverage is breadth, and the integration options are about how the types meet whatever your rendering or image library expects.

Ease of use is the third, and in a library about colour it is a real design constraint rather than a marketing line. A colour library that is correct but unpleasant to call gets bypassed, and a bypassed colour library is worse than none.

The repository is Apache-2.0 or MIT at your option, which is the permissive pair that lets it drop into either licensing scheme without friction. The last push was on 2026-09-05 and there are no GitHub releases, so the crate is published to crates.io and the documentation comes in two forms: the released version on docs.rs, which the README links at 0.7.7, and the master branch documentation hosted separately.

The workspace layout and what each crate is for

The Cargo.toml at the root is a workspace manifest, and its member list explains the shape of the project better than the README does:

toml
[workspace]
members = [
    "palette",
    "palette_derive",
    "palette_math",

    # Test crates
    "integration_tests",
    "no_std_test",
    "benchmarks",

    # Tool crates
    "codegen"
]
resolver = "2"

The main palette crate is the library itself. palette_math is the numeric core, separated out so that the arithmetic can be reused without pulling in the rest, and palette_derive is a derive macro crate, which is the mechanism by which the type system learns about the colour spaces. The separation of the derive macros into their own crate is the usual Rust pattern for keeping proc macros out of the main dependency graph, and it means the derive code can depend on syn and quote without every user of the library compiling them.

The three test crates are labelled as test crates in the manifest itself. integration_tests covers the behaviour across crate boundaries, no_std_test exists because the library has a no_std configuration that has to be verified separately, and benchmarks is a dedicated crate rather than a set of benches inside the main one. Having a separate crate for benchmarks means they can depend on the published package rather than on the internal layout, which is the arrangement that keeps benchmark results comparable over time.

The codegen crate is labelled a tool crate. Its existence suggests that part of the colour space definitions are generated rather than hand-written, which is the sensible approach once you have a large number of spaces with a repetitive structure.

The rest of the repository supports this: a gfx/ directory, an example-data/ directory, a CHANGELOG.md, a CONTRIBUTING.md, a bors.toml for the merging bot, a codecov.yml for coverage reporting and a .vscode/ directory.

Using the type system as the safety mechanism

The most interesting claim in the README is that the library makes use of the type system to prevent mistakes. That is a design decision with a specific shape.

In a conventional colour library, a conversion function takes any colour type and returns a colour type, and the compiler is happy. If the library exposes one colour type per space, the compiler can require the source and destination spaces to be specific, and the mistake of mixing linear and sRGB becomes a type error rather than a subtly wrong pixel.

The cost of that approach is that the API surface is larger, because each space has its own type, and the derive macros exist to generate the repetitive parts of that surface. That is why palette_derive is a separate crate rather than a build script: the macros are what make a wide range of colour spaces practical to expose as distinct types.

The user defined variants are the extension point. The README mentions colour spaces including user defined variants, which means you can define a space that is not in the library, with its own primaries and transfer function, and get the same compile-time guarantees for it as for the built-in ones. For work in a colour-managed pipeline, that is the feature that matters, because real workflows use spaces specific to a display, a camera or a printing condition.

The flexibility also extends to how the types meet other libraries. The README mentions different ways of integrating with other libraries, which in practice means the library can present its colours in the representation another crate expects, so that a value can cross the boundary without a hand-written conversion at every call site.

None of this is spelled out in detail in the README. The pointer is to the palette directory, which the README says holds the usage and examples, and to the API documentation.

The minimum supported Rust version and the release policy

The MSRV section is unusually precise for a library README, and it contains a policy statement that tells you how the project treats its own compatibility promise.

The current version has been automatically tested with Rust version 1.71.0 and with the stable, beta and nightly channels. The important qualifier is the last clause: the minimum supported version may vary with the set of enabled features. So the effective floor depends on which optional features you turn on, which is a common arrangement for a library with a wide feature matrix and an MSRV policy that has to reconcile many combinations.

The policy for moving that floor is stated next. Future versions of the library may advance the minimum supported version to make use of new language features, but this will normally be considered a breaking change. And the exceptions are listed: security patches, dependencies advancing their MSRV in minor or patch releases, and similar changes.

That exception list is worth reading carefully, because it describes the two situations where you might get a bump without a major version. A security patch that requires a newer compiler is a legitimate reason to move the floor in a patch release, and so is a dependency doing the same. It is an honest statement about the practical impossibility of holding a floor when your dependencies do not.

The presence of a no_std_test crate in the workspace connects to this. A library that supports no_std has to build without the standard library, which constrains what it can use and therefore what compiler features it can rely on, and the MSRV has to be a version where those constraints hold.

The two documentation links point at the same library in two states, the released 0.7.7 on docs.rs and the master branch documentation hosted on the project's own pages. For a library with no GitHub releases, that pair is how a user checks what they are reading against what they are compiling.

Limits: an unreleased version line and a moving API surface

The limits are modest but they are worth knowing.

The first is that there are no GitHub releases. The crate goes to crates.io, and the version you get from a dependency is a crates.io version rather than a tag you can point at in a README. For a library this is normal, but it means the release history is the crates.io changelog and the CHANGELOG.md rather than a set of tags, and it means the two documentation links in the README are the only way to know whether you are reading about the version you depend on.

The second is that the master branch documentation is published separately from the released documentation, which is a deliberate choice to document unreleased work, and a trap if you are reading about a feature and then find it missing from the released crate. The README does not flag that explicitly, so it is worth checking which version a feature landed in.

The third is the MSRV interaction with features. Because the effective minimum depends on the enabled feature set, a project pinning an old compiler has to determine the constraint for its own combination, and that combination is not obvious from the README alone.

The fourth is the cost of the type-safety approach, which is real but bounded. A colour library with one type per space has a large surface, and the compiler can only protect the conversions the library has modelled. A colour space you define yourself gets the type treatment, but the correctness of your own primaries and transfer function is on you, and the library cannot check it.

The fifth is the dual licence, which is a strength with one caveat. Apache-2.0 or MIT at your option means you can slot it into either scheme, and the README states that unless you explicitly say otherwise, contributions are dual licensed the same way. That is the standard Rust dual-licensing arrangement and it keeps the licensing question from becoming a blocker for a contributor.

This library against hand-written conversion and against a general colour crate

Two comparisons make the choice clearer.

The first is against writing the conversions yourself, which is what most projects end up doing. The work is not the arithmetic, it is the bookkeeping. You need a distinct type per space, or at least distinct constructor functions, or the mixing happens. You need the transfer function applied on the way in and the inverse on the way out, and the inverse is where the subtle errors live. And you need to know, when you look at a function signature six months later, which space that parameter was in.

The library's contribution is the type discipline and the tested arithmetic. If your project has two or three spaces in play and one conversion between them, hand-rolling is a reasonable afternoon. If you have a rendering pipeline with a display space, a working space, an authoring space and a texture space, the bookkeeping becomes the bug source and a library that makes the compiler catch it pays for itself.

The second comparison is against a general-purpose colour crate, of which there are several for Rust. The difference in approach is scope. A general colour crate gives you a colour type, conversions, and probably sRGB because that is what images are. palette is concerned specifically with colour management and with covering a wide range of spaces, including ones you define, which is the vocabulary of a print or display pipeline rather than of an image library.

The choice between them is about how many spaces you have and whether you need to define your own. One space and some hex parsing, a general crate is the lighter answer. A managed pipeline with user-defined spaces, this one is built for the job.

Editorial conclusion

Adopt palette when you are doing colour work in Rust and want the compiler to stop you converting between incompatible spaces by accident, especially with linear and perceptual workflows in the same codebase. Do not adopt it for a one-off hex to RGB conversion. Verify first that the colour spaces you need are supported, that the feature set you enable still matches your minimum Rust version, and that the version you depend on is the one whose documentation you read, since the released docs and the master branch docs are separate.

Frequently asked questions

What is the palette Rust library?

It is a colour management and conversion library focused on correctness, flexibility and ease of use. It uses the type system to prevent mistakes, supports a wide range of colour spaces including user defined variants, and offers different ways of integrating with other libraries.

What is the minimum supported Rust version for palette?

The current version has been automatically tested with Rust 1.71.0 and with the stable, beta and nightly channels, and the minimum supported version may vary with the set of enabled features. The README says future versions may advance the minimum to use new language features, which is normally considered a breaking change, with exceptions for security patches and dependencies advancing their own minimum in minor or patch releases.

How is the palette repository structured?

It is a Cargo workspace with the palette crate itself, a palette_derive crate for the derive macros and a palette_math crate for the numeric core, plus three test crates for integration tests, no_std testing and benchmarks, and a codegen tool crate. The README points to the palette directory for usage and examples, and links the released documentation on docs.rs alongside separate documentation for the master branch.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. Ogeon/palette on GitHub
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ogeon-palette.svg)](https://hysenlabs.com/projects/ogeon-palette)

Was this useful?