gamut generates color palettes and schemes in Go with perceptual matching
Go package to generate and manage color palettes & schemes 🎨
At a glance
- What is it?
- gamut is a Go package for generating and managing color palettes and schemes, with functions for hex parsing, darkening and lightening, color wheel schemes, shades and tints, six curated named palettes and random palette generators built on a perceptual color model. It suits a Go developer building a theme, an editor or a chart tool, and it is a small library with a release history that has been quiet for years.
- Who is it for?
- Adopt gamut when your Go program needs to derive a coherent palette from a seed color or match an arbitrary color to a named palette perceptually, and pick a dedicated color library when you need broader color science such as color space conversion for print or wide gamut output.
- Can I use it commercially?
- Yes. MIT 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 72 days ago.
- What is it written in?
- Mainly Go, 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
Everything crosses the boundary as a color.Color value
The design decision that keeps the API small is stated plainly in the README. gamut operates on various color spaces internally, but all color values you pass in as parameters and all return values will match Go's color.Color interface. Everything else follows from that. You never handle a gamut-specific color type, so the output of a palette function drops straight into anything in the standard library that accepts a color.Color, including an image draw call or an SVG writer. The package splits into a root module and two subpackages, the root for the color operations and schemes, palette for the curated and user-defined palettes, and theme for working with themes. The import block is the whole setup:
import "github.com/muesli/gamut"
import "github.com/muesli/gamut/palette"
import "github.com/muesli/gamut/theme"The module path is github.com/muesli/gamut, the package requires Go 1.21, and the licence is MIT. The dependency list is short, with go-colorful at v1.4.1 doing the color space work, plus three small helpers from the same author, clusters for grouping, kmeans for clustering and smetrics for the distance metric.
Hex in, hex out, and the wheel operations keep hue steady
The convenience layer is a hex parser and its inverse. The parser accepts the short and standard formats:
color = gamut.Hex("#333")
color = gamut.Hex("#ABCDEF")And the hex encoding of any color.Color comes back through ToHex:
hex = gamut.ToHex(color)Around the wheel, the operations are defined by what they leave untouched. Darker and Lighter change the lightness of a color by a specified percentage without changing the hue, and the percentage is a fraction, so a tenth darker and three tenths lighter:
// returns a 10% darker version of color
color = gamut.Darker(color, 0.1)
// returns a 30% lighter version of color
color = gamut.Lighter(color, 0.3)Complementary returns the color on the opposite side of the wheel, Contrast returns whichever of black or white has the highest contrast against the given color, and HueOffset returns a color with the same lightness and saturation but a different angle, taking a degree value that can be negative to go the other way around the wheel.
Schemes and shades are the two ways to build a palette from one color
The scheme functions all return colors of a different hue with the same lightness and saturation as the color you pass in, and they differ in how the hues are spaced. Triadic gives three hues equally spaced around the wheel, Quadratic gives four, Tetradic takes two colors and their complementary values, Analogous takes colors next to each other on the wheel, and SplitComplementary takes the colors next to the complementary value of the given color. The other family varies saturation and lightness instead of hue, and is the one that looks like a conventional UI scale. Monochromatic returns colors of the same hue with different saturation and lightness. Shades blends from the given color towards black, Tints blends towards white, and Tones blends towards gray. Each takes a count, so gamut.Shades(color, 8) gives you eight steps, and each of these has a rendered example image in the docs directory of the repository. Blends is the general case, returning interpolated colors between two colors with a count of steps.
Six curated palettes come with names, and you can filter them
Gamut ships six curated color palettes, and the interesting part is that every color in them carries a name. The Wikipedia palette holds 1609 colors imported from the List of colors on Wikipedia, Crayola holds 180, the CSS palette holds 147 from the MDN colour value documentation, RAL holds 213, Resene holds 759 and Monokai holds 17. The Colors function lets you retrieve all colors in a palette, and the example in the README prints the name and the color value for each:
for _, c := range palette.Wikipedia.Colors() {
fmt.Println(c.Name, c.Color)
}Naming is what makes the palettes usable rather than merely decorative. You can filter a palette by name, and the example returns all the blue colors in the Wikipedia palette:
colors = palette.Wikipedia.Filter("blue")You can look up a color by name with the Color function, and the Name function goes the other way, returning the name and distance of the closest perceptually matching color in the palette, with the distance being between 0.0 and 1.0:
name, distance = palette.Wikipedia.Name(color)
// name = "Baby blue"
// distance between 0.0 and 1.0The project also asks for contributions, saying new curated palettes and importers are welcome. Building your own palette is a matter of adding colors to a gamut.Palette, where Name and Reference are optional.
Clamped and MixedWith solve the two palette problems you hit in practice
Two functions address situations that come up repeatedly. The Clamped function returns a slice of the closest perceptually matching colors in a palette, maintaining the same order as the original slice you provided, and it is described as the answer to the case where you have a slice of colors but are limited to a palette you can work with. The other is MixedWith, which combines all colors of two palettes by mixing them:
p = palette.Crayola.MixedWith(palette.Monokai)The Clamped function is the more consequential of the two, because it is what lets a design system enforce a brand palette on imagery or user supplied colors. It takes a slice and returns a slice of the same length, in the same order, with every element replaced by its nearest perceptual match, and the fact that the order is preserved is what makes it usable in a rendering pipeline. The distance metric behind the matching is not documented in the visible README, and the dependency list shows smetrics in the tree, so the exact metric is an implementation detail a reader would need to read the source for.
Generators produce random palettes inside a color space constraint
The generator side is the opposite direction, producing colors rather than deriving them. The documentation describes color generators such as the provided PastelGenerator, WarmGenerator or HappyGenerator, which can produce random color palettes within the color space constraints of the generator:
colors, err = gamut.Generate(8, gamut.PastelGenerator{})The count argument asks for eight colors and the generator decides the shape of the result, so PastelGenerator gives you eight pastels while WarmGenerator gives you eight warm ones. There is also a SimilarHueGenerator, which produces colors with a hue similar to a given one, and the README notes that the generator function returns an error, so a generator that cannot satisfy its constraint reports it rather than returning a short slice. The repository has a generator.go and generator_test.go at the root, alongside a palette/ directory and an examples/ directory with separate projects for analysis, generator, htmlgen and palettes, the htmlgen example being the one to look at if you want to see these palettes rendered rather than printed.
The release history is quiet, and the code still compiles against Go 1.21
The maintenance picture deserves a plain statement. The repository is not archived and the last push was on 2026-08-13, so the code is being touched, but the release tags are old. v0.3.1 is dated 2022-07-22, v0.3.0 is from 2021-12-28 and v0.2.0 is from 2020-12-07. So a project that depends on gamut today would take the 2022 release, and the commits since then are not something you get by pulling a tag. The go.mod declares go 1.21, and the dependency versions are of the same vintage, with go-colorful at v1.4.1 and kmeans at v0.3.1. The topic list gives a sense of the scope, covering color-blending, color-palettes, color-schemes, color-wheel, gamut, hue, themes and tints, and the code layout at the root is small, with colors.go, gamut.go and generator.go plus the palette/ and theme/ directories. The badges show a build workflow and a coverage status, and the .golangci.yml file indicates the linter configuration is part of the workflow.
Where gamut is the wrong choice
Three situations argue against it. The first is a project that needs real color science, such as converting between wide gamut profiles for print, or handling colour management with an ICC profile, or producing output for a display that gamut does not model. The library operates on color spaces internally and gives you a palette API, not a color management pipeline, and the dependency on go-colorful is what provides the space conversions underneath. The second is a project that already has a palette system. If your application already loads a brand palette, gamut's job is to derive shades and tints from a seed color, which is a smaller problem, and pulling in a palette library for that is a lot of dependency for a few functions. The third is a team that wants a maintained dependency with a clear compatibility story. The release cadence has been slow since 2020, and while the last push shows work continuing, the code you get from a tag has not moved in years. The realistic alternative for most Go projects is to use go-colorful directly, which is the same underlying library gamut builds on, and write the twenty lines of scheme and tint logic your design system actually needs, which is a good deal less than depending on a general purpose palette library for a narrow requirement.
Editorial conclusion
Adopt gamut when your Go program needs to derive a coherent palette from a seed color or match an arbitrary color to a named palette perceptually, and pick a dedicated color library when you need broader color science such as color space conversion for print or wide gamut output. Verify first that the perceptual distance behaviour matches what your use case needs, because the closest-match functions are tuned to a particular distance model, and check the Go version constraint in go.mod against your toolchain before depending on it.
Frequently asked questions
What is the gamut Go package?
It is a Go package to generate and manage color palettes and schemes. It operates on various color spaces internally, but all color values you pass in and all return values match Go's color.Color interface, and it ships the root package plus palette/ and theme/ subpackages.
Which color palettes does gamut include?
Six curated palettes: Wikipedia with 1609 colors, Crayola with 180, CSS with 147, RAL with 213, Resene with 759 and Monokai with 17. Each color in the curated palettes carries an official name, so palettes can be filtered by name and a color can be matched to its closest perceptual equivalent.
What is the difference between gamut's scheme and shade functions?
The scheme functions, Triadic, Quadratic, Tetradic, Analogous and SplitComplementary, return colors of a different hue with the same lightness and saturation as the given color. The shade family, Monochromatic, Shades, Tints and Tones, keeps the hue and varies saturation and lightness, blending towards black, white or gray respectively.
How do you create your own palette with gamut?
Declare a gamut.Palette and call AddColors with a gamut.Colors slice, where each entry has a name, a color and a reference, and the name and reference are optional. The project also asks for contributions of new curated palettes and importers.
Is gamut still maintained?
The repository is not archived and the last push was on 2026-08-13, but the release tags are old: v0.3.1 from 2022-07-22, v0.3.0 from 2021-12-28 and v0.2.0 from 2020-12-07. The go.mod declares go 1.21, the licence is MIT, and the package depends on go-colorful v1.4.1.
Official sources
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.
[](https://hysenlabs.com/projects/muesli-gamut)Was this useful?