# Color and light: three different kinds of correctness

A portable working chapter; no brand palette is prescribed. Sources were retrieved 2026-09-27 UTC. Read [craft.md](craft.md) for cluster/edge repair and [exercises.md](exercises.md) for tests. Cited facts come from the sources; pixel-level recipes below are authored translations, not claims that the artists used these workflows.

## 1. State which promise matters

| Promise | Useful evidence | Not sufficient |
|---|---|---|
| Physically plausible light | Coherent source positions, visibility, receiving planes and material response | Warm highlights/cool shadows everywhere |
| Deliberate art direction | A readable hierarchy, expressive relationships and declared departures | Calling an arbitrary hue shift “physically accurate” |
| Colorimetric fidelity | Known source/destination spaces, transfer functions, conversion, calibrated/profiled display conditions where required | Matching hex strings in unrelated profiles |

The color of an illuminated object depends on both its reflectance spectrum and the illuminating light; colorimetry concerns the measured/perceived color, not a mood label.[10] A stylized violet shadow can be excellent art direction without being a measured match to a real room.

**Terminology:** use *hue* for color family; *value* for the artist's light–dark organization and name the numerical model when measuring it. HSV **V**, relative luminance **Y**, and Oklab perceptual lightness **L** are not interchangeable. *Chroma* in a chosen perceptual space is not the same coordinate as HSV saturation. CSS Color distinguishes colorimetric spaces, luminance and perceptual spaces; do not call a simple desaturation button a measurement of light energy.[10]

**Practical rule:** maintain two checks: a luminance-based grayscale/value organization and the full-color image. Neither alone predicts salience; a small contrasting hue can be important without the greatest luminance.

## 2. Construct ramps with roles, not equal slider increments

Pixel Joint describes ramps that can share shadows, highlights or neutral bridge colors.[1] Medeiros demonstrates a hue/saturation-shifted green vase but explicitly treats color advice as flexible guides, not immutable rules.[2]

### Build one material ramp

1. Name the material and lighting: “matte green enamel under warm task light and cool ambient fill.” Do not confuse local color with its appearance under one illumination.
2. Assign shade roles: occluded recess, shadow plane, body midtone, lit plane, high light. A separate specular glint may need a separate role.
3. Establish readable light–dark intervals. Equal numerical spacing is not mandatory; reserve the largest useful contrast for focal form boundaries.
4. Adjust hue/chroma as a path: let the lit end move toward the light's influence and the shadow end toward remaining fill/bounce. Compare neighboring swatches both touching and separated by the scene background.
5. Reuse an existing shade only if it keeps the ramp order and material distinction. Split a shared shade when it creates an unwanted coupling.
6. Repaint sample clusters with the ramp. Swatches that look excellent in isolation can produce muddy contours or disappearing planes in context.

**Original teaching ramp, not a sampled artist or DSM palette:**

| Role | Encoded sRGB hex | Computed relative luminance Y |
|---|---|---:|
| Deep cool recess | `#182c35` | 0.0225 |
| Shadow plane | `#365052` | 0.0713 |
| Green-gray body | `#64745e` | 0.1601 |
| Warm lit plane | `#a4a270` | 0.3490 |
| Pale warm high light | `#e1ce90` | 0.6216 |

These numbers were calculated by decoding sRGB and applying `Y = 0.2126 Rlin + 0.7152 Glin + 0.0722 Blin`; coefficients are rounded. The transfer function and linear-sRGB-to-XYZ relation are documented in CSS Color.[10] The monotonic Y values demonstrate ordering, **not** a physical simulation or equal perceptual steps. This example becomes yellowish toward light and blueish in shadow by choice. Under a cool key and warm bounce, redesign the path rather than rotating every hue blindly.

**Avoid three habits:** raising V alone for every highlight; forcing all shadow chroma to zero; forcing all highlights toward white. Each may work in a particular brief, but none follows universally from light physics. A bright diffuse patch can be saturated; a glossy dielectric highlight can carry the illuminant's color; different exposure/gamut choices can alter both.

## 3. Keep semantic accents alive

Separate *signal* from *illumination*. An indicator may be a colored surface, a tiny emissive source, or an imposed UI cue; these have different treatment.

- Give status color a named role and a location/mask. Keep it separate from visually similar wall or clothing shades when their meanings must change independently.
- A tiny LED may remain legible without lighting the whole room. A large bright screen may motivate colored spill on nearby facing surfaces; do not assign spill solely because something is cyan.
- When quantizing, reserve signal colors or remap the masked region explicitly. Then inspect whether the shape survived, not just whether the color exists somewhere in the file.
- Test a color change against surrounding hues and luminance. If exact hue carries required meaning, avoid a global grade that silently changes that meaning; reinforce with shape, position or real text.
- Re-evaluate accent area and contrast. Repeating a strong color everywhere makes it atmosphere rather than a unique signal. Medeiros specifically recommends considering small saturated details against less saturated large areas.[2]

## 4. Build a light map before shading

Write a tiny light sheet: key direction/position, apparent size, color, relative strength; fill/environment; any local emitters; receiving surfaces. Separate these from the observer/camera direction.

The light-transport model balances emission and scattered incoming light, with illumination dependent on scene geometry and other surfaces.[15] Lambertian diffuse reflection is one approximation; specular reflection has its own directional behavior.[14][13]

**A useful drawing approximation:** for a diffuse patch, think `material response × incoming illumination × facing/visibility`, plus bounce and any emission. For a simplified Lambertian direct-light model, each light contributes a term proportional to `max(0, normal·lightDirection)` with visibility and strength included. This is a reasoning aid derived from the diffuse/transport models, not a calibrated renderer or a rule that specular glints sit at the brightest diffuse point.[14][15]

### Make shadows answer geometry

| Shadow or light cue | Question to answer | Pixel translation |
|---|---|---|
| Form shadow | Which part of this surface turns away from the source? | Broad shape-dependent transition, not an inset outline |
| Cast shadow | What blocks this source before it reaches this receiver? | Project a recognizable occluder relationship onto the receiving plane |
| Contact occlusion | Which nearby directions are blocked at the meeting point? | Compact seam/attachment cue; avoid a uniform dark sticker under everything |
| Penumbra | How much of the extended source remains visible? | Narrow near-contact transition, widening where geometry warrants it |
| Bounce | Which illuminated surface sends light here? | Restrained localized reflected color tied to the receiving plane |
| Specular reflection | Can the view direction receive a reflected source/environment feature? | Directional glint/stripe whose position can differ from diffuse shading |

Larger apparent area lights generally broaden penumbrae; PBRT's comparison also shows changes in surface shading and highlight appearance.[9] **Drawing inference:** soften the cast shadow through designed tone clusters or a restricted dither region, not an indiscriminate blur. An angular pixel edge can represent a physically soft transition at low resolution.

A contact region need not be absolute black, and “ambient occlusion” is not a universal dark halo. Account for fill, bounce, transparency and how closed the contact really is. Conversely, an unexplained bright gap under a weight-bearing object can make it float.

### Two colored lights

1. Establish one source at a time. Make a visibility mask for each; the same occluder need not block both.
2. Add their contributions in a linear-light model if computing illumination, not by averaging hue angles or blending encoded RGB as if it were energy.[10]
3. Where a warm source is blocked but a cyan source remains visible, the shadow can be cyan-dominated. This is remaining light, not an automatic “complement of the key” formula.
4. At overlap, do not simply paint white. Result depends on source spectra/intensities, material response, exposure and gamut; RGB channel multiplication is only an approximation for spectral interactions.[10][15]
5. Collapse the result into intentional shade clusters. Preserve contact, silhouette and signal colors when simplifying.

**Relighting test:** moving the key from left to right should require new lit planes, cast shadows and reflection placement. A global palette swap can create a different mood while leaving the old light geometry intact; call it a grade unless geometry was changed too.

## 5. Material response: change the mark, not only its hue

PBRT distinguishes diffuse, glossy and perfect specular behavior and directional anisotropy; most real surfaces combine behaviors.[7] Its specular chapter separates dielectric and conductor optics, with wavelength-dependent response.[13] The following are low-resolution depiction heuristics, not physically exact material models.

| Material intent | Constructive cues | Common false cue |
|---|---|---|
| Matte plaster, paper, rough paint | Broad plane changes; subdued localized variation; few sharp highlights | One white dot on every object |
| Glossy ceramic or plastic | Body-color form shading plus compact light-colored reflection; clear separation of diffuse and specular shape | A pale ring following the whole silhouette |
| Polished metal | Strong neighboring dark/light reflected shapes; highlights may be tinted by metal and light; environment matters | Ordinary diffuse shading made gray |
| Brushed/rough metal | Broader or directionally stretched reflection; sparse aligned texture | Uniform random speckles called roughness |
| Glass | Transmitted background, edge/reflection cues, overlap and thickness; omit detail strategically | Blue fill with indiscriminate low opacity |
| Cloth | Large fold planes first, rougher highlights and selective weave | Checkerboard over the whole body |
| Skin/hair | Preserve facial/gesture planes; use restrained warm transitions or directional hair group highlights where useful | Treating every strand/pore as an independent bright pixel |
| Emissive screen | Luminous face separated from frame, with motivated nearby spill if strong enough | Bloom pasted over unchanged dark objects |

Judge highlight width relative to object size and source size. Roughness and light size both influence the visible reflection; do not infer either uniquely from a single painted highlight.[7][9] Texture describes small surface structure; it is not a substitute for reflected environment structure.

## 6. Linear light, artistic interpolation and alpha

sRGB numbers are encoded; their arithmetic midpoint is not a half-energy mixture. CSS Color defines the piecewise transfer and explains why linear-light spaces are appropriate for light mixing.[10]

For an encoded channel `c` normalized to `[0,1]`:

```text
Decode: L = c / 12.92                         when c <= 0.04045
            ((c + 0.055) / 1.055)^2.4        otherwise
Encode: c = 12.92 * L                         when L <= 0.0031308
            1.055 * L^(1/2.4) - 0.055        otherwise
```

This restricted-range recipe omits extended negative/wide-gamut handling; use a tested color-management library for that. Do not approximate sRGB as a pure exponent when accuracy matters.

**Calculated sanity test:** half-intensity white over black in a linear-light model encodes to about `0.735357`, or 8-bit **188**. An encoded arithmetic midpoint of `0.5` decodes to about **0.214041** light, not half. The calculation tests the transfer model, not a promise that every application's opacity slider works in that space.[10]

**Choose the model on purpose:**

- Sum illumination and perform energy-motivated glow/compositing in linear light.
- Use Oklab/Oklch or hand-picked swatches when the goal is an artistically spaced perceptual ramp, then check gamut and actual clusters. Perceptual interpolation is not a light-transport simulation.[10]
- If matching an existing gamma-encoded blend aesthetic, reproduce it deliberately and label it; do not call it physical just because the result is attractive.

For source-over compositing with **linear** RGB and straight input colors:

```text
outAlpha = srcAlpha + dstAlpha * (1 - srcAlpha)
outPremultRGB = srcRGB * srcAlpha
              + dstRGB * dstAlpha * (1 - srcAlpha)
outStraightRGB = outPremultRGB / outAlpha   if outAlpha > 0
```

For filtering/resampling transparent content, premultiply in the chosen working space before interpolation and unpremultiply afterward where needed; this avoids hidden RGB bleeding into edges. Do not premultiply twice. PNG stores unassociated—not premultiplied—alpha; its alpha samples are linear opacity fractions and are not gamma-encoded color channels.[11] Keep an explicit contract at each decoder, processing and export boundary rather than guessing what an API returns.

For strict binary-alpha pixel art, a declared no-interpolation path is often simpler. Semi-transparent pixels are allowed if the deliverable permits them, but they create background-dependent displayed colors; a small stored RGB palette is not a promise of a small composite palette.

## 7. Color management and delivery limits

Aseprite documents that profiles define what RGB coordinates mean and provides assign/convert operations.[6] PNG can store color-space data, including sRGB and ICC-related chunks.[11]

**Assign** identifies how existing numbers should be interpreted; **convert** transforms numbers between known spaces to preserve appearance as far as gamut/intent permits. Do not “fix” a P3 image by attaching an sRGB label to unchanged samples. If its source profile is unknown, label the assumption rather than declaring a measured match.

Suggested delivery contract:

1. Retain the source profile and editable master. Choose the web delivery space explicitly; sRGB is a conservative default, not a guarantee of identical devices.
2. Convert through the intended color-managed route, then map to the final fixed palette if required. Recheck palette membership after any later conversion.
3. Inspect gamut compression/clipping on the focal accent and neighboring ramp steps. Channel clipping can collapse distinct colors or shift their relationship; a larger working gamut alone does not preserve them in an sRGB export.[10]
4. Export PNG with consistent color-space metadata for the intended encoding. Inspect actual chunks/profile rather than relying on a filename or export preset. Do not add conflicting profiles or metadata; PNG defines their interpretation.[11]
5. Decode the exported file and compare dimensions, alpha and color values to the intended final raster. Test edge compositing on actual host backgrounds.
6. Review the delivered image in a color-managed application and its real browser/layout. Record devices/apps tested. Platform transcoding, uncalibrated displays, ambient light and user display settings limit any universal appearance claim.

**Keep claims separate:** “the file contains these RGB values,” “the profile says sRGB,” “this browser matched the reference on this display,” and “the printed object matches under measured viewing conditions” are different findings. Only the first two can be established by file inspection alone.

For branded use, this chapter supplies technique only. Obtain numerical colors from the project's canonical tokens; keep any expanded illustration palette explicitly separate. No hexadecimal example here creates a brand role.

## Sources

[1] https://pixeljoint.com/forum/forum_posts.asp?TID=11299 — Pixel Joint Forum: The Pixel Art Tutorial
[2] https://medium.com/pixel-grimoire/how-to-start-making-pixel-art-6-a74f562a4056 — How to start making pixel art #6. Basic Color Theory | by Pedro Medeiros | Pixel Grimoire | Medium
[6] https://www.aseprite.org/docs/color-profile — Aseprite - Docs - Color-profile
[7] https://pbr-book.org/4ed/Reflection_Models — Reflection Models
[9] https://pbr-book.org/4ed/Light_Sources/Area_Lights — Area Lights
[10] https://www.w3.org/TR/css-color-4 — CSS Color Module Level 4
[11] https://www.w3.org/TR/png-3 — Portable Network Graphics (PNG) Specification (Third Edition)
[13] https://pbr-book.org/4ed/Reflection_Models/Specular_Reflection_and_Transmission — Specular Reflection and Transmission
[14] https://pbr-book.org/4ed/Reflection_Models/Diffuse_Reflection — Diffuse Reflection
[15] https://pbr-book.org/4ed/Light_Transport_I_Surface_Reflection/The_Light_Transport_Equation — The Light Transport Equation
