qodercli-bench-qwen3.8/02-f2e/README.md at main · QoderAI/qodercli-bench-qwen3.8 · GitHub
Skip to content

Latest commit

 

History

History
334 lines (244 loc) · 19.2 KB

README.md

File metadata and controls

334 lines (244 loc) · 19.2 KB

四个模型,同一批 18 道前端视觉题

Qwen3.8-Max、Claude Opus 4.8、GPT-5.6 sol、Claude Fable 5,跑同一套 FRONTEND-VISUAL-EVAL-2026-07.md 的 C01–C18,同一份 prompt 字节、同一组硬门、同一把尺子。

本文只讲一件事:把四份产物摆在一起,能看见什么,以及有多少是能量出来的。


一、先给结论

Qwen3.8-Max Claude Opus 4.8 GPT-5.6 sol Claude Fable 5
出活 18/18 18/18 18/18 15/18
过 G1–G3 硬门 17/18 15/18 17/18 15/15
单例生成中位耗时 202s 112s 288s 158s
同 6 例中位 %-of-max 53.8% 50.3% 69.1% 49.7%
记忆调色板(GitHub dark / Tailwind) 3/18 4/18 0/18 4/15
emoji 图标(A14 原始标记,见下注) 9/18 7/18 5/18 5/15
prefers-reduced-motion 2/18 1/18 6/18 1/15
transition: all 4/18 1/18 0/18 4/15
:focus-visible 0/18 1/18 4/18 1/15
prefers-color-scheme 0/18 0/18 0/18 0/15

一句话:GPT-5.6 sol 在这批题上明显甩开另外三个,而另外三个彼此之间的差距,小到需要看小数点。 53.8 / 50.3 / 49.7 这三个数落在同一档里;69.1 不是。

(A14 那行是 metrics.json 的原始正则命中,它会误报:GPT-5.6 sol 在 C01 命中的是 ✦✧ 星点装饰、在 C06 命中的是 ☾♥ 两个单色排版符号,都不是 emoji 图标。判分时逐条核过码点, 真正落实的比这行还低。反过来,Qwen 的 ☀🌧🍃❄、Opus 4.8 的 😴❤️⚖🏃、 Fable 5 的 🎉🎙✨✅🔗🔍🔒 都是货真价实的 emoji 当图标用。)

要注意 COMPARE.md 顶部那张表里 Qwen 的中位是 49%——那是 18 例的中位,另外三个是 6 例的中位, 两者不可直接比。上表的 53.8% 是把 Qwen 限制到完全相同的 6 例重新算的,这才是对齐的数。


二、Fable 5 少的那 3 例,不是模型的锅

C12_clone_shot、C16_walkman_3d、C18_img2three 三例,Fable 5 没有产物。翻 result.json:

"subtype": "error_during_execution", "duration_ms": 184297, "is_error": true,
"modelUsage": {"<synthetic>": ...},
"errors": ["Sorry, the system is busy right now. Please try again later."],
"error_code": 113

三次都是 error 113,都在 ~183s 上撞死,modelUsage 是 <synthetic>——请求根本没到模型。 这是上游繁忙,不是模型能力。所以:

  • 上面那张表里 Fable 5 的分母是 15 而不是 18;
  • COMPARE.md 里它的「过门 15/18」看着和 Opus 4.8 的「15/18」一样,但意思完全不同: Opus 4.8 是产出了却没过门(C10、C12、C14),Fable 5 是压根没产出。

本文所有评分只用四个目标都产出了的案例,所以这 3 例不进任何一个分数。


三、六个案例的正式打分

18 例里挑了 6 例做完整 8 维评分,每档两例,且限定四个目标都有产物的案例(这就排掉了 C12/C16/C18)。 Qwen3.8-Max 的 18 例分数早已判完,这次用它当锚:每一维都是先看 Qwen 在这一维上已判的证据落在哪一档, 再把另外三个放进去,四家因此坐在同一把尺子上。

案例 档位 预设(满分) Qwen3.8-Max Claude Opus 4.8 GPT-5.6 sol Claude Fable 5
C01_weather L1 信息卡片 (45) 42.3% 44.6% 74.9% 42.9%
C03_toolbar L1 工具型 (43) 64.4% 57.1% 61.0% 59.1%
C05_saas_landing L2 落地页 (47.5) 56.6% 55.6% 72.4% 58.7%
C06_health_dashboard L2 信息卡片 (45) 50.9% 50.2% 68.3% 50.8%
C15_procedural_planet L3 信息卡片 (45) 48.1% 40.1% 64.0% 39.0%
C17_chiptune_sync L3 信息卡片 (45) 57.3% 50.3% 69.8% 48.7%
中位 53.8% 50.3% 69.1% 49.7%

GPT-5.6 sol 拿下 6 例里的 5 例。唯一输掉的是 C03_toolbar——而且输得有道理,下面会讲。

逐维证据在 scoring/<target-id>/raw.json,渲染成表在各自的 SCORES.md, 单例卡片在 runs/<target-id>/<case-id>/score.md。


四、看图:差距在哪一层

C01 天气卡 —— 差距最大的一例

C01 四家横排

同一句 prompt(四种天气、深色背景、可切换),四种回答:

  • Qwen3.8-Max:CSS 画的插画最饱满,温度 32°/14°/18°/−3° 放在卡片角上,26px。
  • Claude Opus 4.8:最克制,也是唯一 axe 零严重项的一版。但全文 grep ° 只能搜到 rotate(...deg)——这张天气卡上没有任何一个数字。prompt 确实没要求温度,所以这不算不合规, 但 D2 因此无处可「主」:.cond 20px 对 .desc 12px 是 1.67 倍,8px 高斯模糊后卡片上找不到重点。
  • GPT-5.6 sol:唯一被「设计」过的一版。左标题右导语的编辑式页头,卡片带城市·时间·条件三段元信息, 36px/600 的温度对 10px 的 kicker 是 3.6 倍。全场唯一一份 G4_detail 任何等级都为空的产物。
  • Claude Fable 5:层级最弱。18px 字距标签对 14px 元信息 = 1.29 倍,温度被塞进 「18°C · 42 km/h」这行元信息里,h1 是 32px 的 font-weight: 300。

真正拉开分差的是响应式。四档视口摆开看:

C01 四家 × 四档视口

最右一列是 dark @1440——四家都和 1440 那列一模一样。prefers_color_scheme 在 18×4 例里命中 0 次,没有一份产物做了第二套模式。

390 那列则只有 GPT-5.6 sol 换了结构:

@media (max-width: 1050px) {
  .cards { grid-template-columns: repeat(4, 270px);
           overflow-x: auto; scroll-snap-type: x mandatory; }
}
@media (max-width: 680px)  { .cards { grid-template-columns: repeat(4, 82vw); } }
@media (prefers-reduced-motion: reduce) { ... }

四列网格在 1050px 变成横向 scroll-snap 轨道,680px 再变成 82vw 卡片。它 390 的 scrollHeight 正好是 844——页面没有变长,是变形了。另外三家都是 0 条 @media, 靠 flex-wrap 堆成 1619–1857px 的长条。这是 D7 满分判据被字面满足的唯一一次。

C06 健康看板 —— 「四张一模一样的卡」

C06 四家横排

Qwen、Opus 4.8、Fable 5 三家给出的是同一张页面:深色、四张等宽卡、四条一模一样的 面积 sparkline,不管这个指标是时长、心率、体重还是次数。这正是 A17 那条。

GPT-5.6 sol 换了结构:一张通栏的 82 分综合卡先把网格打断,下面才是 2×2 的指标卡。 62px 对 11px 是 5.6 倍,8px 模糊之后你只看得见那个 82。另外三家是 2.83–2.9 倍。

它也不是没代价:1440×900 下 scrollHeight 是 1042,这张看板在它自己的主视口里放不下, 最后一行在折线以下。另外三家都塞进了 900。

C05 SaaS 落地页 —— 三家写出了同一个页面

C05 四家横排

这一例是 §4.1 点名的已公开污染案例,结果也确实最像被背下来的:

Qwen3.8-Max Opus 4.8 GPT-5.6 sol Fable 5
Tailwind indigo 色值 #4f46e5 #4338ca #7c3aed #4f46e5 #4338ca #7c3aed #8b5cf6 无 #4f46e5 #4338ca #6366f1 #6d28d9 #818cf8
主视觉 斜线占位框「产品界面截图占位」 斜线占位框「产品截图占位」 画出来的产品界面 斜线占位框「产品界面截图占位 · 1200 × 900」
emoji 图标组 ✓ ★×15 🎙 🧠 ✅ 🔗 🔍 🔌 ✨ 无 🎉 🎙 ✨ ✅ 🔗 🔍 🔒

三个不同厂商的模型,在同一句 prompt 下收敛到同一批十六进制色值上。 Qwen 和 Fable 5 连大标题的写法都撞了(「开完会,纪要已经写好了」)。 而三家都把 hero 里最重要的那块视觉留成了一个空的斜线框——GPT-5.6 sol 是唯一一个真的把那张 产品界面画出来的。

这条可以扫全 18 例。统计每份产物里出现 ≥3 个 GitHub dark 官方 token(#0d1117 #161b22 #21262d #30363d #58a6ff #8b949e #e6edf3 …)或 ≥3 个 Tailwind slate/gray/indigo token:

Qwen3.8-Max Opus 4.8 GPT-5.6 sol Fable 5
≥3 个 GitHub dark token 1/18 3/18 0/18 1/15
≥3 个 Tailwind token 2/18 1/18 0/18 3/15

C01 上更直接:Qwen、Opus 4.8、Fable 5 三家的背景都是 #0d1117、描边都是 #30363d—— GitHub 深色主题的官方 token,一个字没改。Opus 4.8 和 Fable 5 更是共用同样的六个 (#0d1117 #161b22 #21262d #30363d #8b949e #e6edf3),只在强调色上分岔 (Opus 4.8 用 #58a6ff,Fable 5 用 #388bfd)。 GPT-5.6 sol 的背景是 #080b11,描边是 rgba(255,255,255,.09),一个 stock token 都没有。

「AI 味」在这里不是玄学:它是可以 grep 的。

C03 工具栏 —— GPT-5.6 sol 唯一输掉的一例

C03 四家横排

工具型预设把 D8(状态完成度)的权重拉到 2.0,这一维就决定了排序。

GPT-5.6 sol 的工具栏本身是四家里做得最好的:唯一一个在同一个元素上给出双层阴影 (0 12px 36px + 0 2px 8px,环境影 + 贴地影,D4 的满分判据),同心圆角 (工具栏 14px 14px 0 0 对页脚 0 0 14px 14px),100/120/140/160ms 的真实时长梯度, 33 个 aria 属性、3 条 :focus-visible。

但它下面那页文档只有一个标题加两段话。没有长文本、没有禁用项、没有溢出—— 能演的状态都没有内容去演。而 D8 权重 2.0 的预设不会因为「没写内容」就少扣分。

另外三家在这一维给得更多:Opus 4.8 和 Fable 5 都写了完整的产品文档(Fable 5 还带代码块), Qwen 的文档区反而是空的(只有占位提示),但它交出了四家里最重的编辑器外壳—— 18 个内联 SVG 图标、下拉菜单、插入链接/图片的对话框、全屏模式, 四种真实按钮状态,以及 10.5 倍的组间距比。这一维它拿了 4 分,是六例里唯一一个 4。

顺带一提,四家里只有 GPT-5.6 sol 在这一例写了 @media——一条。另外三家是零条。


五、截图会骗人:C17 是个极端例子

C17_chiptune_sync 的四张 1440 截图长这样:

C17 四家静态截图

四张启动页。gate 的 SETTLE_MS 是 3500ms,而这一例的所有内容都在点了 START 之后才存在。 按静态图判,这一例只能判「四家都做了个开始按钮」。

按下去之后:

C17 四家运行中

(更清晰的版本:C17_chiptune_sync-motion.mp4。 Playwright 的录屏没有音轨,所以这里看到的是可视化层,不是声音。)

  • Qwen3.8-Max:径向频谱射线绕着一颗蓝色核心,底部四点进度。
  • Claude Opus 4.8:环形频谱 + 通栏波形 + 真正的播放器控件——STOP、可拖的进度条、 4.5 / 30.0 计时,四样东西读同一个时钟。四家里唯一有 transport UI 的。
  • GPT-5.6 sol:整个 synthwave 场景——扫描线太阳、透视网格、车、EQ 条, 页眉写着 128 BPM · F MINOR · WEB AUDIO SYNTHESIS,页脚写着 BAR 03 / 16, 证明画面是挂在乐曲时钟上而不是 rAF 计数器上。
  • Claude Fable 5:段落标题跟着编曲走——BUILD 在结构转折点浮出来, 底下是 16 步的 sequencer。它也是这 6 例 24 份产物里唯一一个用了 cubic-bezier 的。

D6(动效时序与缓动)这一维,静态截图根本没有证据可用。这就是 harness/motion_capture.mjs 存在的理由:它复用 gate.mjs 的服务、入口解析和 Chrome channel,所以镜头下的页面和门下的页面 是同一个字节的页面。

其余动态案例:

案例 GIF MP4
C01_weather 四种天气切换 gif mp4
C11_scroll_motion 滚动叙事 gif mp4
C13_canvas_cube gif mp4
C14_glass_marbles gif mp4
C15_procedural_planet gif mp4
C16_walkman_3d gif mp4
C17_chiptune_sync gif mp4
C18_img2three gif mp4

C11 那一条录的时候踩了个坑,值得记一笔:四份产物都写了 scroll-behavior: smooth, 于是浏览器把我逐帧发的 scrollTo 全部动画化了,四格按各自页面高度滞后了不同的量—— 那是镜头的毛病不是产物的毛病。修法是录制期间强制 scroll-behavior: auto, 也就是这些页面自己在 prefers-reduced-motion 分支里做的同一件事。


六、三家共享的三个洞

把 18 例的可 grep 信号拉平,有三条是四家一起塌的,其中三家塌得一样彻底:

1. 暗色模式不存在。 prefers-color-scheme 在 69 份产物里命中 0 次。 模型先选中的那套配色就是唯一一套。gates.json 把 respondsToDark 和 alreadyDark 分开报,是因为「天生就是深色」不等于犯了 A20;但「压根没有第二套」是四家共同的事实。

(顺带说:metrics.json 里的 A20_light_only 标记在 69/69 上都是 true, 它其实只是 prefers_color_scheme=false 的代理,作为检测器是废的。Qwen 的校准轮 已经把它归一化成「只在源码确认为纯浅色时命中」,本轮沿用同一口径。)

2. 焦点环基本没人做。 :focus-visible 命中 Qwen 0/18、Opus 4.8 1/18、Fable 5 1/15、 GPT-5.6 sol 4/18。D8 因此被结构性压在 3 分附近。

3. 响应式多数是「重排」不是「断点」。 六例评分里,@media (min|max-width) 的命中: Qwen 1/6、Opus 4.8 1/6、Fable 5 1/6、GPT-5.6 sol 6/6——而且三家命中的都是同一例 (C05 落地页),这读起来像一条被背下来的落地页惯例,而不是一次判断。 G3(390 无横向滚动)在 69 份产物里过了 64——这道门几乎筛不出东西, 因为 flex-wrap、auto-fill 网格、clamp()、乃至 overflow: hidden 都能让它过。 真正的责任在 D7 的人工判读上,不在这道门上。

维度中位(0–5)把这三条摊开看:

维度 Qwen3.8-Max Opus 4.8 GPT-5.6 sol Fable 5
D1 布局节奏 3 2.75 4 2.75
D2 层级对比 3 2.75 4 3
D3 色彩系统 2.5 2.75 3.5 2.75
D4 形状语言 3 2.5 3 2.5
D5 排版层级 3 2.5 3.5 2.5
D6 动效时序 2.25 2.5 3.25 2.5
D7 响应式 2.25 2.5 3 2.5
D8 状态完成度 2 1.75 2.75 1.75

没有一维超过 4。四家的共同上限,是"看着完成了但没做过真产品"—— line-height 经常一条都不写(Opus 4.8 的 C01 是 433 行里零条,Fable 5 的 C06 是 389 行里零条), font-variant-numeric 在满屏跳动的数字上普遍缺席,阴影多数是单层。


七、这套尺子自己的毛病

写完得说清楚哪些数是不能全信的:

  1. canvas 类案例的 D1/D3/D4/D5 测的是 HUD,不是画面。 C15、C17 的 DOM 只有 16–51 个元素,其余全在一张 <canvas> 里,CSSOM 爬虫看不见。这几维只能靠渲染帧和动态录像判, metrics.json 只用来判外壳。Fable 5 的 C17 spacing_distinct=1(全文档只有 18px 一个间距值) 是 D1 零分判据被字面命中的唯一一次,但那也只是它外壳的事实。
  2. G6 会误判。 GPT-5.6 sol 的 C06 是一张浅色看板,但 gates.json 报 alreadyDark=true——因为它的 body 背景是 rgba(0,0,0,0),探针采到了透明元素。 这一例的 A20 是靠读源码确认的,不是靠门。
  3. 判分是单评委单轮。 源文档要求 ≥3 位独立评委取中位,本轮是一位评委一轮, 靠 Qwen 已判的 18 例当锚做的跨目标对齐。方法记在 scoring/<target-id>/calibrated.json 的 method 字段里,也印在各自 SCORES.md 顶上。
  4. 6 例不是 18 例。 上面所有中位都是 6 例的中位,逐档只有两个样本。 方向(69% vs 50–54%)稳,具体小数不稳。
  5. C05、C15、C01 在污染名单上。 §4.1 明确点名 SaaS 落地页、程序化行星、天气卡属于已公开用例, 且本轮没有做任何 X1–X6 扰动。C05 那张「三家撞同一批色值」的表, 与其说是能力差,不如说是记忆差——但这本身就是要测的东西。
  6. 成本没法比。 三个 daily catalogue 的目标都记成 0 credits,只有 Qwen 有真实计费 (27 例 228.5 credits)。表里的耗时是真的,钱不是。

八、怎么读这个结果

如果只带走一句:这批题上真正区分模型的不是「能不能做出来」,而是「做出来之后长什么样」。

硬门几乎筛不出人——G1/G2/G3 的通过率是 64/69。四家都会写 canvas、会写着色器、会调 three.js。 差距全在门后面:有没有一套色彩 token 而不是抄来的 stock 调色板, 主数字有没有大到 8px 模糊之后还找得到,断点是换结构还是只换宽度, 以及——最能说明问题的——hero 里那张产品图,是画出来了,还是留了个斜线框。

GPT-5.6 sol 在这六项上系统性地做对了,代价是最慢(单例中位 288s,是 Opus 4.8 的 2.6 倍) 和最容易在对比度上翻车(C05 五个 serious 对比度节点,是它那套 lime-on-cream 配色的直接代价)。 Opus 4.8 最快、最克制、a11y 最干净,但也最容易交出一张没有数字的天气卡和一页没有任何动效的落地页。 Fable 5 和 Opus 4.8 像得可疑——同样的 GitHub token、同样的 Tailwind indigo、 C11 里同样落在一个「四步」流程段——但状态完成度上它是全场最认真的那个(C06 里 19 处空态引用)。 Qwen3.8-Max 在这六例上不输给两条 Claude 路由,而它是四家里唯一花了真钱的那个。


复现

cd fv
python3 harness/article_media.py all                  # 所有 quad / grid 图
python3 harness/motion_montage.py                     # 8 个动态案例的 mp4 + gif
python3 harness/motion_montage.py --skip-capture      # 只重新拼,不重录
python3 harness/make_scorecards.py --target <id>      # score.md + SCORES.md
python3 harness/compare.py                            # COMPARE.md

图与视频全部来自 runs/<target-id>/<case-id>/shots/ 和同一份 work/, 没有重新生成任何产物,所以每一张图都能追回到某道门实际看过的那一帧。