๐Ÿ— KeyzHub
19Keys ยท community archive
25667 bytes raw
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
#!/usr/bin/env python3
"""luxury_render.py โ€” cinematic "luxury" clip treatment in 19Keys BLACK + GOLD.
Filmic grade (lifted rich blacks, gold-warm highlights, muted sat) + soft bloom +
vignette + fine grain + a thin gold frame + an elegant Didot caption with a gold
hairline + a small 19 KEYS mark. 9:16 vertical, speaker-tracked crop.

    python3 luxury_render.py --video SRC --start 2947 --end 2956 \
        --title "I CHOOSE NOT TO ENGAGE IN POLITICS" --out out.mp4
"""
import argparse
import hashlib
import re
import shutil
import subprocess
import sys
import tempfile
from pathlib import Path

FF = "/opt/homebrew/opt/ffmpeg-full/bin/ffmpeg"
FFPROBE = "/opt/homebrew/opt/ffmpeg-full/bin/ffprobe"   # NOT FF.replace("ffmpeg","ffprobe"):
                                                        # that also mangles "ffmpeg-full" in the path
DIDOT = "Didot"                      # libass matches by family name
GOLD = "0xD4AF37"                    # brand gold (ffmpeg 0xRRGGBB)
CREAM = "&H00E8ECF2"                 # ASS BGR cream-white
GOLD_ASS = "&H0037AFD4"              # ASS BGR of #D4AF37

# Two registers of luxury:
#  cinematic โ€” rich, moody, framed (A24-ish); gold in the highlights, gold frame.
#  quiet     โ€” "The Blue" quiet luxury: muted cohesive grade, near-monochrome, extreme
#              restraint โ€” no frame, one hairline, a whisper of gold. Power via understatement.
MODES = {
    "cinematic": {
        "grade": ("curves=r='0/0.0 0.5/0.5 0.85/0.9 1/1':g='0/0.0 0.5/0.49 1/0.98':b='0/0.012 0.5/0.475 1/0.95',"
                  "eq=contrast=1.12:saturation=0.93:gamma=0.97:brightness=-0.02,"
                  "colorbalance=rh=0.05:gh=0.035:bh=-0.06"),
        "bloom": "split[b0][b1];[b1]gblur=sigma=12[bl];[b0][bl]blend=all_mode=screen:all_opacity=0.13",
        "film": "vignette=PI/4.2,noise=c0s=5:c0f=t+u",
        "frame": True, "cap_size": 58, "cap_spacing": 3.5, "cap_marginv": 300,
    },
    "quiet": {
        "grade": ("curves=r='0/0.015 0.5/0.5 1/0.985':g='0/0.015 0.5/0.5 1/0.985':b='0/0.02 0.5/0.5 1/0.985',"
                  "eq=contrast=1.05:saturation=0.78:gamma=0.99:brightness=-0.015,"
                  "colorbalance=rh=0.03:gh=0.02:bh=-0.03:rm=0.01:bm=-0.01"),
        "bloom": "split[b0][b1];[b1]gblur=sigma=9[bl];[b0][bl]blend=all_mode=screen:all_opacity=0.08",
        "film": "vignette=PI/5.5,noise=c0s=3:c0f=t+u",
        "frame": False, "cap_size": 50, "cap_spacing": 5.5, "cap_marginv": 250,
    },
}


def _ass(title, dur, w, h, size, spacing, marginv, font=DIDOT):
    """Letter-spaced caption (Didot by default; any installed family via --font), centered
    lower-third, slow fade + a whisper 19 KEYS. libass resolves `font` by family name."""
    end = f"{int(dur//3600)}:{int(dur//60)%60:02d}:{dur%60:05.2f}"
    q = title.replace("{", "(").replace("}", ")")
    fn = (font or DIDOT).replace(",", " ")            # ASS Fontname is a bare family name
    return (
        f"[Script Info]\nScriptType: v4.00+\nPlayResX: {w}\nPlayResY: {h}\nWrapStyle: 0\n"
        "ScaledBorderAndShadow: yes\n\n[V4+ Styles]\n"
        "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, "
        "Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, "
        "Shadow, Alignment, MarginL, MarginR, MarginV, Encoding\n"
        f"Style: LUX,{fn},{size},{CREAM},{CREAM},&H00000000,&H64000000,0,0,0,0,100,100,{spacing},0,1,0,4,2,120,120,{marginv},1\n"
        f"Style: MARK,{DIDOT},27,{GOLD_ASS},{GOLD_ASS},&H00000000,&H00000000,0,1,0,0,100,100,6,0,1,0,0,8,0,60,70,1\n\n"
        "[Events]\nFormat: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n"
        f"Dialogue: 0,0:00:00.00,{end},LUX,,0,0,0,,{{\\fad(700,300)}}{q}\n"
        f"Dialogue: 0,0:00:00.00,{end},MARK,,0,0,0,,{{\\fad(900,300)}}19 KEYS\n"
    )


_HERE = Path(__file__).resolve().parent
_LUTS = _HERE / "luts"
# three grades from 19Keys' own LUTs (copied into the studio โ†’ portable)
GRADES = {"cool": _LUTS / "cool.cube",       # teal/muted โ€” The Blue register (default)
          "warm": _LUTS / "warm.cube",        # rust/gold-rich
          "natural": _LUTS / "natural.cube"}  # clean, refined, understated
DEFAULT_GRADE = "cool"
REFRAME_PY = str(_HERE / "reframe-venv" / "bin" / "python")
REFRAME = str(_HERE / "reframe.py")

# ---- masked luxury grade v2 (lux2 / luxury-masked) ---------------------------------
_MASKS = _HERE / "masks"                       # cached power-window ellipse PNGs
_MATTE_CACHE = _HERE / ".matte-cache"          # cached geo.mp4 + matte.mp4 per clip window
_PM_SRC = _HERE / "personmatte.swift"          # Apple Vision person-matte CLI (source)
_PM_BIN = _HERE / "personmatte"                # compiled on first use via swiftc
_ZP_VERSION = "zp-v1"                          # bump when the zoompan expression changes


def _face_crop(video, start, end, W, H):
    """Speaker-tracked crop geometry (falls back to centre)."""
    try:
        import json as _j
        r = subprocess.run([REFRAME_PY, REFRAME, "--video", str(video), "--start", str(start),
                            "--end", str(end), "--aspect", f"{W}:{H}"], capture_output=True, text=True, timeout=120)
        g = _j.loads(r.stdout or "{}").get("crop")
        if g:
            return f"crop={g}"
    except Exception:
        pass
    return f"crop='min(iw,ih*{W}/{H})':'min(ih,iw*{H}/{W})':(iw-ow)/2:(ih-oh)/2"


def render_pure(video, start, end, out, aspect="9:16", grade="cool", lut=None):
    """The purest cut โ€” your real LUT, composed crop, a slow push-in, film halation +
    grain + a whisper of vignette. NO caption, NO logo, NO frame. Pure image, pure restraint."""
    W, H = (1080, 1920) if aspect == "9:16" else (1080, 1080) if aspect == "1:1" else (1920, 1080)
    dur = round(float(end) - float(start), 2)
    # resolve the LUT: explicit path > named grade > default; fall back to a light built-in grade
    lut_path = Path(lut) if lut else GRADES.get(grade, GRADES[DEFAULT_GRADE])
    if lut_path and lut_path.exists():
        lut_esc = str(lut_path).replace(":", r"\:").replace("'", r"\'")
        color = f"lut3d='{lut_esc}'"
    else:
        color = "eq=contrast=1.08:saturation=0.85:gamma=0.98,colorbalance=rh=0.03:bh=-0.04"  # graceful fallback
    fc = _face_crop(video, start, end, W, H)
    # source fps (keep it โ€” 24fps reads cinematic; avoids judder from a resample)
    fps = _probe_fps(video)
    chain = [
        fc, f"scale={W}:{H}",
        color,
        # slow ~5% push-in (centered) โ€” the "expensive" motion, via zoompan
        f"zoompan=z='min(zoom+0.0004,1.05)':d=1:x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':s={W}x{H}:fps={fps}",
        "split[p0][p1];[p1]gblur=sigma=14[pb];[p0][pb]blend=all_mode=screen:all_opacity=0.10",  # halation
        "vignette=PI/5.5,noise=c0s=4:c0f=t+u",
    ]
    vf = ",".join(chain)
    r = subprocess.run(
        [FF, "-y", "-ss", str(start), "-i", str(video), "-t", str(dur),
         "-vf", vf, "-c:v", "libx264", "-crf", "17", "-preset", "slow",
         "-pix_fmt", "yuv420p", "-c:a", "aac", "-b:a", "192k", str(out)],
        capture_output=True, text=True, timeout=1800)
    if not Path(out).exists():
        raise RuntimeError("pure render failed: " + (r.stderr or "")[-500:])
    return str(out)


# ======================================================================================
# masked luxury grade v2
#   TIER 1  render_lux2    โ€” pure ffmpeg: luminance split-tone (gold highlights / cool
#           shadows through soft geq luma masks), skin-protected saturation (reds+yellows
#           excluded by hue qualifier), soft elliptical power-window lift post-zoompan,
#           then the existing halation + vignette + grain film layer.
#   TIER 2  render_masked  โ€” Apple Vision person matte drives a dual grade: subject
#           gold-warm +0.10 stop, world cool -0.20 stop / -40% sat, merged with a
#           feathered matte (maskedmerge). Falls back to Tier 1 if the matte fails.
# ======================================================================================

def _dims(aspect):
    return (1080, 1920) if aspect == "9:16" else (1080, 1080) if aspect == "1:1" else (1920, 1080)


def _probe_fps(video):
    try:
        fr = subprocess.run([FFPROBE, "-v", "error", "-select_streams", "v:0",
                             "-show_entries", "stream=r_frame_rate", "-of", "csv=p=0", str(video)],
                            capture_output=True, text=True, timeout=30).stdout.strip().split("/")
        return round(float(fr[0]) / float(fr[1] if len(fr) > 1 else 1)) or 24
    except Exception:
        return 24


def _nb_frames(video):
    """Frame count of a stream; nb_frames metadata first, packet-count fallback."""
    fp = FFPROBE
    r = subprocess.run([fp, "-v", "error", "-select_streams", "v:0", "-show_entries",
                        "stream=nb_frames", "-of", "csv=p=0", str(video)],
                       capture_output=True, text=True, timeout=30).stdout.strip()
    if r.isdigit():
        return int(r)
    r = subprocess.run([fp, "-v", "error", "-select_streams", "v:0", "-count_packets",
                        "-show_entries", "stream=nb_read_packets", "-of", "csv=p=0", str(video)],
                       capture_output=True, text=True, timeout=120).stdout.strip()
    return int(r) if r.isdigit() else -1


def _zoompan(W, H, fps):
    """The slow 5% push-in. BYTE-IDENTICAL everywhere (v1, lux2, tier-2 geometry bake) โ€”
    the matte is only valid against the exact same motion."""
    return (f"zoompan=z='min(zoom+0.0004,1.05)':d=1:x='iw/2-(iw/zoom/2)'"
            f":y='ih/2-(ih/zoom/2)':s={W}x{H}:fps={fps}")


def _lut_filter(grade, lut=None):
    """Resolve grade/--lut to a lut3d filter string (escaped), eq fallback if missing."""
    lut_path = Path(lut) if lut else GRADES.get(grade, GRADES[DEFAULT_GRADE])
    if lut_path and lut_path.exists():
        esc = str(lut_path).replace(":", r"\:").replace("'", r"\'")
        return f"lut3d='{esc}'"
    return "eq=contrast=1.08:saturation=0.85:gamma=0.98,colorbalance=rh=0.03:bh=-0.04"


def _ellipse_mask(W, H, cy=0.40):
    """Soft elliptical power window, rendered ONCE per resolution and cached as PNG.
    Center 0.5W x cy*H, radii 0.42W/0.30H, wide 0.60-span feather โ€” 'start wide and
    very soft'. cy=0.40 for 9:16 talking head, 0.50 for 1:1/16:9."""
    _MASKS.mkdir(parents=True, exist_ok=True)                     # verify correction
    p = _MASKS / f"ellipse_{W}x{H}_cy{int(cy * 100)}.png"
    if p.exists():
        return p
    src = (f"color=black:s={W}x{H},format=gray,"
           f"geq=lum='255*clip((1.30-sqrt(pow((X-W/2)/(0.42*W),2)"
           f"+pow((Y-{cy}*H)/(0.30*H),2)))/0.60,0,1)'")
    r = subprocess.run([FF, "-y", "-f", "lavfi", "-i", src, "-frames:v", "1",
                        "-update", "1", str(p)],                  # verify correction: -update 1
                       capture_output=True, text=True, timeout=120)
    if not p.exists():
        raise RuntimeError("ellipse mask gen failed: " + (r.stderr or "")[-300:])
    return p


def render_lux2(video, start, end, out, aspect="9:16", grade="cool", lut=None):
    """TIER 1 โ€” masked luxury v2, pure ffmpeg. Node order per the colorist canon:
    secondaries (skin-protected sat, luma split-tone) BEFORE the LUT look, power-window
    lift after zoompan (screen-space), film texture strictly last (hides mask seams).
    Midtones โ€” where skin lives โ€” are excluded from the split-tone by construction."""
    W, H = _dims(aspect)
    dur = round(float(end) - float(start), 2)
    fps = _probe_fps(video)
    color = _lut_filter(grade, lut)
    wm = _ellipse_mask(W, H, 0.40 if aspect == "9:16" else 0.50)
    fc = _face_crop(video, start, end, W, H)
    fg = (
        # out_range=full: geq split points 150/90 are range-dependent โ€” normalize so
        # limited-range sources (tv) hit the same Log-wheel splits (verify correction)
        f"[0:v]{fc},scale={W}:{H}:out_range=full,format=gbrp,"
        "huesaturation=saturation=-0.25:colors=g+c+b+m:strength=8:lightness=1,"
        "huesaturation=hue=-6:saturation=-0.10:colors=b+c:strength=6:lightness=1,"
        "split=4[base][gold_in][cool_in][m_in];"
        "[gold_in]colorbalance=rh=0.15:gh=0.06:bh=-0.12:pl=1[gold];"
        "[cool_in]colorbalance=rs=-0.06:bs=0.10:pl=1,eq=saturation=0.90[cool];"
        "[m_in]format=gray,split=2[hm_in][sm_in];"
        "[hm_in]geq=lum='clip((lum(X,Y)-150)*2.5,0,255)',gblur=sigma=4,format=gbrp[hm];"
        "[sm_in]geq=lum='clip((90-lum(X,Y))*2.5,0,255)',gblur=sigma=4,format=gbrp[sm];"
        "[base][gold][hm]maskedmerge[t1];"
        "[t1][cool][sm]maskedmerge[st];"
        f"[st]{color}[look];"
        f"[look]{_zoompan(W, H, fps)},format=gbrp[zp];"
        "[1:v]format=gbrp[wm];"
        "[zp]split=2[w0][w1];[w1]exposure=exposure=0.18[lift];"
        "[w0][lift][wm]maskedmerge[win];"
        "[win]split=2[p0][p1];[p1]gblur=sigma=14[pb];"
        # pin yuv420p BEFORE vignette,noise so grain semantics are deterministic
        # (verify correction โ€” vignette forced it implicitly before)
        "[p0][pb]blend=all_mode=screen:all_opacity=0.10,format=yuv420p,"
        "vignette=PI/5.5,noise=c0s=4:c0f=t+u[v]"
    )
    r = subprocess.run(
        [FF, "-y", "-ss", str(start), "-i", str(video), "-i", str(wm), "-t", str(dur),
         "-filter_complex", fg, "-map", "[v]", "-map", "0:a?",
         "-c:v", "libx264", "-crf", "17", "-preset", "slow",
         "-c:a", "aac", "-b:a", "192k", str(out)],
        capture_output=True, text=True, timeout=1800)
    if not Path(out).exists():
        raise RuntimeError("lux2 render failed: " + (r.stderr or "")[-500:])
    return str(out)


def _ensure_personmatte():
    """Compile tools/personmatte.swift on first use. None -> caller falls back to Tier 1."""
    if _PM_BIN.exists():
        return _PM_BIN
    swiftc = shutil.which("swiftc")
    if not swiftc or not _PM_SRC.exists():
        return None
    r = subprocess.run([swiftc, "-O", "-o", str(_PM_BIN), str(_PM_SRC)],
                       capture_output=True, text=True, timeout=600)
    if not _PM_BIN.exists():
        print("[luxury_render] personmatte build failed: " + (r.stderr or "")[-300:], file=sys.stderr)
        return None
    return _PM_BIN


def _geometry_pass(video, start, end, W, H, fps, dst):
    """PASS 1a โ€” bake face-crop + scale + push-in into geo.mp4 (crf 10 intermediate).
    Every downstream frame index becomes canonical: matte sync with zoompan is free."""
    dur = round(float(end) - float(start), 2)
    fc = _face_crop(video, start, end, W, H)
    vf = f"{fc},scale={W}:{H}:out_range=full,{_zoompan(W, H, fps)}"
    r = subprocess.run(
        [FF, "-y", "-ss", str(start), "-i", str(video), "-t", str(dur),
         "-vf", vf, "-c:v", "libx264", "-crf", "10", "-preset", "veryfast",
         "-pix_fmt", "yuv420p", "-c:a", "aac", "-b:a", "192k", str(dst)],
        capture_output=True, text=True, timeout=900)
    if not Path(dst).exists():
        raise RuntimeError("geometry pass failed: " + (r.stderr or "")[-400:])
    return dst


def _matte_pass(geo, W, H, fps, dst):
    """PASS 1b โ€” Vision person matte over geo.mp4, streamed raw-gray into a crf-6 encode.
    Encode pinned -pix_fmt gray -color_range pc: the matte is full-range BY CONSTRUCTION
    and tagged so (verify correction โ€” never blind-expand limited->full). Matte stored
    RAW (no feather) so tmix/gblur stay tunable per grade."""
    binp = _ensure_personmatte()
    if not binp:
        raise RuntimeError("personmatte unavailable (swiftc or source missing)")
    p1 = subprocess.Popen([str(binp), str(geo), str(W), str(H), "accurate"],
                          stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    p2 = subprocess.Popen(
        [FF, "-y", "-f", "rawvideo", "-pix_fmt", "gray", "-s", f"{W}x{H}", "-r", str(fps),
         "-i", "-", "-c:v", "libx264", "-crf", "6", "-pix_fmt", "gray",
         "-color_range", "pc", str(dst)],
        stdin=p1.stdout, stdout=subprocess.DEVNULL, stderr=subprocess.PIPE)
    p1.stdout.close()
    try:
        err2 = p2.communicate(timeout=1800)[1]      # segmentation budget: minutes, not 120s
        err1 = (p1.stderr.read() or b"").decode(errors="replace")
        p1.wait(timeout=60)
    except subprocess.TimeoutExpired:
        p1.kill(); p2.kill()
        raise RuntimeError("matte pass timed out")
    if p1.returncode != 0:
        raise RuntimeError("personmatte failed: " + err1[-400:])
    if p2.returncode != 0 or not Path(dst).exists():
        raise RuntimeError("matte encode failed: " + (err2 or b"").decode(errors="replace")[-400:])
    ng, nm = _nb_frames(geo), _nb_frames(dst)
    if ng > 0 and nm != ng:
        raise RuntimeError(f"matte frame parity broken: matte {nm} != geo {ng}")
    cov = re.search(r"coverage=([0-9.]+)", err1)
    if cov and float(cov.group(1)) < 0.02:
        raise RuntimeError(f"no person found (mean coverage {cov.group(1)})")
    return dst


def _masked_assets(video, start, end, W, H, fps):
    """Cache layer: geo.mp4 + matte.mp4 keyed on source|mtime|window|dims|fps|zoompan-ver.
    Segmentation runs once per clip window ever; re-grades are a single cheap pass 2."""
    _MATTE_CACHE.mkdir(parents=True, exist_ok=True)
    src = Path(video).resolve()
    key = hashlib.sha1(
        f"{src}|{src.stat().st_mtime}|{start}|{end}|{W}x{H}|{fps}|{_ZP_VERSION}".encode()
    ).hexdigest()[:16]
    geo = _MATTE_CACHE / f"{key}-geo.mp4"
    matte = _MATTE_CACHE / f"{key}-matte.mp4"
    if not geo.exists():
        _geometry_pass(video, start, end, W, H, fps, geo)
    if not matte.exists():
        try:
            _matte_pass(geo, W, H, fps, matte)
        except Exception:
            matte.unlink(missing_ok=True)
            raise
    return geo, matte


def render_masked(video, start, end, out, aspect="9:16", grade="cool", lut=None):
    """TIER 2 โ€” luxury-masked-{cool,warm,natural}: person-matte dual grade.
    One LUT before the split = one cohesive base look; then the relight recipe:
    world down-and-cool (-0.20 stop, sat 0.60, blue push), subject up-and-warm
    (+0.10 stop, temp 5800 โ€” warmth slides skin ALONG the skin-tone line, never a hue
    rotation), merged through a feathered temporally-smoothed matte. White matte selects
    the SUBJECT branch ([bg][fg][m]). Silently falls back to Tier 1 if the matte fails."""
    W, H = _dims(aspect)
    fps = _probe_fps(video)
    color = _lut_filter(grade, lut)
    try:
        geo, matte = _masked_assets(video, start, end, W, H, fps)
    except Exception as e:
        print(f"[luxury_render] matte unavailable ({e}); falling back to lux2-{grade}",
              file=sys.stderr)
        return render_lux2(video, start, end, out, aspect, grade, lut)
    fg = (
        f"[0:v]format=gbrp16le,{color},split=2[bg_in][fg_in];"
        "[bg_in]exposure=exposure=-0.20,eq=saturation=0.60,"
        "colorbalance=rs=-0.03:bs=0.06:bm=0.03:pl=1[bg];"
        "[fg_in]exposure=exposure=0.10,colortemperature=temperature=5800,eq=saturation=1.05,"
        "huesaturation=saturation=-0.06:colors=c+b+m:strength=6:lightness=1[fg];"
        # matte branch: tag full range (data IS full by construction โ€” see _matte_pass),
        # normalize pts/fps, temporal smooth (kills matte buzz), wide spatial feather
        f"[1:v]extractplanes=y,setrange=full,setpts=PTS-STARTPTS,fps={fps},"
        "tmix=frames=3:weights='1 2 1',gblur=sigma=7,format=gbrp16le[m];"
        "[bg][fg][m]maskedmerge[mrg];"
        "[mrg]split=2[p0][p1];[p1]gblur=sigma=14[pb];"
        "[p0][pb]blend=all_mode=screen:all_opacity=0.10,format=yuv420p,"
        "vignette=PI/5.5,noise=alls=3:allf=t+u[v]"
    )
    r = subprocess.run(
        [FF, "-y", "-i", str(geo), "-i", str(matte),
         "-filter_complex", fg, "-map", "[v]", "-map", "0:a?",
         "-c:v", "libx264", "-crf", "17", "-preset", "slow", "-c:a", "copy", str(out)],
        capture_output=True, text=True, timeout=1800)
    if not Path(out).exists():
        print("[luxury_render] masked merge failed (" + (r.stderr or "")[-200:]
              + "); falling back to lux2", file=sys.stderr)
        return render_lux2(video, start, end, out, aspect, grade, lut)
    return str(out)


def render_matte_preview(video, start, end, out, aspect="9:16"):
    """QC mode โ€” the person matte composited as a 50% red overlay on geo.mp4 so edge
    quality and flicker can be eyeballed before committing to a grade. No fallback:
    a preview that can't build its matte should fail loudly."""
    W, H = _dims(aspect)
    fps = _probe_fps(video)
    geo, matte = _masked_assets(video, start, end, W, H, fps)
    # red frame synthesized FROM the finite geo stream (drawbox t=fill) โ€” an infinite
    # lavfi color input does not reliably terminate under -filter_complex
    fg = ("[0:v]split=3[g0_in][g1_in][g2_in];"
          "[g0_in]format=gbrp[g0];[g1_in]format=gbrp[g1];"
          "[g2_in]drawbox=x=0:y=0:w=iw:h=ih:color=red:t=fill,format=gbrp[red];"
          "[1:v]extractplanes=y,setrange=full,format=gbrp[m];"
          "[g1][red][m]maskedmerge[fr];"
          "[g0][fr]blend=all_mode=normal:all_opacity=0.5,format=yuv420p[v]")
    r = subprocess.run(
        [FF, "-y", "-i", str(geo), "-i", str(matte),
         "-filter_complex", fg, "-map", "[v]", "-map", "0:a?",
         "-c:v", "libx264", "-crf", "18", "-preset", "medium", "-c:a", "copy", str(out)],
        capture_output=True, text=True, timeout=900)
    if not Path(out).exists():
        raise RuntimeError("matte preview failed: " + (r.stderr or "")[-400:])
    return str(out)


def _mode_grade(mode):
    """Trailing grade of a mode name ('lux2-warm' -> 'warm'), default otherwise."""
    tail = mode.rsplit("-", 1)[-1]
    return tail if tail in GRADES else DEFAULT_GRADE


def render(video, start, end, title, out, aspect="9:16", mode="quiet", font=DIDOT):
    if mode == "matte-preview":           # QC: matte as 50% red overlay
        return render_matte_preview(video, start, end, out, aspect)
    if mode.startswith("lux2"):           # "lux2" | "lux2-cool" | "lux2-warm" | "lux2-natural"
        return render_lux2(video, start, end, out, aspect, _mode_grade(mode))
    if mode.startswith(("luxury-masked", "masked")):   # "luxury-masked-*" a.k.a. "masked-*"
        return render_masked(video, start, end, out, aspect, _mode_grade(mode))
    if mode.startswith("pure"):           # "pure" | "pure-cool" | "pure-warm" | "pure-natural"
        grade = mode.split("-", 1)[1] if "-" in mode else DEFAULT_GRADE
        return render_pure(video, start, end, out, aspect, grade)
    m = MODES.get(mode, MODES["quiet"])
    W, H = (1080, 1920) if aspect == "9:16" else (1080, 1080) if aspect == "1:1" else (1920, 1080)
    dur = round(float(end) - float(start), 2)
    crop = f"crop='min(iw,ih*{W}/{H})':'min(ih,iw*{H}/{W})':(iw-ow)/2:(ih-oh)/2,scale={W}:{H}"
    with tempfile.TemporaryDirectory() as td:
        ass = Path(td) / "lux.ass"
        ass.write_text(_ass(title, dur, W, H, m["cap_size"], m["cap_spacing"], m["cap_marginv"], font))
        # a short gold hairline above the caption; frame only in cinematic mode
        chain = [crop, m["grade"], m["bloom"], m["film"]]
        if m["frame"]:
            chain.append(f"drawbox=x=26:y=26:w=iw-52:h=ih-52:color={GOLD}@0.45:t=2")
        rule_y = int(H * (0.82 if not m["frame"] else 0.79))
        chain.append(f"drawbox=x=(iw-130)/2:y={rule_y}:w=130:h=2:color={GOLD}@0.8:t=fill")
        chain.append(f"ass={ass}")
        vf = ",".join(chain)
        r = subprocess.run(
            [FF, "-y", "-ss", str(start), "-i", str(video), "-t", str(dur),
             "-vf", vf, "-c:v", "libx264", "-crf", "18", "-preset", "slow",
             "-pix_fmt", "yuv420p", "-c:a", "aac", "-b:a", "192k", str(out)],
            capture_output=True, text=True, timeout=1200)
        if not Path(out).exists():
            raise RuntimeError("luxury render failed: " + (r.stderr or "")[-500:])
    return str(out)


if __name__ == "__main__":
    a = argparse.ArgumentParser()
    a.add_argument("--video", required=True); a.add_argument("--out", required=True)
    a.add_argument("--title", default=""); a.add_argument("--aspect", default="9:16")
    # quiet | cinematic | pure[-GRADE] | lux2[-GRADE] | luxury-masked-GRADE (a.k.a.
    # masked-GRADE) | matte-preview        GRADE = cool | warm | natural
    a.add_argument("--mode", default="quiet")
    a.add_argument("--font", default=DIDOT, help="caption family for quiet/cinematic (installed system font; default Didot)")
    a.add_argument("--grade", default="cool", choices=["cool", "warm", "natural"])
    a.add_argument("--lut", default=None, help="explicit .cube path (overrides grade)")
    a.add_argument("--start", type=float, default=0); a.add_argument("--end", type=float, default=30)
    p = a.parse_args()
    if p.mode.startswith("pure"):
        grade = p.mode.split("-", 1)[1] if "-" in p.mode else p.grade
        print(render_pure(p.video, p.start, p.end, p.out, p.aspect, grade, p.lut))
    elif p.mode.startswith("lux2"):
        grade = p.mode.split("-", 1)[1] if "-" in p.mode else p.grade
        print(render_lux2(p.video, p.start, p.end, p.out, p.aspect, grade, p.lut))
    elif p.mode.startswith(("luxury-masked", "masked")):
        grade = _mode_grade(p.mode) if "-" in p.mode else p.grade
        print(render_masked(p.video, p.start, p.end, p.out, p.aspect, grade, p.lut))
    elif p.mode == "matte-preview":
        print(render_matte_preview(p.video, p.start, p.end, p.out, p.aspect))
    else:
        print(render(p.video, p.start, p.end, p.title, p.out, p.aspect, p.mode, p.font))