technique
Palettes and ramps
Build each material's colors as a short dark-to-light ramp that shifts hue and saturation as it climbs, share the darkest steps across ramps, and keep the whole palette small enough to swap.
Before this
This page assumes you are comfortable with:
- prerequisiteColor basicsHue, saturation, and value, how they relate to red, green, and blue, why value alone decides whether a sprite reads, and how to keep colors safe for players who cannot tell red from green.
- prerequisiteLight and formThe zones of light on a sphere and a cube, why shadows are never black, and how a 9 by 9 sphere in four values shows form while the same sphere pillow-shaded does not.
Why you need this
A pixel art game has room for very few colors on any one sprite, so each color has to do a job. A ramp is the unit that makes that possible: one small ordered set of colors that shades one material from shadow to highlight. Every shading, dithering, and anti-aliasing decision later in the pipeline picks from a ramp, so the ramps are decided in stage 1, "decide the rules", before the first sprite. A palette built from good ramps also gives you palette swaps for free, which is how one enemy sprite becomes three enemy tiers.
The idea
A ramp is an ordered list of colors, written dark to light, used to shade one material. Four colors is the common size for a 16-pixel sprite: shadow, dark midtone, midtone, highlight. A palette is the set of every ramp a game uses, counted as "N colors."
The naive ramp takes the material's base color and makes it darker and lighter by changing only value (how light the color is, the V in HSV). That produces a ramp where the shadow is the same red as the midtone, only dimmer. Real shadows and highlights do not work that way, and neither do good ramps. A ramp climbs three things at once:
- Value steps up from dark to light. This is the step that makes the ramp read at all; see Color basics for why value carries the form.
- Hue shifts as the value changes. Shadows lean toward cool colors, purple and blue; highlights lean toward warm colors, yellow and orange. This mimics a warm light source and a cool sky filling the shadows, and it makes every ramp feel lit rather than tinted.
- Saturation peaks in the midtones. The darkest step and the brightest step are less saturated than the middle, because deep shadow loses color and a bright highlight washes toward the light's color.
The precise version: pick the midtone as . Each step away from the midtone changes by a fixed fraction, moves toward 270 degrees (purple) on the dark side and toward 60 degrees (yellow) on the light side, and scales down as it leaves the middle.
Worked example
Start with a red cloth. Base midtone: hue 8, saturation 70 percent, value 75 percent, which is #bf4b39.
Step 1, value only. Keep hue and saturation, set value to 22, 49, 75, and 90 percent:
#391711 #7c3125 #bf4b39 #e65a45
Every color is the same red. The dark end looks like dried mud and the light end looks like plastic. This is the straight-value ramp, and it is the most common beginner ramp.
Step 2, shift the hue. Move the shadow steps toward purple and the highlight toward yellow: hues 328, 353, 8, 28.
#391127 #7c252f #bf4b39 #e69045
The darkest step is now a wine purple and the highlight is orange. The ramp already reads as one lit material rather than four tints.
Step 3, shape the saturation. Drop the darkest step to 56 percent saturation and the highlight to 42 percent, leaving the middle two at 70:
#39192a #7c252f #bf4b39 #e6b285
That is the finished ramp. Here it is against two more, built the same way:
| Step | Skin | Grass | Red cloth |
|---|---|---|---|
| Shadow | #4b2a3e (H 324, S 44, V 29) |
#2a2f4a (H 231, S 43, V 29) |
#39192a (H 328, S 56, V 22) |
| Dark mid | #8f5147 (H 8, S 50, V 56) |
#2f6b3a (H 131, S 56, V 42) |
#7c252f (H 353, S 70, V 49) |
| Midtone | #d9906c (H 20, S 50, V 85) |
#6bb04a (H 101, S 58, V 69) |
#bf4b39 (H 8, S 70, V 75) |
| Highlight | #f8d3ad (H 30, S 30, V 97) |
#c8de6e (H 72, S 50, V 87) |
#e6b285 (H 28, S 42, V 90) |
Read down any column: value rises, hue moves from the purple side to the yellow side, saturation is highest in the middle rows. The grass ramp's shadow is a blue-purple, not a dark green, and grass drawn with it looks like grass in daylight.
Sharing steps. Three ramps with three separate shadows is nine dark colors doing one job. Replace all three shadow steps with one dark purple, #2b1d3a, and the palette drops by two colors while every material now shares the same shadow. That single shared color is the strongest unifying trick in pixel art palettes. Highlights can share too: one near-white #f8f0dc as the brightest step of skin, metal, and cloth.
Value contrast test. Convert the palette to grayscale using the usual luminance weights, . For the skin ramp: 54, 98, 162, 218. For the grass ramp: 49, 84, 144, 203. Each ramp steps by at least 40 between neighbors, so a sprite drawn with it still shows its form with the color turned off. If two steps in one ramp land within 15 of each other, they will merge on a dim phone screen. If a whole ramp sits in the same gray range as another (a red and a green with identical values), sprites in those two materials will not separate from each other; give one of them a different value range.
Palette size. A whole game on 8 colors is possible and severe: two ramps of four, or one ramp of four plus four accents. 16 colors is comfortable for a small game with two or three materials per sprite. 32 colors covers characters, tiles, and backgrounds with distinct ramps for metal, wood, stone, skin, cloth, foliage, sky, and water. Beyond that, more colors stop helping: each new color is one more decision per pixel, and near-duplicate colors turn clean clusters into noise (see Pixel art fundamentals).
Building a palette from a purchased pack. The running example is a forest tileset with a 16-pixel grid and a seasonal variant. To match new art to it:
- Sample every distinct color in the pack's ground, foliage, and trunk tiles. A 16-color tileset usually turns out to hold 20 to 30, because of stray one-off pixels.
- Sort the samples by value using the grayscale formula.
- Group them into ramps by material: which four browns shade the trunks, which four greens the leaves. Colors used on only a few pixels are candidates to remove.
- Find the gaps. If the pack has foliage and bark but you need a stone wall, build a stone ramp with the same value steps and the same shadow color as the pack's ramps. It will sit beside the pack's tiles without looking imported.
Palette swaps. Because a ramp is an ordered list, you can replace the whole list and keep the sprite. The red cloth ramp becomes a blue ramp, and the same knight sprite is now on the other team. The grass ramp becomes an orange-brown ramp, and the same tileset is autumn. The pack's seasonal variant is exactly this. In an indexed color image (see Raster images and pixels) each pixel stores a small number and a table maps numbers to colors, so a palette swap is a new table and zero changes to pixels. The engine can do it at load time, or at draw time with a lookup, which is why enemy tiers, team colors, and seasons are nearly free once the art is on ramps.
Here is a generator that builds a four-step ramp from a midtone, with the hue shift and saturation shaping above. It runs in a browser console.
function hsvToHex(h, s, v) { // h in degrees, s and v in 0..1
const f = (n) => { const k = (n + h / 60) % 6;
return Math.round(255 * (v - v * s * Math.max(0, Math.min(k, 4 - k, 1)))).toString(16).padStart(2, "0"); };
return "#" + f(5) + f(3) + f(1);
}
function stepHue(h, target, deg) { // move h toward target by deg, the short way round
const d = ((target - h + 540) % 360) - 180;
return (h + Math.sign(d) * Math.min(deg, Math.abs(d)) + 360) % 360;
}
function ramp(h, s, v) { // midtone in, dark-to-light ramp out
return [hsvToHex(stepHue(h, 270, 40), s * 0.8, v * 0.3), hsvToHex(stepHue(h, 270, 15), s, v * 0.65),
hsvToHex(h, s, v), hsvToHex(stepHue(h, 60, 20), s * 0.6, Math.min(1, v * 1.2))];
}
ramp(8, 0.7, 0.75); // ["#39192a", "#7c252f", "#bf4b39", "#e6b285"]
The magic numbers (40 and 15 degrees toward purple, 20 toward yellow, saturation times 0.8 and 0.6) are a starting point. A game with a moonlit look pushes the shadow hue further and lowers every saturation; a game with a noon-desert look pushes the highlight hue and keeps the shadows warmer.
In a game's art pipeline
Ramps are written down in stage 1 with the resolution and light direction, as a palette file the whole team shares. Stage 2, "draw the still", shades every sprite by picking from a ramp (Shading and lighting), and mixes adjacent steps of a ramp when it needs a gradient (Dithering) or a soft edge (Anti-aliasing in pixel art). Stage 4 uses palette variants for seasons and regions. Stage 5 exports indexed images so swaps stay free, and Adapting purchased packs starts by extracting the pack's palette exactly as in the worked example above.
Common mistakes
- Straight-value ramps. Only lighter and darker, no hue shift. Symptom: shadows look muddy, highlights look like plastic, and every material seems painted with the same dull brush.
- Oversaturated shadows. The shadow step is a deep pure red or pure blue. Symptom: shadows glow instead of receding, and the sprite looks lit from inside.
- Black shadows. Pure
#000000as the darkest step of a colored ramp. Symptom: a hole in the sprite; the form ends where the shadow starts instead of turning away from the light. - Too many colors. Five near-identical greens on one bush. Symptom: at 1x the bush is speckled and no single cluster reads; converting to grayscale shows two or three of the greens are the same value.
- Ramps that collide in value. A red cloth ramp and a brown leather ramp with the same four grays. Symptom: in a screenshot with the color pulled, the cloak and the belt are one shape.
- A palette that grows. Each new sprite adds "just one" color. Symptom: the palette hits 60 colors, swaps break because nothing is on a ramp anymore, and new art never matches old art.
Cost
Building a palette is a one-time cost of a few hours, and it pays back on every sprite: an artist choosing from a fixed ramp places pixels faster than one mixing colors per sprite, and reviews are faster because "wrong color" becomes a yes-or-no question. The cost lands later if the palette was wrong. Changing a ramp that fifty sprites already use is a search-and-replace on an indexed image, which is cheap, but changing the number of steps in a ramp means reshading everything, which is not. On file size a palette is free: an indexed image stores one byte or less per pixel plus a table of at most 256 entries, so a 32-color game's art is smaller than the same art as full-color PNGs. Where it starts to hurt is a game with many materials at high resolution, where 32 colors stops being enough and the discipline of ramps has to be kept by convention rather than by the file format.
Going further
- Shading and lighting, for where on a form each step of the ramp goes.
- Dithering, for gradients that use two adjacent steps of a ramp.
- Adapting purchased packs, for extracting and extending a pack's palette.
- Color basics, if the hue and saturation steps above did not feel solid.
Leads to
- techniqueAdapting purchased packsHow to audit a bought asset pack, make it match your game's pixel size, palette, light, and outline rules, extend it in its own style, and keep the license paperwork straight.
- techniqueAnti-aliasing in pixel artSoften the stair steps on a diagonal or curve by placing one intermediate ramp color at the corner of each step, on the inside of the shape, and never against a transparent background.
- techniqueBackgrounds and parallaxHow to stack background layers that scroll at different speeds, tile each one without an obvious repeat, and push the far ones back with color so a flat screen reads as deep.
- techniqueDitheringMix two neighboring ramp colors in a fixed pattern so a large area reads as a smooth gradient without adding a single color to the palette.
- techniqueShading and lightingChoose the light direction once, then place highlight, midtone, and shadow on every form so the pixels describe volume instead of tracing the outline or glowing from the center.
- techniqueVFX and particlesHow hit sparks, explosions, smoke, dust, and fire are built as short frame sequences from a shared bright-to-dark ramp, and when to hand the work to a code-driven particle instead.