taste-distillation

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Taste Distillation

品味蒸馏

This standalone skill ships its implementation in
scripts/
; use
taste-application
for the subsequent generated or local-take edit. Keep each named genre in its own pack. Measurements from Flash Ethereal must not be silently reused for Fluid Sketch or 3D Cyber Glitch. A measured zero is valid data; distinguish it from an absent field.
Local dependencies are in
scripts/requirements.txt
. Separately authorized provider work also needs
scripts/requirements-live.txt
, credentials and explicit
TASTE_FORGE_ALLOW_LIVE=1
.
--dry-run
does not read credentials or submit jobs. Never infer that a workflow was saved from a local endpoint name; use the actual provider-side workflow or request evidence.
Turn reference videos into a style pack: a folder of measurements and assets that later stages consume deterministically.
这个独立技能的实现代码位于
scripts/
目录下;后续的生成剪辑或本地素材剪辑请使用
taste-application
技能。每个命名风格流派都应存放在独立的风格包中。Flash Ethereal的测量数据绝不能悄无声息地复用到Fluid Sketch或3D Cyber Glitch风格中。测量得到的零值是有效数据,需与字段缺失区分开。
本地依赖列于
scripts/requirements.txt
中。如需调用需单独授权的服务商服务,还需要
scripts/requirements-live.txt
、凭证以及显式设置
TASTE_FORGE_ALLOW_LIVE=1
。
--dry-run
模式不会读取凭证或提交任务。绝不要通过本地端点名称推断工作流是否已保存,应以服务商侧的实际工作流为准或要求提供证明。
将参考视频转换为风格包:一个包含测量数据和资产的文件夹,后续流程可确定性地调用这些内容。

When to Activate

适用场景

  • "capture the look of these clips" / "distill the vibe" / "make this repeatable"
  • User has reference footage and wants a LUT, a grade, or matching pacing
  • Building a library of looks partitioned by genre
  • Any request where the answer would otherwise be "describe the style in a prompt"
  • 「提取这些片段的视觉风格」/「提炼氛围感」/「让效果可复用」
  • 用户有参考素材,需要生成LUT、色彩分级或匹配的剪辑节奏
  • 搭建按风格流派划分的视觉效果库
  • 任何原本只能回复「在prompt中描述风格」的需求

The Core Finding

核心结论

Prompting cannot deliver a grade. Measurement can.
Measured on real footage: three paid generations with escalating colour direction moved midtone a* from +1.9 → +2.8 → +0.3 against a +24.9 target, and contrast never left ~19 against a 34.7 target. Applying a measured pack to the same footage hit chroma MAE 1.88 and contrast 33.7 in one deterministic pass, for free.
So the split is: the model supplies content, motion and lighting structure; the pack supplies the look. Colour words in a generation prompt are worse than useless — they cost money and push the render away from the neutral base the LUT wants. Say so explicitly in the prompt: "Colour: none. Render neutral. Grading is applied afterwards."
靠Prompt无法实现精准的色彩分级,靠测量可以。
在真实素材上的测试显示:三次付费生成、逐步强化色彩指令后,中间调的a*值从+1.9→+2.8→+0.3,而目标值是**+24.9**;对比度始终在19左右,目标值为34.7。而将测量生成的风格包应用到同一素材上,仅需一次确定性处理,就能实现色度MAE1.88、对比度33.7的效果,且无需额外成本。
因此分工应该是:模型负责内容、动态和光影结构,风格包负责视觉风格。 生成Prompt里的色彩描述不仅没用,反而有害:它们会增加成本,还会让渲染结果偏离LUT所需的中性基底。请在Prompt中明确说明:「色彩:无。渲染中性画面。后续会施加色彩分级。」

What a Pack Contains

风格包内容

stylepacks/<genre>/
  grade.json      measured colour statistics (see below)
  cadence.json    every detected shot boundary + the derived distribution
  look.cube       33^3 LUT, drag straight into Resolve as a node LUT
  spec.json       VLM description, grounded in the measurements
  grounding.txt   the measured facts fed to the VLM
  stills/         full-res frames from the longest shots (conditioning images)
  plates/         screen-blend overlay elements lifted onto black
  props/          minted GLB meshes
  pack.json       manifest
stylepacks/<genre>/
  grade.json      measured colour statistics (see below)
  cadence.json    every detected shot boundary + the derived distribution
  look.cube       33^3 LUT, drag straight into Resolve as a node LUT
  spec.json       VLM description, grounded in the measurements
  grounding.txt   the measured facts fed to the VLM
  stills/         full-res frames from the longest shots (conditioning images)
  plates/         screen-blend overlay elements lifted onto black
  props/          minted GLB meshes
  pack.json       manifest

Running It

运行方式

bash
python mint.py --genre <name> --refs a.mov b.mov c.mov     # offline, no API key
python distill.py --genre <name>                            # one VLM call
mint.py
is pure numeric analysis — no network, no key, deterministic, so a pack can be regenerated rather than backed up.
bash
python mint.py --genre <name> --refs a.mov b.mov c.mov     # offline, no API key
python distill.py --genre <name>                            # one VLM call
mint.py
是纯数值分析工具——无需联网、无需密钥、结果确定,因此风格包可以重新生成,无需额外备份。

The Measurements That Matter

核心测量指标

Chroma by luminance zone, not globally

按亮度分区测量色度,而非全局测量

Colour identity usually lives in one luminance band. A global a*/b* offset mathematically cannot represent split-toning. Measure chroma inside zones (
L* edges [0,15,35,55,75,100]
).
A real signature: violet at L*25 (a* +24.9, b* −17.5), near-neutral at both ends. Reporting only the darkest and lightest zones calls that "uniform cast" — always print the whole curve.
色彩风格通常体现在某一个亮度区间内。全局的a*/b*偏移在数学上无法表现分色(split-toning)效果。需在各亮度区间内测量色度(
L* edges [0,15,35,55,75,100]
)。
一个真实的风格特征案例:在L25处为紫色(a +24.9,b* −17.5),而亮度两端接近中性色。如果只报告最暗和最亮区间的数值,会把这种情况误判为「统一偏色」——务必输出完整的曲线数据。

Median + MAD, never mean + std

中位数 + MAD,绝不使用均值 + std

Chroma in real reference sets is strongly right-skewed. On one measured reel the mean midtone chroma was 36.9 against a median of 17.5, so a mean-based LUT pushed colour ~3x harder than the material warranted.
真实参考素材集中的色度分布呈强右偏态。在一次测试素材的测量中,中间调色度的均值为36.9,而中位数仅为17.5,因此基于均值生成的LUT会让色彩饱和度比素材实际需要高出约3倍。

Contrast is std(L*), not white minus black

对比度为std(L*),而非白场减黑场

The white−black range is ~100 on almost any real footage and discriminates nothing.
几乎所有真实素材的白黑场差值都在100左右,无法区分任何风格差异。

Background share is a first-class statistic

暗部占比是核心统计指标

Record the share of pixels below L*10. No moment of the distribution can see it: a clip can hold the right mean, std and chroma while its blacks have been lifted into grey. This is exactly how a grade once scored MAE 1.88 / contrast 33.7 while the actual frame was a muddy purple mess.
需记录L*值低于10的像素占比。这一信息无法通过分布的矩量推导出来:一个片段的均值、标准差和色度可能都符合要求,但黑场已经被提亮成了灰色。曾经就有这样的情况:色彩分级的MAE为1.88、对比度为33.7,看起来指标很好,但实际画面却是浑浊的紫色一团糟。

Mask the interface before measuring

测量前先屏蔽界面元素

Screen-recorded references carry static furniture — letterbox bars, a status bar, a like icon, caption text. All of it lands in the statistics as if it were the look: black bars inflate shadow weight, a red heart skews a* toward magenta. Temporal variance separates them cleanly — the footage moves, the interface does not — so no hand-tuned crop is needed. On real material this keeps ~65% of pixels.
录屏类参考素材带有静态界面元素——比如黑边、状态栏、点赞图标、字幕文本。这些都会被计入风格统计数据:黑边会抬高暗部占比,红色爱心会让a*值向品红偏移。时间方差可以清晰地将二者区分开——素材是动态的,界面是静态的——因此无需手动调整裁剪区域。在真实素材上,这种方法能保留约65%的有效像素。

Cadence needs an adaptive threshold

剪辑节奏检测需要自适应阈值

The right content-detector threshold is material-dependent: a high-contrast action reference cuts hard enough for 30, a moody one hides its cuts under it. Sweep descending thresholds and take the highest one that still recovers ≥90% of the shots the most sensitive setting finds — that biases toward real cuts over noise. Reject thresholds implying an absurd cut rate (>100/min); continuous camera moves trip the detector every frame.
Run the whole sweep in one decode pass with a shared
StatsManager
. The naive version re-decodes per threshold, which on 60fps source is the difference between seconds and minutes.
内容检测器的合适阈值因素材而异:高对比度的动作类参考素材剪辑切换强烈,阈值设为30都能检测到;而氛围感柔和的素材的剪辑点会被这个阈值掩盖。可以从高到低遍历阈值,选取仍能检测到最灵敏设置下≥90%镜头的最高阈值——这样更倾向于识别真实剪辑点而非噪声。要排除导致剪辑率过高(>100次/分钟)的不合理阈值;连续的镜头移动会让检测器每帧都误触发。
使用共享的
StatsManager
在一次解码过程中完成所有阈值遍历。朴素的实现会为每个阈值重新解码,对于60fps的素材,这会导致耗时从几秒变成几分钟。

Overlay Plates: Assets, Not Screenshots

叠加层素材:是资产,不是截图

A still is a whole frame — compositing one just puts a second picture on top. A plate is the reference's graphic vocabulary (flares, streaks, glitch fragments) lifted onto black so it screen-blends with no keying.
Two traps, both hit on real material:
  1. Absolute thresholds fail. On a bright reference an
    L>55 AND chroma>12
    selection takes ~90% of frame, and the "plate" is the picture — including a recognisable face. Select by percentile (~top 3%) and reject any plate covering more than ~22% of frame.
  2. Rank by separation, not by brightness. "Share of bright saturated pixels" ranks a washed-out frame top and a black frame with one intense flare — the actual signature — near the bottom. Score
    p99.5(energy) / median(energy)
    .
Also mask before scoring: burnt-in typography is bright, saturated and high-contrast, so an unmasked run yields a perfect plate of someone else's title card.
静帧是完整的一帧——合成静帧相当于在画面上再叠一张图。而**plate(叠加层素材)**是从参考素材中提取的图形元素(光晕、光条、故障碎片等),背景为纯黑,因此可以直接用屏幕混合模式叠加,无需抠像。
有两个常见陷阱,在真实素材处理中都曾出现过:
  1. 绝对阈值不可靠。 在明亮的参考素材上,
    L>55 AND chroma>12
    的选区会覆盖约90%的画面,这样提取的「plate」就是整张图——包括可识别的人脸。应按百分位(约前3%)选取,并且拒绝任何覆盖画面占比超过约22%的plate。
  2. 按区分度排序,而非亮度。 「亮部饱和像素占比」的排序方式会把过曝的帧排在前面,而带有单个强烈光晕的黑帧——这才是真正的风格特征——却排在后面。应使用
    p99.5(energy) / median(energy)
    作为评分标准。
评分前同样要做屏蔽处理:烧录在画面上的文字明亮、饱和且高对比度,因此不做屏蔽的话,提取出的「完美plate」可能只是别人的标题卡。

Grounding the VLM

VLM Grounding

Feed the measurements into the system prompt before asking for a description. Ungrounded, a VLM will report "no apparent colour grading, neutral" on footage with a +24.9 a* cast. Grounded, it describes the cast correctly and infers the secondary accent independently.
Ban hedging words (
varied
,
mixed
,
dynamic
,
some
,
often
,
neutral
,
or
) — a model cannot render "varied lighting". Enforce the ban in code, not just in the prompt: it was violated in roughly one run in three. Re-ask per-field, keep the least-hedged answer after N attempts rather than failing.
Caveat worth stating to the user: once the spec is grounded in the measurements it is no longer an independent check on them.
在要求VLM生成描述前,先将测量数据输入系统提示词中。没有Grounding的情况下,对于a*偏移达+24.9的素材,VLM可能会报告「无明显色彩分级,画面中性」。有了Grounding后,VLM能正确描述偏色情况,还能独立推断出次要强调色。
禁止使用模糊的模棱两可的词汇(
varied
、
mixed
、
dynamic
、
some
、
often
、
neutral
、
or
)——模型无法渲染「多变的灯光」。要在代码中强制禁用这些词,而不只是在提示词里说明: 大约每三次运行就有一次会违反提示词中的要求。应按字段逐个追问,在N次尝试后选取最不含糊的答案,而非直接失败。
需要向用户说明的注意事项:一旦规范文本基于测量数据生成,它就不再能作为测量数据的独立验证依据。

LUT Baking Gotchas

LUT烘焙注意事项

  • A LUT can only encode a per-pixel RGB function. Anything distribution-dependent (histogram matching, percentile anchors) must be reduced to a constant before baking, or it silently measures the uniform LUT grid instead of the footage.
  • cv2.cvtColor(LAB2RGB)
    clamps internally, so an out-of-gamut test using it reports 0%. Convert Lab→linear sRGB by hand; a real measurement was 83.3% OOG.
  • Offset chroma transfer, not affine. Affine divides by the source σ and overshoots — on real footage it flipped b* to +11.6 against a −17.5 target. Offset took MAE from 6.23 to 2.13.
  • Gamut compression cost 3.8x runtime for identical MAE. Make it opt-in.
  • LUT只能编码逐像素的RGB函数。任何依赖分布的操作(直方图匹配、百分位锚定)都必须在烘焙前转换为常量,否则烘焙过程会悄无声息地测量均匀的LUT网格,而非实际素材。
  • cv2.cvtColor(LAB2RGB)
    会在内部做截断处理,因此用它来做超色域测试会得到0%的结果。需手动实现Lab到线性sRGB的转换;真实测量中曾出现过83.3%的OOG比例。
  • 使用偏移法进行色度转换,而非仿射变换。仿射变换会除以源σ,导致过度偏移——在真实素材上,它会把b*值从目标的−17.5变成+11.6。偏移法将MAE从6.23降到了2.13。
  • 色域压缩会让运行时间增加3.8倍,但MAE结果完全相同。应将其设为可选功能。

Anti-Patterns

反模式

Don'tWhy
Tune against synthetic test footageCost four separate wrong conclusions on one project; real footage overturned every one
Trust MAE alone1.88 MAE looked like success on a visibly broken frame
Use mean/std for chromaRight-skewed; pushes ~3x too hard
Compare only endpoint zonesBoth ends are near-neutral by construction
Describe the look and stopThe spec is for content and structure; the pack is for colour
错误做法原因
用合成测试素材调优曾在一个项目中导致四次错误结论;每次都被真实素材推翻
只信任MAE指标曾出现MAE为1.88看似成功,但实际画面明显有问题的情况
用均值/std衡量色度色度分布右偏,会导致色彩强度高出约3倍
只对比亮度两端的区间两端的数值天生就接近中性色
只描述风格就完事规范文本用于内容和结构,风格包才负责色彩

Handoff

交接方式

The pack is the interface. Once it exists, use the taste-application skill to generate and assemble against it, or hand
look.cube
to a colourist directly.
风格包就是交互接口。生成风格包后,可以使用taste-application技能基于它生成和剪辑内容,也可以直接把
look.cube
交给调色师。

Bundled Code

附带代码

scripts/
in this skill is a working implementation, not pseudocode. It has no project-specific assumptions: point it at any reference videos and it produces a pack.
bash
pip install -r scripts/requirements.txt
export FAL_KEY=...            # only needed for the stages that call fal
Every network call is stubbed under
TASTE_FORGE_DRY_RUN=1
or
--dry-run
, so the plan, prompts, track layout and manifest can be inspected without spending.
本技能中的
scripts/
目录是可运行的实现,而非伪代码。它没有项目特定的假设:指向任何参考视频都能生成风格包。
bash
pip install -r scripts/requirements.txt
export FAL_KEY=...            # only needed for the stages that call fal
在
TASTE_FORGE_DRY_RUN=1
或
--dry-run
模式下,所有网络调用都会被桩化,因此无需花费成本就能检查方案、提示词、轨道布局和清单文件。