【免费下载链接】Skills
Agent skills for designers and builders using Codex, Claude, Cursor, and other AI coding agents
木材只有在暗房间里被一束方向性主光斜扫过时,才真正"像木头":纹理、接触阴影和光柱由同一扇窗户照亮,最后统一做一次色调映射,每一部分都在渲染完成的帧上被量化测量,而不是靠"感觉"来评判。本篇文章以 Skills 仓库中3d-wood-lighting-scorecard技能附带的评分标准(rubric.md)为核心,完整解析这套"8 项 10 分制"评测体系:每一项如何由 2~4 个可测量子指标构成、每个子指标如何通过三个锚点[v@3, v@6, v@9]映射为分数,以及如何结合metrics.js、scorecard.mjs与真实 scorecard JSON 来诚实地阅读、验证和迭代渲染结果。读完你将掌握一套可复制到任意 Three.js 木材光照场景的客观评分方法,以及"分数会说谎"时如何自我校验。
评分卡机制:从原始像素到 0~10 分
rubric.md 的开头定义了整套评分体系的核心机制,这也是理解后面所有表格的前提:
- 八个评分项(item),每项 0~10 分;
- 每个评分项由2~4 个可测量的子指标(sub-metric)构成;
- 每个子指标通过三个锚点
[v@3, v@6, v@9]映射到分数——锚点之间线性插值,超出锚点范围继续外推,最终clamp 到 0~10;对于"越低越好"的指标,锚点可以按从高到低排列; - 评分项的总分是其所有子指标分数的平均值(在 metrics.js 中对应
item()函数对parts.map(p => p.score)求均值); - 锚点数值与 metrics.js 中的硬编码一一对应(第 100~222 行的
part()调用),rubric.md 明确警告:改动任何一个锚点,必须同时修改 metrics.js 中的对应数组,并重新运行 baseline 与 ablation 测试,否则分数将失去意义。
三个用于校准的"基准场景"描述:
- "9":一帧 Kibori 车站的静帧(上过油的扁柏长凳、一扇窗户、光束中的灰尘),一眼看过去与照片无法区分;
- "6":一个合格的 Three.js 场景——颜色正确、有光照、没有明显错误,但也毫无说服力;
- "3":一个平涂着色(flat-shaded)的道具。
完整的分数语义(Scale):
| 分数 | 含义 |
|---|---|
| 10 | 可以拿来研究观摩 |
| 9 | 受过训练的眼睛也几乎挑不出毛病 |
| 8 | 打磨到位,只有细微瑕疵 |
| 7 | 有明显缺陷 |
| 6 | 能用,但有肉眼可见的粗糙边缘 |
| 5 | 平庸 |
| 3~4 | 多处明显错误 |
| 1~2 | 几乎无法正常工作 |
rubric.md 还强调了区域(region)的约定:所有下述测量区域都以"帧自身的比例坐标"表示,并通过实时相机从世界坐标点投影得到(即 demo.html 中的KiboriScore.regions(),见 demo.html)。因此换一个场景打分,只需要重写regions()函数,而不需要改动任何指标逻辑——指标始终只吃一张帧的 RGBA 字节加一组区域矩形。
1. 材质与木纹(Materials and grain)
木纹是木材真实感的第一道门槛。rubric.md 给出了三个观察锚点:
| 分数 | 看起来像什么 |
|---|---|
| 3 | 单一平坦的棕褐色,或可明显看到重复的平铺照片;木纹线以随机角度横穿木板(uFlat开启时,实测得分 1.7) |
| 6 | 条纹方向正确,但每块木板图案相同;没有毛孔,没有年轮漂移 |
| 9 | 年轮漂移成拱形(cathedral arcs),毛孔与纤维在 1 px 尺度仍可分辨,端面年轮可读出细胞结构,没有两块木板相同(demo 实测 8.1) |
测量指标(在"素木的受光斑块"上测量,避开雕刻区域):
| 子指标 | 说明 | 锚点[v@3, v@6, v@9] |
|---|---|---|
grainContrast | 1~8 px 带通标准差 / 亮度均值 | 0.006 / 0.022 / 0.05 |
grainAniso | 垂直于木纹方向的梯度能量 / 沿木纹方向 | 1.1 / 1.9 / 3.2(线条沿轴线方向) |
toneVar | 29 px 模糊后的标准差 / 均值,捕捉年轮带的宽幅漂移 | 0.008 / 0.035 / 0.08 |
在 metrics.js 中,这三个指标在grain区域内计算:grainContrast用 1 px 与 4 px 盒式模糊的差值做带通(Y[i] - b4);grainAniso把梯度旋转到木纹角度坐标系(ca/sa)后分别累计横向与纵向能量;toneVar用 14 px 盒式模糊(boxAt(...,14))估计宽幅亮度漂移。
实测参考(来自 last-scorecard.json):demo 该评分项 8.13 分,其中grainContrast = 0.0357 → 7.46、grainAniso = 106.48 → 10(远超锚点上界)、toneVar = 0.0491 → 6.94。而全部层关闭的 baseline 只有 1.67 分,可见"一个平坦颜色"与"程序化木纹 + 光照"之间的差距有多大。
2. 主光 / 补光对比(Key / fill contrast)
木材的"雕塑感"来自受光面与背光面的明确分离,同时背光面又不能死黑。
| 分数 | 看起来像什么 |
|---|---|
| 3 | 受光面与背光面相差不足一档,读起来像环境光(baseline 实测 4.1) |
| 6 | 有清晰的亮面,但暗面要么糊成一片、要么死黑 |
| 9 | 暖主光高出冷补光 3 档以上,冷补光让背光侧保持"活着";房间在光池之外保持黑暗(demo 实测 10) |
测量指标:
| 子指标 | 说明 | 锚点 |
|---|---|---|
keyFillStops | log2(受光面线性亮度 / 背光面线性亮度),单位为档 | 0.7 / 1.7 / 2.8 |
rangeStops | 全帧 p99 / p1 的亮度比,档数 | 3 / 5 / 7 |
shadeAlive | 背光面线性亮度 ×1000(必须不能被压到 0) | 1.5 / 4 / 10 |
源码中(metrics.js),keyFillStops先把 8-bit 亮度通过 sRGB 解伽马查找表LIN转成线性光,再取两区域均值比值的 log2;shadeAlive直接返回背光面线性亮度 ×1000,专门用来拦截"补光太弱导致背光面 crush 到 0"的典型错误。
实测:demo 该项满分 10(keyFillStops = 3.29档、rangeStops = 10.32档、shadeAlive = 44.06)。对应 SKILL.md 中的光照配置:暖主光DirectionalLight0xfff2df、强度 2.0,补光 0xaec7df 0.60~0.76,轮廓光 0xffdeb4 0.72,半球光 0x19——这些弱光项"只负责让背光侧保持存活,不是画面本身"。
3. 阴影与接触(Shadows and contact)
阴影是物体"坐进"场景的关键。rubric.md 指出两个最典型的问题:无阴影,以及物体底部与阴影之间出现亮缝(peter-panning)。
| 分数 | 看起来像什么 |
|---|---|
| 3 | 无阴影,或阴影与物体之间有亮缝(baseline 实测 5.6) |
| 6 | 阴影落下了,但是均匀灰色;每个物体的底部都有一点"漂浮" |
| 9 | 阴影起始处深、向外散开成柔和的半影(penumbra),物体在接触处有一条暗缝(demo 实测 9.6) |
测量指标(4 个子指标,是该技能中维度最丰富的一项):
| 子指标 | 说明 | 锚点 |
|---|---|---|
shadowRatio | 受光长凳 / 阴影长凳的线性亮度比 | 1.6 / 3.5 / 7 |
contactDark | 接触带 / 开放长凳亮度(越低越好) | 0.75 / 0.42 / 0.18 |
penumbraMono | 剖面中从接触点向外单调上升的比例 | 0.6 / 0.8 / 0.95 |
contactGap | 离开接触点时的亮度骤降——即物体底部的亮缝(越低越好) | 0.30 / 0.10 / 0.02 |
实现层面(metrics.js):contact.p0 → p1定义了一条横穿物体前缘的剖面线,lineProfile()沿该线采样 64 点并平滑;penumbraMono统计剖面中逐点亮度不低于前一点 ×0.985 的比例;contactGap则扫描剖面前 16 点中最大的"离开接触点时的亮度落差",专门检测 peter-panning 的亮缝。对应的渲染侧对策在 SKILL.md:normalBias要按阴影贴图分辨率缩放(4096 用 0.0045、2048 用 0.0085),并在每个物体下方烘焙径向衰减的接触暗池(contact pool,y=0.0012),因为仅靠阴影贴图无法让接缝变暗。
实测:demo 该项 9.57 分——shadowRatio = 6.75、contactDark = 0.12、penumbraMono = 1.0(完全单调)、contactGap = 0(无亮缝)。
4. 体积光柱与灰尘(Volumetric shafts and dust)
暗房间 + 光束 + 灰尘,是这张场景"氛围感"的来源,也是最容易把黑位和木纹一起毁掉的环节。
| 分数 | 看起来像什么 |
|---|---|
| 3 | 没有光束,或一块硬边半透明平面、能看到明显边界(baseline 实测 4.7) |
| 6 | 光束两侧柔和,但亮度从头到尾相同;灰尘要么没有、要么均匀撒布 |
| 9 | 沿长度方向调制、逐渐淡入淡出的光束;没有任何硬楔形;光束旁的黑位保持完整;灰尘只在有光处可见(demo 实测 8.0) |
测量指标:
| 子指标 | 说明 | 锚点 |
|---|---|---|
shaftDelta | 光束相对其外平行参考带的亮度级数 | 1.2 / 4 / 9,且不得超过 35——超过说明光束正在"洗掉"房间黑位,70 时该项降到 3 分 |
shaftRough | 光衰轮廓的锯齿度(越低越好) | 0.5 / 0.22 / 0.08 |
dustFrac | 光束内(减去暗墙参考区)比其 7 px 邻域亮 6+ 级的柔和光斑占比 | 0.0002 / 0.001 / 0.003 |
这是评分卡中唯一带cap(上限惩罚)的指标:anchor()函数的cap参数(metrics.js)实现"太亮同样扣分"——shaftDelta超过 35 后分数线性跌到 3。对应渲染侧,SKILL.md 给出的对策是:每块光束平面按世界高度淡出(smoothstep(0.02, 0.34, y))、增益控制在 0.13,并时刻检查黑位p1是否低于 7。实测中shaftDelta = 41.14已经越过 35 上限(得分 7.95),说明该 demo 的光束增益仍偏亮,这是指标直接暴露出的可优化点。
5. 背景光线条带(Background rays)
墙上投射的窗户光条带,是"这扇窗真实存在"的视觉证据。
| 分数 | 看起来像什么 |
|---|---|
| 3 | 没有条带,或只有一条(baseline 实测 0.8) |
| 6 | 两条条带,亮度均匀 |
| 9 | 四条或更多条带,宽度与亮度都不相等、沿墙逐渐变暗、位于物体之后、不与物体争夺注意力(demo 实测 8.8) |
测量指标:
| 子指标 | 说明 | 锚点 |
|---|---|---|
rayContrast | 横穿墙带剖面的 p92 − p8,亮度级数 | 1 / 3 / 6.5,上限:超过 45 视为眩光墙(90 时得 3 分) |
rayPeaks | 墙面上可区分的条带数量 | 1 / 2 / 4 |
rayPeaks的峰值检测在 metrics.js:对 96 点剖面平滑后,统计"比两侧 3 点都高 0.7 级以上"的局部峰。实测 demo 该项 8.75 分:rayContrast = 36.15(未过 45 上限,得 10 分)、rayPeaks = 3 → 7.5——条带数量刚好差一条到满分,是一个明确的量化缺口。
6. 色彩与色调映射(Colour and tone mapping)
暗场景最容易在最后一步色调映射上翻车:高光裁切、黑位抬升、渐变条带、冷暖不分。
| 分数 | 看起来像什么 |
|---|---|
| 3 | 高光裁切成纯白,黑位抬成灰,渐变出现条带,冷暖色混为一谈(baseline 实测 4.5) |
| 6 | 没有裁切,但画面平淡,或对比过压 |
| 9 | 窗户高光是柔和的滚降而非裁切,黑点落在 2~7 之间,暖主光对冷阴影,暗墙无条带(demo 实测 9.8) |
测量指标(5 个子指标,最多的一项):
| 子指标 | 说明 | 锚点 |
|---|---|---|
clipPct | 任一通道 ≥ 254 的像素占比(越低越好) | 4 / 1.2 / 0.25 |
p1 | 黑点亮度(越低越好,直到被压死) | 34 / 18 / 7 |
crushPct | 亮度 < 2 的像素占比 | 45 / 22 / 8 |
warmCool | 同一长凳受光面与阴影面 R−B 之差 | 1 / 8 / 18 |
flatRun | 暗墙像素中连续 6+ 个完全相同值(8-bit 条带)的占比(越低越好) | 0.5 / 0.2 / 0.04 |
源码中clipPct、crushPct、p1/p50/p99在全帧统计(metrics.js);flatRun通过逐行扫描"同一 RGB 三元组连续 6 像素以上"的运行来检测 8-bit 色带,对应渲染侧在 ACES 之后、sRGB 编码之后加±0.0015哈希抖动(dither 0.003)来消除条带。实测 demo 该项 9.84 分,五项子分数全部在 9.4 以上。
7. 纹理分辨率与纹素密度(Texture resolution and texel density)
木材的真实感最终取决于纹理在 1 px 尺度上是否还有细节、以及掠射视角是否抖动。
| 分数 | 看起来像什么 |
|---|---|
| 3 | 最近视角下是模糊的"软泥",或木板边缘视角出现闪烁摩尔纹(16 px 字段实测 6.9) |
| 6 | 正面看锐利,掠射角"爬行" |
| 9 | 正面 1 px 细节,相机移动半像素时画面平静,源纹素 ≥ 每设备像素 1 个(demo 实测 9.7) |
测量指标:
| 子指标 | 说明 | 锚点 |
|---|---|---|
fineStd | 1 px 拉普拉斯标准差(亮度级) | 0.5 / 1.4 / 3.2 |
texelPerPx | 最细纹理带上,源纹素 / 设备像素(低于 1 表示被放大、发虚) | 0.45 / 0.9 / 1.6 |
shimmer | 视图偏移半像素后的平均差值 /(0.5 × 平均梯度),越低越好 | 3.2 / 1.9 / 1.15;预过滤表面约为 1,走样表面 3+ |
shimmer是最有技巧性的一个测量:它需要把相机视图平移半像素重渲染一帧(scorecard.mjs 的shimmerRatio()),如果表面经过正确预过滤,两帧差异应与梯度成正比(比值 ≈1);如果走样,半像素移动会产生远超梯度的跳变(3+)。texelPerPx则由 demo 的KiboriScore.texelPerPx()实时计算(demo.html:最细纤维带 230 周期/米 × 纹素/周期,除以每米像素数)。实测 demo 该项 9.69 分,shimmer = 1.13(接近预过滤理想值 1)。
8. 高光与粗糙度真实感(Specular and roughness realism)
这是 demo 中唯一"未达标"的评分项,也是最能体现这套评分卡价值的案例。
| 分数 | 看起来像什么 |
|---|---|
| 3 | 没有高光,或一个白色塑料感的热点(baseline 实测 4.5) |
| 6 | 一道光滑光泽,完全无视木纹 |
| 9 | 一道宽阔柔和的光泽横穿木板,遇到开放毛孔处粗糙度上升而被打断,永远不接近纯白(demo 实测 6.5,偏短) |
测量指标:
| 子指标 | 说明 | 锚点 |
|---|---|---|
sheenSpread | 模糊木材线性亮度的 p95 / p25 | 1.06 / 1.3 / 1.9 |
paintClip | 木材中接近纯白像素的占比(越低越好,"油"而非"塑料漆") | 0.05 / 0.01 / 0.0005 |
hlBreakup | 光泽最亮四分位内仍然存活的纹理(粗糙度贴图打断光泽) | 0.004 / 0.018 / 0.045 |
实现上(metrics.js):用 6 px 盒式模糊分离"宽泛光泽"与"木纹高频"(避免把纹理解成高光);hlBreakup只在高亮四分位内部统计高频能量,专门检查粗糙度贴图是否真正打断了光泽。实测 demo 该项仅 6.52 分,拖累项是hlBreakup = 0.01 → 4.29与sheenSpread = 1.32 → 6.11——如 SKILL.md 所记录的,两位"理论上的修复者"(整板清漆、各向异性 0.3)都抬高了数字却让木板更难看了,因此被当场否决。这正是"分数必须对照片负责"的实例。
如何诚实地阅读一张评分卡
rubric.md 用一整节专门警告"分数是会骗人的",并给出四条纪律:
- 指标都是代理(proxy)。有两件事任何指标都看不见:物体是否被读成"它本身"(一块匾,而不是一个托盘);光照选择是否有品味。处理办法:把渲染图交给一位没见过这些数字的独立评审人,取两方分数中较低的那个。
- 消融(ablation)是对指标本身的检验。
scorecard.mjs会逐个关闭渲染层并重测(scorecard.mjs)。如果某个层没有推动任何它应该推动的评分项,或者关掉它反而让总分上升,说明指标量错了东西,或该层没有赚回它的成本。demo 实测中关闭"工作室反射"(env)让总分+0.14(因为它抬高了阴影),这个结果被如实记录(last-scorecard.json 的ablation.env.drop = -0.14),而不是被调参调掉。 - 分数只在相同尺寸与 DPR 下可比。demo 在 1440x900 @1x 得 8.8,@2x 得 8.7(更多纹素,但灰尘光斑细于 7 px 测量窗口)。不同分辨率下的分数不能横向比较。
- 达标就停。当每项都达到目标,或某项因任务之外的原因进入平台期,就停止迭代。demo 的高光项停在 6.5~7.4:光泽是"宽阔"而非"独立高光",而能制造独立高光的两个杠杆(填满木板的清漆、各向异性)在 2x 裁剪下都会糊掉木纹或抹掉雕刻,于是当场被拒。
把评分卡跑起来:从 baseline 到 ablation
rubric.md 是"打分之眼",而 scorecard.mjs 是"打分之手"。它的工作流完整印证了 rubric 的机制:
# 1. 服务 demo 页面并安装 headless 浏览器 npm i playwright-core # 2. 跑一次完整评分(capture → 冻结时间 → 八项打分 → 逐层消融 → 写 JSON) node references/scorecard.mjs --size 1440x900 --dpr 1 --target 8 # 3. 可选:--sync 把 references/metrics.js 原样同步回 demo.html 的内联块 node references/scorecard.mjs --sync # 4. 可选:--generic 模式把任意页面(提供 regions.json)纳入评分 node references/scorecard.mjs --url URL --generic --selector canvas --regions regions.json关键点(scorecard.mjs):
- headless Chromium + 冻结时间:
KiboriScore.freeze(true)固定时间与相机摆动(freeze()会把时钟钉在 t=5.2,见 demo.html),否则"指标会随相机移动"; - 渲染与读取在同一任务内完成:
KiboriScore.render(nx, ny)与getImageData在同一次page.evaluate中执行,因此无需preserveDrawingBuffer(绘制缓冲在一次任务后即失效); - 固定尺寸与 DPR:
--size/--dpr决定可比性;结果写入 JSON,含all_on、baseline、ablation、cost、short与pass字段; - 退出码即 CI 信号:任何一项低于
--target时进程以退出码 1 结束(pass: false),可直接接进持续集成; - shimmer 需要第二帧:
grab(0.5, 0)用相机setViewOffset平移半像素重渲染,再与基准帧比较。
实测基线(last-scorecard.json):全部层关闭时总分为3.73(最低项 rays 0.75),全部开启后8.81(最低项 spec 6.52,唯一低于 8 目标的一项)。消融表还揭示了每层的真实贡献:关掉grain总分掉 0.94 且波及 texture/spec;关掉key掉 0.70 且波及 shadow/tone/texture;关掉shafts掉 0.31 且波及 rays;而关掉env反而 +0.14。这些数字正是 rubric"层必须赚回成本"原则的实证。
延伸:把这份 rubric 用到你自己的场景
rubric.md 的可迁移性来自两处刻意设计:
- 区域与指标解耦:所有测量都基于
regions()返回的帧比例坐标矩形。更换场景时,只需照 demo.html 的regions()模式重写世界点投影(demo 用RL(mesh, ...)把物体局部坐标投影到屏幕),metrics.js与锚点一行都不用动。PROMPT.md 的 Remix 提示正是这么要求的:换题材、换调色、重写regions()、先打 baseline、跑 ablation、迭代到每项 ≥8 或说明平台期原因。 - 锚点语义可复用:
anchor()的"三锚点 + 线性 + clamp + 可选 cap"机制(metrics.js)不限于木材——任何"从可测量物理量到主观质量分数"的映射都可以套用,包括那些"过高反而扣分"的 cap 型指标(光束亮度、眩光对比度)。
最后提醒:rubric 本身反复强调的"给独立评审人看 + 取较低分",说明再精密的代理指标也无法替代人的判断。用这套评分卡做的是把模糊的"感觉"变成可复现、可消融、可对比的量化证据——分数负责拦截回归,人负责最后的品味把关。
【免费下载链接】Skills
Agent skills for designers and builders using Codex, Claude, Cursor, and other AI coding agents
相关推荐
Three.js 木作照明评分卡实战:3d-wood-lighting-scorecard 的程序化木材光照管线与可复现的头less 10 分制质检体系
Three.js 木作照明评分卡实战:3d wood lighting scorecard 的程序化木材光照管线与可复现的头less 10 分制质检体系 木材只
3D Wood Lighting Scorecard:用 Three.js 程序化木纹与一扇窗暖主光,把"灯光像不像木头"量化成 0-10 分
3D Wood Lighting Scorecard:用 Three.js 程序化木纹与一扇窗暖主光,把"灯光像不像木头"量化成 0 10 分 导读:本文完整解
木材科技开发:gitignore 模板库中的木材项目规则
木材科技开发:gitignore 模板库中的木材项目规则 一、木材科技项目的版本控制痛点与 gitignore 解决方案 在木材科技开发(如 CNC 加工系统、
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考