Color grading library with LUT loading machinery, cinematic grades, and film-stock approximations
Project description
color-fx
Color grading library with 60 grades, full LUT machinery, and optional ACES support.
Install
pip install color-fx
That pulls in pydantic, numpy, Pillow, opencv-python-headless, and ffmpeg-python (~80 MB). You also need ffmpeg >= 6.0 on your PATH.
Extras:
| Extra | What it adds | Approx size |
|---|---|---|
pip install color-fx[sklearn] |
scikit-image + scikit-learn for KMeans skin-tone refinement | ~140 MB |
pip install color-fx[aces] |
colour-science + OpenColorIO for ACES and BT.2020 workflows | ~250 MB |
pip install color-fx[all] |
Both of the above | ~310 MB |
The base install works without either extra.
5-minute tour
Apply a named grade to a video:
from color_fx import apply_grade, GradeConfig
apply_grade(
video="raw.mp4",
grade="nordic_desaturation_standard",
output="graded.mp4",
config=GradeConfig(
grade="nordic_desaturation_standard",
intensity_override=0.6,
preserve_skin_tones=True,
),
)
Load and apply your own LUT:
from color_fx import load_lut, apply_lut
lut = load_lut("/path/to/MyKodak2383.cube")
apply_lut(video="raw.mp4", lut=lut, output="graded.mp4", strength=0.8)
Chain multiple grades in one pass:
from color_fx import apply_grade_chain
apply_grade_chain(
video="raw.mp4",
grades=[
{"grade": "log_to_rec709"},
{"grade": "warm_print_film_inspired"},
{"grade": "shadow_lift", "config": {"intensity_override": 0.3}},
],
output="layered.mp4",
)
The 60 grades
Three categories. 60 slugs total.
cinematic_grades (30)
Ten cinematic looks, each in three intensities: subtle (0.35), standard (0.70), bold (1.0).
| Slug | Display name |
|---|---|
nordic_desaturation_subtle |
Nordic Desaturation — Subtle |
nordic_desaturation_standard |
Nordic Desaturation — Standard |
nordic_desaturation_bold |
Nordic Desaturation — Bold |
golden_hour_subtle |
Golden Hour — Subtle |
golden_hour_standard |
Golden Hour — Standard |
golden_hour_bold |
Golden Hour — Bold |
cold_steel_subtle |
Cold Steel — Subtle |
cold_steel_standard |
Cold Steel — Standard |
cold_steel_bold |
Cold Steel — Bold |
warm_contrast_subtle |
Warm Contrast — Subtle |
warm_contrast_standard |
Warm Contrast — Standard |
warm_contrast_bold |
Warm Contrast — Bold |
muted_earth_subtle |
Muted Earth — Subtle |
muted_earth_standard |
Muted Earth — Standard |
muted_earth_bold |
Muted Earth — Bold |
high_contrast_bw_subtle |
High Contrast B&W — Subtle |
high_contrast_bw_standard |
High Contrast B&W — Standard |
high_contrast_bw_bold |
High Contrast B&W — Bold |
cyberpunk_neon_subtle |
Cyberpunk Neon — Subtle |
cyberpunk_neon_standard |
Cyberpunk Neon — Standard |
cyberpunk_neon_bold |
Cyberpunk Neon — Bold |
natural_flat_subtle |
Natural Flat — Subtle |
natural_flat_standard |
Natural Flat — Standard |
natural_flat_bold |
Natural Flat — Bold |
deep_shadows_subtle |
Deep Shadows — Subtle |
deep_shadows_standard |
Deep Shadows — Standard |
deep_shadows_bold |
Deep Shadows — Bold |
summer_fade_subtle |
Summer Fade — Subtle |
summer_fade_standard |
Summer Fade — Standard |
summer_fade_bold |
Summer Fade — Bold |
film_stock_emulation (15)
Nine base film-stock approximations plus six cross-stock combination grades.
Film stock approximations — entries in the
film_stock_emulationcategory (Warm Print Film, Cool Cinematic Stock, Punchy Consumer Film, Grainy Black and White Stock, Instant Photo Vintage, Super 8 Film, 16mm Documentary, 35mm Prestige, Saturated Three-Strip Look, Expired Film, and the cross-stock combos) are approximations based on publicly-documented characteristics of named film stocks. They are NOT licensed or measured emulations. For production-grade film emulation requiring true spectral measurements, use commercial offerings (Kharma, FilmUnlimited, Cinematch).
| Slug | Display name |
|---|---|
warm_print_film_inspired |
Warm Print Film |
cool_cinematic_stock |
Cool Cinematic Stock |
punchy_consumer_film |
Punchy Consumer Film |
grainy_bw_stock |
Grainy Black and White Stock |
instant_photo_vintage |
Instant Photo Vintage |
super8_film |
Super 8 Film |
16mm_documentary |
16mm Documentary |
35mm_prestige |
35mm Prestige |
saturated_three_strip |
Saturated Three-Strip Look |
expired_film |
Expired Film |
cross_warm_cool |
Cross: Warm Print + Cool Cinematic |
cross_punchy_prestige |
Cross: Punchy Consumer + 35mm Prestige |
cross_super8_bw |
Cross: Super 8 + Grainy B&W |
cross_vintage_expired |
Cross: Instant Photo + Expired Film |
cross_documentary_prestige |
Cross: 16mm Documentary + 35mm Prestige |
luts_and_curves (15)
Pure math operations: S-curves, log conversions, channel adjustments.
| Slug | Display name |
|---|---|
log_to_rec709 |
Log to Rec.709 |
s_curve_gentle |
S-Curve (Gentle) |
s_curve_strong |
S-Curve (Strong) |
shadow_lift |
Shadow Lift |
highlight_rolloff |
Highlight Rolloff |
split_tone_warm_cool |
Split Toning: Warm Shadows / Cool Highlights |
split_tone_cool_warm |
Split Toning: Cool Shadows / Warm Highlights |
gamma_correction_rec709 |
Gamma Correction (Rec.709) |
channel_mixer_warm |
Channel Mixer: Warm |
channel_mixer_cool |
Channel Mixer: Cool |
hsl_vibrance |
HSL Vibrance |
hsl_saturation_boost |
HSL Saturation Boost |
crush_blacks |
Crush Blacks |
lift_shadows_matte |
Lift Shadows (Matte) |
identity |
Identity (pass-through) |
LUT loading
No bundled LUTs — color-fx ships LUT machinery (read, apply, bake, interpolate) but does NOT ship any
.cubefiles. Bring your own LUTs from free repositories (FreshLuts, Lutify.me free pack) or commercial vendors.
Read .cube or .3dl files:
from color_fx import load_lut, save_lut, apply_lut, bake_grade_to_lut
lut = load_lut("/path/to/MyGrade.cube") # or .3dl
print(lut.title, lut.size, lut.dimensions) # e.g. "My Grade" 33 3
apply_lut(video="raw.mp4", lut=lut, output="out.mp4", strength=0.85)
Bake any named grade out to a .cube file for use in DaVinci Resolve or Premiere:
bake_grade_to_lut(grade="nordic_desaturation_bold", output="nordic_bold.cube", size=33)
save_lut(lut, "custom.cube", title="My Custom Grade")
Convert between formats:
from color_fx.lut import convert_lut
convert_lut(input="my_grade.3dl", output="my_grade.cube")
Both trilinear and tetrahedral 3D-LUT interpolation are available. Tetrahedral is the default and is more accurate for most film-print-style grades.
ACES note: with pip install color-fx[aces], you can specify working_color_space="ACEScg" in
GradeConfig and the library routes the transform through OpenColorIO automatically. Without the
extra, that field is accepted but ignored and the library processes in Rec.709.
Engines
Three base engines cover all 60 grades:
| Engine | Module | Grades |
|---|---|---|
grade_recipe |
engines/grade_recipe.py |
30 cinematic grades (10 looks × 3 intensities) |
film_emulation |
engines/film_emulation.py |
15 film-stock approximations (9 base + 6 cross combos) |
curve_or_lut |
engines/curve_or_lut.py |
15 LUT and curve primitives |
Each grade recipe computes an internal 33x33x33 or 65x65x65 LUT at startup and caches it for the duration of a render. The film emulation engine also drives a grain overlay and optional halation simulation on top of the grade LUT.
GradeConfig
All API functions accept an optional GradeConfig. Every field has a safe default.
| Field | Type | Default | Description |
|---|---|---|---|
grade |
str |
— | Grade slug (required) |
intensity_override |
float | None |
None |
Override catalog intensity, 0–1 |
region |
tuple[int,int,int,int] | None |
None |
Apply only within (x, y, w, h) |
mask_image |
str | None |
None |
Path to a greyscale mask image |
preserve_skin_tones |
bool |
False |
HSV-based skin-tone protection |
lut_strength |
float |
1.0 |
Blend between identity (0) and full LUT (1) |
interpolation |
"trilinear" | "tetrahedral" |
"tetrahedral" |
3D LUT interpolation method |
working_color_space |
"Rec.709" | "Rec.2020" | "ACES2065-1" | "ACEScg" |
"Rec.709" |
Requires [aces] for non-Rec.709 |
display_color_space |
"Rec.709" | "Rec.2020" | "P3-D65" |
"Rec.709" |
Output color space |
video_codec |
str |
"libx264" |
ffmpeg video codec |
audio_codec |
str |
"copy" |
ffmpeg audio handling |
The model uses extra="forbid", so passing unknown fields raises a validation error at call time
rather than silently doing the wrong thing.
CLI
All subcommands accept --help.
Apply a grade:
color-fx apply --video raw.mp4 --grade nordic_desaturation_standard --out graded.mp4
color-fx apply --video raw.mp4 --grade warm_print_film_inspired --intensity 0.5 --out out.mp4
Chain grades from a YAML config:
color-fx chain --video raw.mp4 --config chain.yaml --out out.mp4
LUT operations:
color-fx apply-lut --video raw.mp4 --lut my.cube --strength 0.8 --out graded.mp4
color-fx bake-lut --grade warm_print_film_inspired --size 33 --out warm_print.cube
color-fx convert-lut --input my.3dl --output my.cube
Catalog discovery:
color-fx list # all 60 grades, one slug per line
color-fx list --category cinematic_grades # 30 grades in that category
color-fx list --include-skipped # 60 + 15 video-fx-overlap stubs with redirect notes
color-fx categories # prints the 3 category names
color-fx info nordic_desaturation_bold # full metadata, disclaimer if film stock
ACES (requires [aces] extra):
color-fx aces list
color-fx aces apply --video raw.mp4 --view "ACES 1.1 SDR Video" --out aces.mp4
Preview (generates a synthetic gradient video to inspect the grade):
color-fx preview --grade vintage_film_fade_standard --out preview.mp4
Schema (for LLM integration):
color-fx schema --pretty
Composition
color-fx is a peer of optic-fx, video-fx, and cut-fx. It does not import any of them.
A typical pipeline:
import subprocess
# 1. Cut and assemble with cut-fx / video-fx
# 2. Color grade with color-fx
from color_fx import apply_grade
apply_grade(video="assembled.mp4", grade="nordic_desaturation_standard", output="graded.mp4")
# 3. Add optical effects with optic-fx
from optic_fx import apply_effect
apply_effect(video="graded.mp4", effect="anamorphic_lens_flare_standard", output="final.mp4")
color-fx intentionally does NOT include Teal and Orange, Bleach Bypass, or other grades that
overlap with video-fx's cinematic_color category. Use video_fx.apply_effect("teal_and_orange")
for those. Running color-fx list --include-skipped shows each overlap slug and the exact
video-fx call to use instead.
Disclaimers
Film stock approximations — entries in the film_stock_emulation category are approximations
based on publicly-documented characteristics of named film stocks. They are NOT licensed or
measured emulations. The library carries explicit disclaimer text in the catalog for every
film-stock entry; get_grade_info() and color-fx info <slug> surface this text at runtime.
No bundled LUTs — color-fx ships LUT machinery but does not ship any .cube files.
ACES pathway — the optional ACES OCIO config is NOT bundled in the wheel. It is downloaded
at first use when the [aces] extra is installed. Internet access is required the first time.
What this is NOT
- Not a real-time preview tool. It processes video files via ffmpeg.
- Not a video editor or timeline tool. Use cut-fx or video-fx for that.
- Not a licensed film-emulation product. Film stocks are approximations only.
- Not a replacement for DaVinci Resolve's node-based pipeline. It is a Python library for programmatic and batch color grading.
- Not affiliated with or endorsed by any film stock manufacturer or camera brand.
Provenance
Built at Trollfabriken AITrix AB for the CineForge pipeline cinematic grading work, AIMOS Insight municipal report visual polish, SocKartan civic-transparency stylization, and the Timelock Film AB festival slate's color-grading pass.
Source: https://github.com/tomastimelock/color-fx PyPI: https://pypi.org/project/color-fx/ License: MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file color_fx-0.1.0.tar.gz.
File metadata
- Download URL: color_fx-0.1.0.tar.gz
- Upload date:
- Size: 154.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
891bf21afffb4a0a5242f10db80e1bb7fcf1ef63d54c8fc7b4e6029314fe5fdb
|
|
| MD5 |
c3741ed355706099fd7298a8fafb627e
|
|
| BLAKE2b-256 |
b95520d2f1b400e03b32b0e8f6c4126fef98d8d3369164c1dbc5b526af99ea54
|
Provenance
The following attestation bundles were made for color_fx-0.1.0.tar.gz:
Publisher:
release.yml on tomastimelock/color-fx
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
color_fx-0.1.0.tar.gz -
Subject digest:
891bf21afffb4a0a5242f10db80e1bb7fcf1ef63d54c8fc7b4e6029314fe5fdb - Sigstore transparency entry: 1629728253
- Sigstore integration time:
-
Permalink:
tomastimelock/color-fx@a143f68abcfe205f6f908fd6a86e64db41cde302 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/tomastimelock
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a143f68abcfe205f6f908fd6a86e64db41cde302 -
Trigger Event:
push
-
Statement type:
File details
Details for the file color_fx-0.1.0-py3-none-any.whl.
File metadata
- Download URL: color_fx-0.1.0-py3-none-any.whl
- Upload date:
- Size: 68.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
793696978ece206fc53e3237ef96a0d8242048efb793cdb0834a0ad54b5611ee
|
|
| MD5 |
9d47e850e37109d3a5a142fcef1b49bb
|
|
| BLAKE2b-256 |
2b1b9049c6243d152496d71e1e7bc67fa9f9cd1e63909695ac404310b709aaf1
|
Provenance
The following attestation bundles were made for color_fx-0.1.0-py3-none-any.whl:
Publisher:
release.yml on tomastimelock/color-fx
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
color_fx-0.1.0-py3-none-any.whl -
Subject digest:
793696978ece206fc53e3237ef96a0d8242048efb793cdb0834a0ad54b5611ee - Sigstore transparency entry: 1629728286
- Sigstore integration time:
-
Permalink:
tomastimelock/color-fx@a143f68abcfe205f6f908fd6a86e64db41cde302 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/tomastimelock
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@a143f68abcfe205f6f908fd6a86e64db41cde302 -
Trigger Event:
push
-
Statement type: