Communitygithub.com

saltjsx/build-design-system

當有人想要從應用程式現有 UI 構建設計系統,或其中某個階段時使用,例如「從應用程式中提取 tokens」、「為我們的 Button 加入狀態」、「將硬編碼的顏色替換為 token」或「啟動一個設計系統」。將畫面遷移到現有系統元件上請使用 migrate-design-system。一個模糊的全應用請求則交給 design-system-boss。

build-design-system 是什麼?

這個技能(saltjsx/build-design-system)是一個高度自動化的工具,用於從現有應用程式的 UI 中逆向工程並構建一個完整的設計系統。它遵循一套嚴格的、逐步的流程,從分析應用程式的視覺外觀和元件開始,提取設計 token,建立可重複使用的元件,並在整個過程中通過視覺回歸和 linting 檢查來確保一致性。該技能旨在防止常見陷阱,例如引入應用程式中不存在的顏色或間距,並確保所有變更都有明確的記錄和理由。它支援在類似 Claude Code 或 Cursor 的 AI 代理環境中執行,通過執行本機腳本和與開發伺服器互動來自動化建立捕捉和比較視覺差異。這讓開發人員能夠以結構化、可稽核的方式將混亂的程式碼庫轉變為基於 token 的、有文件的設計系統,從而減少技術債務並提高 UI 一致性。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/saltjsx/compassneo/tree/HEAD/.claude/skills/build-design-system

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

建構設計系統

詞彙表位於 references/glossary.md,關於禁用項與寬度的預設值位於 references/taste.md。應用程式自身的外觀是來源。不得發明任何應用程式中尚未擁有的顏色、字型、陰影、漸層或動畫值,除非使用者選擇了設計來源並確認了範例。

腳本位於此技能的 scripts/ 目錄中。請從儲存庫根目錄使用 node 執行它們,並先閱讀 --help。scripts/capture.mjs 負責拍攝螢幕截圖,由 scripts/capture-guard.mjs 保護(後者會阻擋所有寫入),而 scripts/pixdiff.mjs 則負責比較它們。Capture 和 pixdiff 需要 Playwright 和一個 Chromium 瀏覽器,scripts/find-chromium.mjs 可以找到它或解釋如何安裝。

步驟

  1. 框架。 讀取 AGENTS.md 或 CLAUDE.md、清單檔和路由樹。用使用者的話寫下問題、回答問題的第一個可見變更,以及試點流程(問題所指名的流程,否則就是包含最多元件家族和一個帶有錯誤狀態的表單的流程)。將 .design-system/ 加入 .git/info/exclude,這樣任何筆記、捕捉或暫存檔案都不會被提交。使用使用者命名的分支作為運行分支,或者建立一個新分支,並將你開始使用的分支名稱寫入 .design-system/start-branch,land.mjs 會拒絕使用它。提供一次 references/taste.md,其禁用項保持未選取狀態,並將接受的副本儲存到 .design-system/taste.md。不要問其他任何問題。接受預設值,將其記錄為 default (unanswered) 並繼續。 當問題、試點流程、分支和接受的 taste 檔案都被寫下來時,此步驟完成。

  2. 庫存與基線。 列出每個畫面、其狀態以及是否寫入資料。使用 scripts/check-system.mjs --no-allowlist --no-self-test --json 計算原始值的出現次數(#fff、text-gray-500、p-[13px]),並將元件分組為家族。在進行任何編輯之前,以支援的最窄和最寬寬度(預設為 390 和 1280)捕捉每個畫面在每個狀態下的情況,每個寬度一次全新導航。在應用程式運行時(此處為連接埠 3000),將每個畫面列為 .design-system/surfaces.tsv 中的一行 surface<TAB>route<TAB>states,並將應用程式發送的每個寫入操作從其網路日誌複製到 .design-system/writes.txt 中,格式為 METHOD URL。然後執行 node <this skill>/scripts/capture.mjs --base http://localhost:3000 --kind before --out .design-system/captures --surfaces .design-system/surfaces.tsv --writes .design-system/writes.txt。如果沒有 --writes(或對於不發送寫入的應用程式使用 --no-backend),它會拒絕啟動;它會在瀏覽器開啟前證明每個寫入都被阻擋;它會儲存每個捕捉的無障礙樹;如果遺漏了任何捕捉,它會以退出碼 1 結束。刪除任何未使用的內容,並在一個單獨的提交中進行。 當每個畫面都有一個基線或一個已說明的 not captured 原因時,此步驟完成。

  3. Token。 根據角色對原始值進行聚類,根據用途命名它們,並將每個畫面與其前景色配對(references/tokens.md)。執行 token-mapping,直到每個原始值都對應到一個角色、一個合併或一個列出的例外。在容忍度內的合併是決策。超出容忍度時,為每個閘門開啟一個預設值為合併值的群集。在每個路由上進行每個相同值的交換。 當 token-mapping 報告例外清單外零差距,且 pixdiff.mjs 在容忍度為 0 時報告每個受交換影響的畫面差異為 0% 時,此步驟完成。

  4. 元件。 首先從頭到尾構建最常用的家族(references/components.md)。文字原始元件和小型文字原始元件與 Button 一起在第一波中發布。使用 component-docs 記錄每個元件。在擴散之前向使用者展示該家族,因為在畫面消耗系統後發現的核心錯誤將需要一次全面的修正(例如,仍繪製為紅色的禁用欄位、比 Input 高 2 px 的 Combobox、不換行的面板動作、默默失敗的檔案拖放)。 當每個規範元件都有一個註冊表行和一份文件,並且其 disabled、required、error 和長文字狀態在展示區中被捕捉並展示給使用者時,此步驟完成。

  5. 檢查。 將 scripts/check-system.mjs 和 scripts/oklch.mjs 複製到儲存庫的 scripts/ 目錄中,執行 --init,然後執行一次 --init-allowlist。一個規則只有在被發現失敗時才算數:在掃描的資料夾中植入一個違規,執行 --files <plant> --no-allowlist,看到命名該規則的退出碼 1,然後刪除該植入點。允許清單和棘輪只會縮小。一個禁用項應與其檢查規則在同一次變更中一起發布。複製規則應隨其豁免權一起發布(作用域限定於元素),用於必須保持原樣的文字(引文、術語、版本字串),以及用於機器或人員會貼到別處的負載字串(提示、API 範例、剪貼簿值),因為改寫它們會改變其他人接收到的內容。 當檢查在一個乾淨的克隆上以退出碼 0 結束,--self-test 結束時顯示「all as expected」,並且運行中添加的每個規則都在本次會話中在其植入點上被發現失敗時,此步驟完成。

  6. 試點。 使用一個 codemod(你必須逐塊閱讀)遷移試點流程。在遷移後使用與基線相同的命令、寬度、主題和資料進行捕捉,僅將 --kind 改為 after,然後使用 pixdiff.mjs 比較兩個資料夾。無法解釋的差異即為缺陷。使用鍵盤瀏覽流程,強制觸發其錯誤和載入狀態,然後在 after 捕捉上執行 ui-review。 當捕捉中的每個差異都可追溯到一個決策或閘門時,此步驟完成。一個沒有捕捉的渲染變更將被報告為 checks-only。

  7. 就緒狀態。 在遷移擴散之前,必須滿足以下五項審計,或持有已記錄的豁免。

  8. 交接。 重新執行計數。用數字報告系統涵蓋了哪些內容(首先是未回答的預設值),然後報告發現了什麼但未修復的內容(按優先級排序)。提供遷移方案及其規模。不要開始遷移。 當報告中的每個數字都指出了產生它的命令時,此步驟完成。

就緒狀態審計

在畫面消耗系統後發現的差距需要一次全面的修正。在畫面消耗系統前發現的差距只需要一個差距行。在步驟 5 結束時以及在第一波之前執行這些審計。將每個結果寫入 .design-system/readiness.md,並附上 verdict 詞。

  1. 插槽與屬性對等性。 每個舊有原始元件中具有呼叫點的屬性,在新原始元件上都有一個對應的屬性或一個差距行。
  2. 行為合約。 每個可互動的原始元件都有一個「觸發了什麼」的表格,每行一個測試(references/components.md)。
  3. 色調對等性。 每個可按壓和行原始元件都與每個狀態色調加上靜音色調進行交叉比對。每個空白儲存格都是一個差距行或聲明為不支援。
  4. 固定字串。 每個按角色名稱或文字進行的舊有測試查詢在新原始元件上都有一個預設名稱和一個標籤覆蓋。
  5. 最困難的畫面。 每個家族中最困難的一個呼叫點會在展示區中渲染,並附上螢幕截圖。

未就緒的家族不會被遷移。其畫面將繼續使用舊有元件。

永遠不要

  • 推送、發布或部署,除非使用者在此會話中要求這樣做。
  • 在運行開始時所在的分支上提交。請先建立運行分支。
  • 在骯髒的工作目錄中執行 stash 或切換分支。骯髒的工作目錄會在其自己的工作樹中取得運行分支(git worktree add)。
  • 刪除任何其他套件或公開 API 導出的內容。停下來,並將其及其匯入者列為閘門。
  • 默默地跳過一個步驟。如果應用程式無法建置或運行,報告應說明 code-complete, not runtime-verified 並指出哪些部分未被執行。
  • 稱自己的工作為 verified。在無法啟動其他代理的主機上,按順序運行步驟,從 diff 和捕捉的重新讀取中檢查每個步驟,並將這些 verdict 標記為 self-verified。

規則

  • 原始值的「味道」包括 #fff、rgb(、text-gray-500、p-[13px] 和 style={{ padding: 12 }}。每個都必須對應到一個語意 token 或一個列出的例外。
  • 缺少原始元件是一個差距行,永遠不能在畫面內部使用變通方法。
  • 在 delta E OK 2 範圍內的顏色合併,以及在 2 px 範圍內的間距合併,都是決策。邊框寬度、字重和緩動函數沒有容忍度。
  • 僅增加語意(名稱、角色、aria-current)的變更是決策。移除或重構語意的變更是閘門。
  • 錯誤:{saving ? "Saving..." : "Save"}。正確:空閒標籤保持不變, spinner 位於同一個盒子內,並設定 aria-busy。
  • 重複出現兩次的修正應被提升為檢查規則或腳本,而不是另一個句子。
  • 絕不能為了讓 diff 通過而編輯基線。標記正確程式碼的檢查應在檢查本身中修復,同時提供一個證明修復的植入案例,而不是透過扭曲程式碼。
  • 沒有腳本產生的計數,或從未被發現失敗的檢查,都不應被報告。

完成

檢查在乾淨的克隆上以退出碼 0 結束,每個規則都已被發現失敗,每個路由在生產建置上回應 200(capture.mjs --status),試點流程與其基線匹配(除了列出的預期變更之外),並且每個交接計數都來自腳本。

references/traps.md 按 ID 列出了行為陷阱。references/tokens.md 包含了層級、名稱、容忍度和動畫預設值。

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

相關技能