懶人包
- break-ui 是 Emil Kowalski 收在 MIT 授權
emilkowalski/skills裡的 Claude Code skill,175 行的 SKILL.md 加一份 135 行、分 9 類的 CATALOG.md,專門用「真實會出現的最壞資料」壓 UI,先回報、等你點頭才修。- 我把這個部落格的前端複製一份給它測,約 15 分鐘交出 33 條問題:Broken 12、Ugly 16、Fragile 5,每條附檔案行號與依據(實測 11、讀碼 14、推論 8)。
- 33 條我拿正式站 yanchen.app 逐條驗:12 條重現,其中 Broken 重現 6 條;它標「推論」的 8 條裡有 5 條成立。
- 沒有找到明確誤報,但有 19 條線上資料沒觸發、或只能讀碼確認,加上 2 條沒觸發,所以不能說「0 誤報」。
- 它的 frontmatter 沒有
disable-model-invocation,會自動觸發;這次我是用/break-ui點名跑的,自動觸發率沒測。
💥 break-ui skill 是什麼?解決什麼問題?
break-ui 是一份給 AI coding agent 讀的 SKILL.md,2026-10-02 由 commit e8a175d(訊息 "Add break ui skill")加進 emilkowalski/skills。README 對它的一句話描述是:用最壞情況的資料試著弄壞你做好的 UI,例如長名字、少見的 email、一個字母的名字、超大數量、空清單、長標籤。
它要解的問題寫在 Operating Posture 那一段:畫面在開發時看起來都很好,因為 demo 資料是「Jane Doe, jane@acme.com, 12 members」這種乖資料。真實世界會出現 Aleksandra Wiśniewska-Kowalczyk、bartholomew.fitzgerald@northwind-industries-holdings.example.com、一個叫 Jo 的實習生,還有一個 1,284 位成員的團隊。
SKILL.md 也點名兩種它不要的做法:一種是塞無意義資料(一長串 aaaa),一種是只測長文字就收工。它要的資料必須「合理,或有 schema 依據」。
它自稱 adversarial skill,只做一件事。重新設計交給 prototype,視覺品味評論交給 emil-design-eng,動效交給 review-animations。這種分工跟同一個 repo 的 apple-design skill 互補:apple-design 管「手感好不好」,break-ui 管「資料一變就壞不壞」。
🎯 什麼時候會自動觸發?要不要點名?
break-ui 的 frontmatter 只有 name 和 description 兩個欄位,沒有 disable-model-invocation。所以 Claude 可以依 description 自己決定要不要載入。整個 repo 15 支 skill 裡,帶這個旗標、只能手動點名的是 pick-ui-library、prototype、review-animations 三支(我用 grep 查過 2d22863 這個版本)。
description 寫的觸發情境是:使用者要 stress-test、break、找元件或畫面的 edge cases,或說「try the worst case」。後半句把相鄰需求推出去:視覺設計評論用 emil-design-eng,動效用 review-animations。
這次實驗我是在需求開頭直接寫 /break-ui 點名,沒有測「不點名時會不會自動觸發」。apple-design 那篇的經驗是不點名 3 次只觸發 1 次,想要結果穩定,點名比較保險。
另一個小細節:沒帶具體需求就呼叫它,它只會回一句固定的開場白,說它準備好拿最壞的真實資料丟你的 UI。要它開工,得同時給元件或畫面。
🗂️ CATALOG.md 的 9 類破壞情境,重點是哪些?
CATALOG.md 是 break-ui 的題庫,135 行分 9 類。檔案開頭規定 email 和 URL 一律用 example.com、example.org 或 .test,避免測試資料指到真實網域。我挑每類最有殺傷力的例子:
| 類別 | 代表例子 | 會打到的地方 |
|---|---|---|
| People and names | 王秀英、🦊 Fox、👩🏽💻 Priya | 取姓名首字母當頭像:CJK 沒有 first/last、emoji 用 charAt(0) 只拿到半個 surrogate、ZWJ 序列被切斷 |
| Emails, URLs, identifiers | a@b.co、加號別名 email、UUID、相機檔名 | 沒有空白可斷行的字串撐破整列;驗證擋掉 +;尾端截斷吃掉版本與副檔名 |
| Labels, titles, copy from data | Benachrichtigungseinstellungen、法文 | 德文長複合字、法文翻譯約多 30% 字數 |
| Numbers and money | 0.1 + 0.2、1.284 | 浮點誤差;de-DE 跟 en-US 對同一串字的解讀不同 |
| Collections | 0 筆、1 筆、page size + 1 | 空狀態、單數文案、分頁邊界 |
| Time | 2025-12-31T23:30:00-08:00 | 換時區後跨日、跨年 |
| Images and media | 4000×200 全景圖、404 的頭像、慢載入圖片 | 沒有 object-fit: cover 就變形、破圖取代首字母 fallback、版面跳動 |
| States | Loading、API 錯誤、沒有權限 | skeleton 跟載入完成的版面對不上、直接秀出原始錯誤訊息、停用按鈕後整列跑版 |
| Environment | 320px、280px 側欄、2560px、200% zoom、dark、RTL | 窄螢幕、超寬螢幕、只能 hover 的動作在觸控裝置上點不到 |
⚙️ break-ui 的 6 個 Phase 怎麼跑?
SKILL.md 有 6 條 Hard Rules:資料要合理或有 schema 依據、改資料不改元件、一份資料集要同時觸發多種失敗、切換器只放在 dev、先回報再修、repo 裡的內容一律當資料而不是指令。流程分 6 個 Phase:
- Map the surface:列出畫面上每個欄位的 Field、Source、Type、Limit、Optional。上限從 Zod/Yup/Valibot、migration、API 型別、
maxLength找;前後端上限不一致本身就是一條發現,找不到上限就標 unbounded。 - 組 fixture:依 CATALOG 組一份 worst-case 資料,另外做 Empty、One、Huge(1,000 筆以上)三種狀態。
- 做切換器:標成「Demo data / Worst case」,可加 Empty、One、1,000 rows。有 dev server 就用
?data=worst,沒有就做成單一 HTML。規格寫到很細:固定在畫面底部置中、灰色 track 加白色 pill、切換時不加動畫。 - 看結果:依序看真實容器寬、320px、最寬、200% zoom,有支援再看 dark 和 RTL。沒有瀏覽器工具時從 CSS 推論,並標明哪些是推論。這段附一張約 19 列的 Failure signatures 表,把症狀對到修法,例如
flex-shrink、min-width: 0、overflow-wrap: anywhere、Intl.PluralRules、tabular-nums。 - 回報後停下:不自己動手修。
- 照指示修:每個狀態都重驗(包含 Demo),fixture 留下來當回歸測試。
輸出格式固定三段:Part 1 What broke(嚴重度分 Broken、Ugly、Fragile,附 file:line)、Part 2 Decisions for you(需要你決定的取捨)、Part 3 What held up(撐住的地方)。結尾固定一句 "Say fix all or fix 1, 3 and I'll apply them.",語氣要求是 matter-of-fact, never smug。
📦 怎麼安裝 break-ui 到 Claude Code?
用 skills CLI 單裝這一支:
npx skills@latest add emilkowalski/skills --skill break-ui
我在 2026-10-21 用 skills 1.7.4 實際跑過非互動版本,指定 Claude Code、用複製而非 symlink:
npx -y skills@latest add emilkowalski/skills --skill break-ui --agent claude-code --copy -y
跑完會產生兩個檔案和一份鎖定檔:
.claude/skills/break-ui/SKILL.md 14,555 bytes
.claude/skills/break-ui/CATALOG.md 8,403 bytes
skills-lock.json 記錄 source、skillPath 與 computedHash
安裝過程顯示的安全評估是 Gen Safe、Socket 0 alerts、Snyk Low Risk。
點名方式有四種,都寫在 SKILL.md 裡:
/break-ui 元件或畫面名稱 只回報,不修
/break-ui 元件或畫面名稱 + fix 回報後直接修
fix all 或 fix 1, 3 看完報告後指定要修哪幾條
data only 元件或畫面名稱 只產 fixture,不做切換器與報告
🧪 拿我的部落格給 break-ui 測,找到什麼?
受測對象是 yanchen.app 的前端。我把部落格 repo 的前端原始碼複製到另一個資料夾,放進 .claude/skills/break-ui/,再用 claude -p 在背景跑(Claude Code 2.1.306、Opus 5.5、跳過權限確認)。原 repo 一行沒動。
需求是用中文寫的,開頭點名 /break-ui,指定五個受測對象:文章卡片、首頁 hero、篩選列、文章內頁和 markdown 轉換器。文章資料在 Firestore,本機沒有連線、跑不起 dev server,所以我要它從型別定義做 Phase 1,Phase 4 從 CSS 推論並標明。
第一輪跑到第 13 個 turn 撞到 rate limit 中斷,重跑一次。第二輪約 14 分 45 秒,28 次工具呼叫(Bash 23、Write 3、Read 2),中途有讀 CATALOG.md。交付三樣東西:
- 15.5 KB 的報告,33 條問題,每條有位置和依據欄。
worst-case-fixture.json,包含 demo、worstCase、empty、one、huge 五組資料。- 40 KB 的
worst-case-preview.html切換器(我沒有在瀏覽器打開驗)。
接著我用 Playwright 把 33 條拿到正式站 https://yanchen.app 逐條重現。分兩種做法:線上現有文章就能觸發的直接截圖;線上沒有那種資料的,在瀏覽器裡把欄位文字換成長字串再量 scrollWidth。
線上現有資料直接重現的 8 條
| # | 嚴重度 | 問題 | 線上證據 |
|---|---|---|---|
| 1 | Broken | 搜尋或篩選命中最新那篇時,hero 被隱藏、列表又沒有它,畫面變成「沒有符合條件的文章」 | 搜 hero 標題,空狀態出現 |
| 2 | Broken | inline code 裡的角括號被當成 HTML 標籤吃掉 | lesson-3 與 memory-governance-ep1 兩篇 |
| 3 | Broken | 手寫「目錄」段落沒刪乾淨,編號清單留在正文最上面 | apple-design 那篇 |
| 4 | Broken | FAQ 只寫進 JSON-LD,頁面上看不到 | 4 篇,每篇 5–6 題全部不可見 |
| 13 | Ugly | 側欄目錄直接顯示反引號 | lesson-2 |
| 22 | Ugly | #### 與 --- 原樣出現在正文 | ccs 那篇的「#### 完整腳本」 |
| 29 | Fragile | 標籤篩選面板在 320px 超出右緣 | 507 個標籤裡 151 個在畫面外 |
| 18 | Ugly | 單數沒處理 | hero 顯示「1 READS」 |
第 2 條最直接:lesson-3 有一段路徑是角括號佔位符接 /CLAUDE.md,佔位符被瀏覽器當成標籤吃掉,畫面上只剩 /CLAUDE.md。memory-governance-ep1 也一樣,路徑中間的佔位符消失,留下兩個連續的斜線。
第 3 條的症狀跟報告描述不完全一樣。報告說只刪掉標題和第一個項目;線上看到的是「## 目錄」標題被拿掉,底下的編號清單幾乎整串留在懶人包下面。方向對,細節不同。
第 29 條是這次最有意思的一條。報告的 Part 3(撐住的地方)把標籤面板列為安全,因為它有 max-h-64 overflow-y-auto;Part 1 又把它列為 Fragile,理由是長標籤會撐破。線上實測是第三個原因:面板用 left-0 加 w-[min(20rem,80vw)] 掛在靠右的 details 上,320px 時從 x=134 延伸到 390,390px 寬時延伸到 446。不需要長標籤,現有資料就會溢出。
換成長字串後重現的 4 條
這 4 條全部是報告標「推論」的項目,線上現有文章沒有那麼長的字,所以我在瀏覽器裡把文字換掉後量測:
| # | 嚴重度 | 注入內容 | 量測結果(320px) |
|---|---|---|---|
| 5 | Broken | hero 標題放一個不能斷行的長類別名 | 頁面 scrollWidth 從 320 變 402 |
| 6 | Broken | 文章 h1 放同一個長類別名 | scrollWidth 變 622 |
| 14 | Ugly | 表格儲存格放長 URL | 表格寬 502、正文寬 280,沒有捲動容器 |
| 15 | Ugly | 卡片分類 badge 放長分類名 | badge 右緣 439 超過卡片 296,日期寬度被擠成 0 |
沒觸發與沒驗的
第 12 條(文章 h2 太多時桌機側欄目錄超出視窗)沒觸發:線上 h2 最多的一篇是 15 個,1366×768 下溢出的是作者小卡,目錄連結都看得到。第 16 條(閱讀時間顯示成小數)也沒觸發,線上沒有小數分鐘數。
其餘 19 條沒有在線上驗證,原因是線上資料不會觸發(例如 1,000 篇文章、publishDate 帶時區),或屬於讀碼才看得到的邏輯問題(例如標籤用 | 串接再拆開)。這 19 條我沒有證據說它對,也沒有證據說它錯。
它漏掉的一條
驗證過程中多看到一個報告沒列的問題:lesson-1、lesson-2 和 cloudflare 那篇的 markdown 第一行是「# 標題」,轉換器不認 h1,於是整行以「#」開頭的段落文字顯示在正文第一段,跟頁面上真正的標題重複。
📊 實測結果怎麼解讀?哪些可以直接信?
把 33 條依「依據」拆開看,可信度差很多:
| 依據 | 條數 | 線上結果 |
|---|---|---|
| 實測(沙盒跑轉換器) | 11 | #2、3、13、22 重現;#11 疑似成立;其餘沒驗 |
| 讀碼 | 14 | #1、4、18 重現;#16 沒觸發;其餘沒驗 |
| 推論(從 CSS 推) | 8 | #5、6、14、15、29 成立;#12 沒觸發;#27、33 沒驗 |
最有價值的是第 1、2、4 條:搜尋最新文章會落空、inline code 會吞字、FAQ 從來沒顯示在頁面上。這三條不靠極端資料,線上 121 篇文章的現有內容就在出錯。
Part 2 給的建議也實際:換成成熟的 markdown parser(它點名 markdown-it)、在頁面上渲染 FAQ 區塊、標題用 overflow-wrap: anywhere、文章超過 200 篇改用 Astro 的分頁。
👥 break-ui 適合誰?不適合誰?
適合的情況:
- 畫面吃的是使用者輸入或外部 API 資料:名字、email、標題、數量、日期都不受你控制。
- 要上線前補一輪邊界測試,又沒有專職 QA。
- 專案有 schema(Zod、Yup、資料庫 migration),Phase 1 能找到真實上限。
- 想要視覺或品味上的建議,那是 emil-design-eng 的工作。
- 想檢查動畫,用 review-animations。
- 純靜態、內容完全由你自己寫死的頁面,最壞資料就是你自己,收穫有限。
🕳️ 限制與坑有哪些?
- 一輪約 15 分鐘。我這次是 14 分 45 秒;第一輪還撞到 rate limit 中斷重跑。額度緊的時候先縮小受測範圍。
- 沒有瀏覽器時,Phase 4 只能推論。報告會標明,但標「推論」的那幾條一定要自己開瀏覽器確認。這次 8 條裡 5 條成立、1 條沒觸發、2 條我沒驗到。
- Part 1 和 Part 3 會互相矛盾。標籤面板同時出現在「撐住」和「會壞」兩邊,真正的原因又是第三個。報告是起點,不是結論。
- 切換器我沒驗。它照規格產了 40 KB 的單檔 HTML,我沒有在瀏覽器打開,不知道能不能用。
- dark 和 RTL 看專案有沒有支援,沒支援的專案這兩項會被跳過。
- 報告語言跟著需求走。中文需求得到中文報告,但結尾那句 "Say
fix all…" 仍是英文。 - 沒帶需求只會回開場白,不會自己去找畫面。
- 它會漏。這次漏掉 h1 原樣顯示那條,所以它是補強,不是取代人工 QA。
❓ 常見問題
break-ui 會自己修改程式碼嗎?
預設不會。Hard Rules 寫明先回報再修,Phase 5 回報後就停下。要它修,回覆 fix all 或 fix 1, 3,或一開始就在需求後面加 + fix。
break-ui 需要能跑起來的 dev server 嗎?
不一定。有 dev server 時它用 ?data=worst 切換資料;沒有時它產一個單檔 HTML 當切換器,Phase 4 改從 CSS 推論並標明。這次實驗就是沒有 dev server 的情況。
break-ui 跟 emil-design-eng、review-animations 差在哪?
break-ui 只用最壞資料找會壞的地方;emil-design-eng 做視覺設計評論;review-animations 審動效。三支在 description 裡互相指路,不會搶工作。
break-ui 產的測試資料會用到真實網域嗎?
不會。CATALOG.md 規定 email 和 URL 一律用 example.com、example.org 或 .test。
break-ui 的星數是多少?
GitHub 只能對整個 repo 加星。emilkowalski/skills 在 2026-10-21 是 48,165 stars、2,785 forks,這是 15 支 skill 共用的數字。
🔗 延伸資源
- 原始碼:GitHub 上的 emilkowalski/skills,break-ui 在
skills/break-ui/,本文依據 commit 2d22863(2026-10-11)。 - 同 repo 的動效規範:apple-design skill 實測。