C-Log3 puts 18% middle grey at 33.10% of the code range. That is the lowest of the eight log formats this site's transform library implements, and it sits 7.96 points below where S-Log3 puts the same grey card. Carry the wrong one of those two numbers onto a stage and your exposure is 0.92 stops out before you have touched anything else.
Every figure below is computed from public/js/color-transforms.js, the transform library this site ships and the previewer runs. Nothing here is about a camera body. The curve in that file is a fixed function of scene reflectance with no gain or ISO term in it, so these are properties of the format, and they are the same on every camera that writes it.
Where the curve puts middle grey
| Scene value | C-Log3 code value |
|---|---|
| Zero reflectance (linear 0) | 12.51% |
| Toe cut, linear 0.014 — 3.68 stops under grey | 15.28% |
| 2 stops under middle grey | 20.46% |
| Middle grey, 18% reflectance | 33.10% |
| 90% white card | 54.88% |
| Display white in this site's chain (linear 8.0) | 88.72% |
| Ceiling — code value 100% | linear 16.30, i.e. 90.5× grey, 6.50 stops over |
In 10-bit that is code 338.6 of 1023; in 8-bit, 84.4 of 255.
Look at how the container splits. Of the 100 points of code value, 33.10 sit below middle grey and 66.90 above it — and of that lower third, only 20.58 points describe real light, because linear zero already lands at 12.51%. Two thirds of the code range sits above middle grey.
The library derives C-Log3's shadow toe rather than transcribing it: the toe's slope is the log branch's own derivative at the cut, so the join is continuous by construction. Sweeping the decode across 100,001 evenly spaced code values returns zero monotonicity violations — no tone anywhere in the range inverts.
A waveform reading is a stop count in disguise
| Stops from middle grey | C-Log3 code value |
|---|---|
| −4 | 14.73% |
| −3 | 16.87% |
| −2 | 20.46% |
| −1 | 25.86% |
| −0.5 | 29.26% |
| 0 | 33.10% |
| +0.5 | 37.31% |
| +1 | 41.83% |
| +2 | 51.59% |
| +3 | 61.96% |
| +4 | 72.65% |
| +5 | 83.53% |
| +6 | 94.49% |
The spacing is not even, and the direction it leans matters. Near grey the curve runs 0.0807 code per stop — 82.5 ten-bit codes per stop, so a single 10-bit code is 1.21% of a stop. Step a third of a stop up from grey and the waveform moves 2.77 points. You can read a third of a stop off a waveform in this format.
Going up, a stop costs more code value, not less: 8.74 points from 0 to +1, 9.76 from +1 to +2, 10.87 from +4 to +5, converging on 11.06 points per stop as the log branch takes over from the small linear offset inside it. Going down it collapses fast — the whole stop from −4 to −3 is 2.14 points, a quarter of what a stop is worth at grey. Four stops under grey the curve runs 1.54 points per stop, so one point of waveform wobble is 0.65 of a stop of scene light. Shadow readings on a C-Log3 waveform are not precise, and no amount of squinting makes them so.
That asymptote of 11.06 points per stop is also why the format runs out of headroom early — of the eight formats in the library, only Apple Log has less. S-Log3's equivalent is 7.70 points per stop. C-Log3 spends about 44% more code value on each highlight stop, so the same 0–100 container holds fewer of them.
How much room sits above grey
Code value 100% decodes to linear 16.30, which is 6.501 stops over middle grey. That is a property of the container — how much scene range the format's numbers can describe — not a claim about what any sensor captures.
This site's chain runs out earlier than that. The shared shoulder is extended Reinhard with WHITE = 8.0, and the constant is exact: shoulder(8.0) returns 1.0 to the last bit, and the Rec.709 OETF maps 1.0 to 1.0. Linear 8.0 is 44.44× middle grey, or 5.474 stops over. C-Log3 encodes linear 8.0 at 88.72%.
So everything between 88.72% and 100% — 11.28% of the code range, 1.03 stops of scene — converts to flat 255. Every format gives something up here, because Rec.709 has to end somewhere. Only Apple Log gives up less than C-Log3 does — 5.00% of its range against C-Log3's 11.28%. At the other end RED Log3G10 hands over 30.54% and Blackmagic Film Gen5 28.92%.
The shoulder is not only a highlight tool. shoulder(0.18) returns 0.15297 — it pulls middle grey down 15.02% in linear before the OETF sees it. The payoff is that all eight formats land 18% grey on Rec.709 0.373142 — 8-bit 95 for every one of them. Six of the eight agree to within 1.1 × 10⁻¹⁶. The two that drift are ARRI LogC3, by 1.8 × 10⁻⁷, and Apple Log, by 1.8 × 10⁻⁵, and they are exactly the two whose matrix rows sum to 1.0 only approximately — off by 1 × 10⁻⁶ and 1 × 10⁻⁴. Eight different curves converging on one display value is the cross-check that the transforms agree with each other.
What the Cinema Gamut matrix does, and what it does not
C-Log3 carries the Cinema Gamut → Rec.709 matrix. Its rows sum to 1.0 exactly — the worst deviation across the three rows is 2.2 × 10⁻¹⁶, which is floating-point dust, not error.
What that buys is precise and narrow: a neutral in is a neutral out. Feed the matrix [0.18, 0.18, 0.18] and all three channels come back 0.18 to within 3 × 10⁻¹⁷ — double-precision rounding and nothing else — because when the three inputs are equal each row computes the same weighted sum. Grey stays grey at every level.
What it does not do is touch a colour cast — neither remove one nor preserve one:
| Camera-linear in | Rec.709-linear out | R/B ratio in → out |
|---|---|---|
| Neutral 0.180 / 0.180 / 0.180 | 0.1800 / 0.1800 / 0.1800 | 1.000 → 1.000 |
| Warm wash 0.360 / 0.180 / 0.180 | 0.4883 / 0.1567 / 0.1820 | 2.000 → 2.683 |
| Magenta 0.240 / 0.120 / 0.300 | 0.2612 / 0.0994 / 0.3576 | 0.800 → 0.730 |
| Blue wash 0.120 / 0.140 / 0.360 | 0.0271 / 0.1364 / 0.4286 | 0.333 → 0.063 |
The warm wash leaves 34% warmer by red-to-blue ratio. The blue wash leaves with its R/B ratio divided by 5.3. A cast that is in the file when the matrix runs comes out changed in size and still there. That is the arithmetic reason the FAQ on this site's homepage puts primary exposure and white balance on node 1, on the native log image, and the transform on node 2. There is a longer walk-through in log to Rec.709 conversion done right.
One more consequence of the coefficients, which run from +1.7127 down to −0.3573: a saturated input can leave the matrix with a negative channel. Push the three pure primaries — [1, 0, 0], [0, 1, 0], [0, 0, 1] — through the C-Log3 matrix and every one of them comes out with at least one negative channel, and the same holds for all eight matrices in the library. toRec709() clamps negatives to zero, and that clamp is where saturated stage colour loses its shape. Stage lasers, LED walls and clipping covers what to do about it.
The spread across eight formats
| Format | 18% grey | 10-bit code | Headroom to code 1.0 | 10-bit codes/stop at grey | Code at display white |
|---|---|---|---|---|---|
| Canon C-Log3 | 33.10% | 338.6 | 6.50 stops | 82.3 | 88.72% |
| RED Log3G10 | 33.33% | 341.0 | 10.00 | 63.2 | 69.46% |
| Blackmagic Film Gen5 | 38.36% | 392.4 | 10.27 | 59.8 | 71.08% |
| ARRI LogC3 | 39.10% | 400.0 | 8.26 | 72.3 | 79.30% |
| DJI D-Log M | 39.88% | 407.9 | 7.87 | 74.4 | 81.53% |
| Sony S-Log3 | 41.06% | 420.0 | 7.74 | 74.5 | 82.59% |
| Panasonic V-Log | 42.33% | 433.0 | 8.00 | 70.9 | 81.64% |
| Apple Log | 48.83% | 499.5 | 6.06 | 82.9 | 95.00% |
Codes per stop is a centred difference across one stop at grey — encode(0.18·√2) − encode(0.18/√2), ×1023 — the same definition the RED Log3G10 page states. An instantaneous slope at grey reads about 0.1 higher on the steeper formats; this measures the code budget a whole stop actually gets. The grey targets span 15.73 points, from C-Log3 at the bottom to Apple Log at the top. That spread is the whole point of this page, because a waveform target is not transferable:
| You meter C-Log3 to… | which is correct for | Real C-Log3 exposure |
|---|---|---|
| 33.10% | Canon C-Log3 | 0.00 stops |
| 33.33% | RED Log3G10 | +0.03 |
| 38.36% | Blackmagic Film Gen5 | +0.62 |
| 39.10% | ARRI LogC3 | +0.70 |
| 39.88% | DJI D-Log M | +0.79 |
| 41.06% | Sony S-Log3 | +0.92 |
| 42.33% | Panasonic V-Log | +1.05 |
| 48.83% | Apple Log | +1.72 |
The homepage tip that middle grey sits at 41% is for S-Log3, and computing S-Log3's encode at 0.18 gives 41.06%, so that tip is right. It is simply the wrong number for this format, by nearly a stop.
The error is not symmetric, either, because the curves have different slopes. Shooting C-Log3 and metering to S-Log3's 41.06% overexposes by 0.92 stops. Shooting S-Log3 and metering to C-Log3's 33.10% underexposes by 1.12 stops. Same code-value gap, different cost.
What this means when you are shooting
Only what the arithmetic above supports:
- Nominal is 33%. An 18% grey card, under the light you are actually shooting, reads 33.1% on a waveform watching the C-Log3 signal. A 90% white card reads 54.88%, which is 2.32 stops over grey.
- Count exposure offsets in points, not by eye. Above grey, +1 stop is +8.74 points, +2 is +18.50, +3 is +28.86. A third of a stop is 2.77 points. If you choose to expose to the right, you can place it exactly rather than approximately.
- Do not read shadows off the waveform. A whole stop is 2.14 points between −4 and −3, and 1.11 points between −5 and −4. That region is for your eyes, not for a numeric target.
- You have 5.47 stops between nominal grey and the point this site's conversion reaches 255. Expose a stop to the right and 4.47 remain; make the S-Log3 mistake instead and 4.56 remain. That is the budget a bright LED wall or a hard key eats into.
- Never reuse another format's number. The table above is the price list.
Correct exposure and white balance on the native log image, convert, then apply the look. That is the order the homepage FAQ gives, and the matrix behaviour above is one of the reasons for it.
Picking a conversion LUT for C-Log3
A baked conversion LUT samples the curve on a lattice and straight-line interpolates between the nodes — trilinear, exactly as sample() in middleware/lutprofile.js does it. On the C-Log3 code axis near middle grey, one node gap is worth:
| Lattice | Node gap | Stops of scene per gap, centred on grey | Gaps between grey and display white |
|---|---|---|---|
| 17³ | 0.0625 | 0.778 stops | 8.9 |
| 33³ | 0.03125 | 0.388 | 17.8 |
| 65³ | 0.015625 | 0.194 | 35.6 |
Doubling the lattice halves the interval the interpolator has to guess across. The uploader accepts lattices from 8 to 65 (middleware/lutfile.js). Reading LUT_3D_SIZE off all 60 published LUTs gives 16³ ×5, 17³ ×29, 32³ ×16, 33³ ×8 and 65³ ×2. The log to Rec.709 conversions are baked at 33³ from this same library. More background in the Academy and in S-Log3 exposure, read off the curve.
How these numbers were produced
Every colour figure above comes from public/js/color-transforms.js, run under Node. To reproduce: const CT = require('./public/js/color-transforms.js'), then
- grey code value:
CT.encode('Canon C-Log3', 0.18) - headroom:
Math.log2(CT.decode('Canon C-Log3', 1.0) / 0.18) - the stop ladder:
CT.encode('Canon C-Log3', 0.18 2 * s)for each s - codes per stop at grey: a central difference of
encodeat ±0.001 stop, × 1023 - display white:
CT.encode('Canon C-Log3', CT.WHITE), withCT.shoulder(CT.WHITE)confirming the shoulder returns exactly 1.0 there - matrix rows:
CT.matrix('Canon C-Log3'), each row summed; the cast table isCT.applyMatrix(CT.matrix('Canon C-Log3'), triplet)on the listed triplets - the cross-format table:
CT.decode('Canon C-Log3', CT.encode(other, 0.18)), converted to stops against 0.18 - the whole chain:
CT.toRec709('Canon C-Log3', [c, c, c]) - the negative channels:
CT.applyMatrix(CT.matrix(cam), p)for each pure primaryp - the lattice table: with
g = CT.encode('Canon C-Log3', 0.18)andgap = 1/(N-1),Math.log2(CT.decode('Canon C-Log3', g + gap/2) / CT.decode('Canon C-Log3', g - gap/2))
The catalogue counts are not from that file. They are LUT_3D_SIZE read from /api/luts/:id/cube-meta for every id the public listing returns, which is 60 ids and does not touch the download counter.
Round-tripping decode(encode(0.18)) returns 0.18 for all eight formats with residuals at or below 8.3 × 10⁻¹⁷, which is what makes the constants trustworthy in the first place.
Sources
- The transform library this site ships — the C-Log3 decode and encode curve with its derived toe, the Cinema Gamut → Rec.709 matrix, the shared extended-Reinhard shoulder that white-points at linear 8.0, the Rec.709 OETF, and the clamp on negative channels. Every number on this page is computed from that one file.
- The LUT validator — the accepted lattice range of 8 to 65 and the reason for each bound.
- The LUT profiler — the trilinear sampling the lattice table is reasoning about, which is the same interpolation the preview renderer uses.
- The site's colour-pipeline notes — the six 33³ technical conversion LUTs, and 0.3310 recorded as C-Log3's grey anchor.
- The site's own public catalogue API — the lattice size of each of the 60 published LUTs, which is where the 16³/17³/32³/33³/65³ counts come from.
- The homepage tips and FAQ — the 41% S-Log3 target quoted for comparison, and the node order that puts exposure and white balance on the log image before the transform.