# Color

> How OWG records an asset's color space and the ACES viewing pipeline that renders it, using the ASWF Color Interop ID, ACES transform IDs and the ACES Metadata File, without carrying any color math.

**Status:** v0.94 (draft, published for review). A typed `asset.color` field, with one validator rule and the existing reference checks.

## What the color standards define

Four pieces of the Academy Software Foundation and ACES work fit together:

- **The Color Interop ID.** The ASWF [Color Interop Forum](https://github.com/AcademySoftwareFoundation/ColorInterop) publishes one string per common color space, such as `lin_ap1_scene` or `srgb_rec709_display`, with rules for namespacing any other color space ([Recommendation v1.0.0](https://github.com/AcademySoftwareFoundation/ColorInterop/blob/main/Recommendations/03_ColorInteropID/ColorInteropID.md), July 2026). OpenEXR carries it as the `colorInteropID` header attribute from 3.5. OpenColorIO carries it as a color space's `interop_id` from 2.5. Other file formats are expected to follow.
- **ACES transform IDs.** Every official ACES transform has a URN, such as `urn:ampas:aces:transformId:v2.0:Output.Academy.Rec709-D65_100nit_in_Rec709-D65_BT1886.a2.v1`. ACES publishes them in a machine-readable [registry](https://github.com/aces-aswf/aces/blob/main/transforms.json) that also maps each ACES 1.x ID to its 2.0 equivalent.
- **The ACES Metadata File (AMF).** An XML sidecar that records a shot's viewing pipeline: input transform, looks (often an ASC CDL) and output transform, each marked as already applied to the pixels or not. See the [AMF specification](https://docs.acescentral.com/amf/specification/).
- **OpenColorIO configs.** A show's config names its color spaces, displays and views. A config's own `name` is also the namespace the Color Interop ID uses for config-local color spaces.

## The hook

Color sits on the **asset**, as references only. OWG says *which* color space and *which* transforms. It never carries matrices, LUT values or transform code.

```json
{
  "id": "plate_040_0010",
  "type": "image",
  "role": "plate",
  "color": {
    "interop_id": "lin_ap0_scene",
    "input_transform": { "transform_id": "urn:ampas:aces:transformId:v2.0:CSC.Academy.ACEScct_to_ACES.a2.v1", "applied": true },
    "look_transforms": [{ "asset": "plate_cdl", "applied": false }],
    "output_transform": { "transform_id": "urn:ampas:aces:transformId:v2.0:Output.Academy.Rec709-D65_100nit_in_Rec709-D65_BT1886.a2.v1", "applied": false },
    "amf": "plate_amf",
    "ocio_config": "show_config"
  }
}
```

| Key in `color` | From | Holds |
|---|---|---|
| `interop_id` | Color Interop Forum (OpenEXR `colorInteropID`, OpenColorIO `interop_id`) | The color space of the asset's color pixels |
| `input_transform` | AMF `inputTransform` | The transform into the working space |
| `look_transforms[]` | AMF `lookTransform`, in order | Creative looks, often an ASC CDL |
| `output_transform` | AMF `outputTransform` | The transform for viewing on a display |
| `amf` | | The AMF asset the pipeline was read from |
| `ocio_config` | | The OpenColorIO config asset the `interop_id` resolves against |

Each transform names an ACES `transform_id`, or the `asset` that holds it (a CDL, LUT or CLF file in the assets registry), or both. `applied` mirrors AMF: `true` when the transform is already baked into the pixels, `false` when it is still to be applied for viewing. Unknown keys are rejected. Extensions use the `x-` prefix, as everywhere in OWG.

The files themselves (AMF, CDL, LUT, config) are ordinary assets, so they version, carry provenance and travel in turnovers like anything else. In OMC terms, they are assets of structural type `color.cdl`, `color.lut`, `color.colorSpace` and `configuration.colorSpace`.

Four rules keep the record honest:

- **Never guess a color space.** When it is not known, write `unknown`. Never write a default such as `lin_rec709_scene`. This is the Forum's own rule for OpenEXR, and it holds here.
- **Use `data` for pixels that are not color,** such as normals, IDs, depth and mattes.
- **Don't forward color facts across a change.** When a task changes an asset's color space, the produced asset gets its own `color`. It does not inherit its predecessor's.
- **Keep transform IDs as written.** An ACES 1.x ID stays as the source wrote it. An implementation may map it forward using the registry's `previousEquivalentTransformIds`, but the document records what was read.

## The Color Interop ID rule (v0.94)

The schema checks the ID's form: lower-case ASCII, the Forum's allowed punctuation, and at most two `:` namespace separators. One rule needs the validator:

| `interop_id` | Result |
|---|---|
| A published ID, e.g. `lin_ap1_scene`, `srgb_rec709_display`, `data`, `unknown` | Passes |
| A namespaced ID, e.g. `my-studio:show-log`, `show-config:local:srgb`, `ocio:arrilogc4_awg4_scene` | Passes |
| A bare ID the Forum has not published, e.g. `arrilogc4_awg4_scene` | `OWG_COLOR_INTEROP_ID_UNPUBLISHED` |
| Upper case, spaces, three separators, or an empty base | `OWG_SCHEMA_ERROR` |

The rule exists because a bare ID is a claim that the Forum defined it. Anyone else's color space needs a namespace, or two parties could mean different things by the same name. The validator's list of published IDs is generated from the Forum's own recommendation configs, and it changes only when the Forum publishes more.

The `amf`, `ocio_config` and transform `asset` references resolve like any other asset reference (`OWG_UNKNOWN_REFERENCE`).

## With OpenTimelineIO and OpenEXR

- **OpenTimelineIO.** A clip in a cut is identified by scope `otio.clip`, as clip name plus source range. OTIO has no persistent clip ID, so treat a match on it as low assurance. OTIO's own roadmap adds color to its schema. When that lands, OTIO and OWG share the Color Interop ID, so clip color maps across without translation.
- **OpenEXR.** An implementation that reads a file's `colorInteropID` can record it as `interop_id` unchanged. A multi-part file whose data channels sit in a separate part tagged `data` (as the Forum recommends) is two assets, or one asset plus a `data` part, whichever the workflow needs to govern.

## Identifier scopes

v0.94 documents three scopes for [identifier pass-through](/standards-bindings#1-identifier-pass-through):

| Scope | Identifies |
|---|---|
| `aces.amf` | An AMF, by its `amfInfo` UUID |
| `ocio.config` | An OpenColorIO config, by its `name` |
| `otio.clip` | An OpenTimelineIO clip, as clip name plus source range |

## Reference workflow

[`aces-vfx-shot-color.owg.json`](/corpus/aces-vfx-shot-color.owg.json): a VFX shot on an ACES show. The plate arrives as an OpenEXR sequence with an AMF and the show config. A compositor delivers the comp and its mattes (tagged `data`), and editorial reviews the comp in the cut through the plate's look and output transform.

## Known gaps

- **Transform IDs are not checked against the ACES registry.** The registry is large, and it grows with each ACES release. Checking it is left to tooling.
- **A config-local ID is not resolved.** The validator does not open the referenced OpenColorIO config to check that an `interop_id` exists in it.
- **Color covers whole assets.** A per-shot color change inside one timeline is expressed by the clips' own assets, not by regions of one asset.

See also: [Standards bindings](/standards-bindings), [Assets and versioning](/assets-and-versioning), [IPTC](/iptc), [Validation](/validation), [Changelog](/changelog).
