lens 是做什麼的?
透鏡 (Lens) 是一個 JSON 圖表 <lens>/model.json,可建構成一份自含式的 <lens>/index.html,任何人都能開啟並在該頁面上留言。<lens> 是它被建立時所在的資料夾(預設為 docs/lens)。<lens>/README.md 文件記錄了節點類型、關聯、主張形狀與完整性規則。建置流程會拒絕任何違反規則的模型,因此綠色的建置結果是首要檢查項目。
此技能本身的資料夾中包含 template/(會被複製到專案中的內容)、scripts/(競爭者輔助工具)以及 competitors.md。你可以在專案的 .claude/skills/lens/ 找到它,或是在全域安裝時位於 ~/.claude/skills/lens/;下方以 $SKILL 表示該資料夾。
需求:Node 20+ 與 git。不需要 package.json,無任何相依套件。
建立新的透鏡
-
選擇資料夾。 詢問使用者透鏡應存放的位置;預設為
docs/lens。拒絕覆蓋已存在的model.json。 -
複製範本(除了已建置好的
index.html以外的所有內容):mkdir -p docs/lens && cp -R "$SKILL/template/." docs/lens/ && rm -f docs/lens/index.html echo '[]' > docs/lens/ids.lock.json # 起始的 ID 並非你的 ID;從空的鎖定檔開始 -
訪談使用者,然後取代起始模型。
model.json內含一個虛構的「Acme Notes」範例,展示每一種常見的節點類型。保留其結構,但取代其內容。一次詢問一個主題,並提供具體的草稿供使用者修正,而不是提出空泛的問題:- 產品名稱 (
title) 與擁有者姓名(owner人物節點,id 為p-owner,除非使用者偏好其他名稱;其title會在每個觀點主張上顯示為「<姓名> 的觀點」); - 一句話描述產品目的 (
purpose,一個引用擁有者來源的view主張); - 核心循環,2–5 個有序的
loop-step; - 產品為誰而做(
avatars,包含人物誌地圖),以及他們的痛點(problems); - 他們已有的訪談或其他證據(
source+person節點;切勿憑空捏造引述或時間戳——如果沒有逐字稿,則記錄為擁有者的報告); - 已經上線的內容(
surface,shipped: true,附上真實截圖)以及僅是點子的內容(shipped: false); - 人們使用的替代方案(
alternatives); - 最多三個目前要驗證的賭注(
hypothesis節點,focus: 1|2|3)。 使用者所說的一切,若無證據支持,皆視為view(其觀點)或hypothesis;除非有來源和at時間戳,否則不得標記為observed。使用占位符名稱(例如「受訪者 A」),除非使用者希望在可能公開的檔案中使用真實姓名。
- 產品名稱 (
-
清理範例。 一旦沒有任何節點參考
assets/example.png,就將其刪除,並將螢幕截圖指向assets/surfaces/<surface-id>/<slug>.png。Surface 的code和adrs路徑相對於專案根目錄,且必須存在(將adrs指向專案存放決策記錄的位置,例如docs/adr/)。 -
建置與測試:
node docs/lens/build.mjs && node --test docs/lens/tests/*.test.mjs -
查看結果。 留言是根據瀏覽器的來源 (origin) 儲存的,因此請啟動伺服器來提供服務,而不是直接開啟檔案:
python3 -m http.server 8767 --bind 127.0.0.1 # 從專案根目錄執行 open "http://127.0.0.1:8767/docs/lens/index.html" -
如果使用者會追蹤競爭對手的廣告,建議在
.gitignore中加入docs/lens/assets/ads/**/*.mp4。提交model.json、ids.lock.json、index.html、assets/以及資料夾中的其他內容,並遵循專案本身的提交規則。
奠基工作
在詢問擁有者任何問題之前,請先閱讀相關的節點、其主張及其來源。提供一份具體的綜合摘要供其修正。對於一個 Surface,如果其行為至關重要,請檢查其命名的程式碼 (code) 和決策記錄 (adrs);決策記錄說明的是當時的決定,而非程式碼目前的狀態。
新增證據
每一項陳述都是一個主張,包含 kind、evidence 以及選擇性的 next:
- observed(聽聞/所見):某人說過的話或做過的事。使用
at(逐字稿的時間戳,或文件的章節)來引用來源。貼近原文引用或改寫;切勿升級含糊的用語(例如「可能有用」)。 - view(擁有者觀點):擁有者的解讀。它必須引用一個來源,且該來源的
people必須包含模型的owner。 - hypothesis(未驗證):任何未經測試的事物,包括代理程式的建議和實作點子。
- 假設也是一種節點類型:記錄每一項證據時,需包含
stance(supports或contradicts)和at。切勿設定信心度;focus假設上的信心度計量器是根據該證據在下一次建置時計算得出的(有不同受訪者支持則提升;有人反駁則降低一級;擁有者的觀點永遠不會提高信心度)。應像記錄支持證據一樣樂於記錄反駁證據。 - 每個薄弱的證據都應給予一個
next:一個足夠具體、可在通話中提出的問題。它會出現在「下一個對話」區塊中。 - 釐清誰說了什麼:一個由擁有者提出且其他人同意的主張,並非他們的需求。
- 一次新的訪談是一個
source,包含date、people、locator和簡短的takeaways,並由其所支持的主張引用。省略與產品無關的個人詳細資訊。僅在儲存庫為私人且受訪者同意的情況下,才將逐字稿歸檔至<lens>/sources/。
更新 Surface(在變更之後)
當變更改變了 Surface 的外觀或功能時,請在同一個分支中進行以下操作:
- 從正在運行的產品中,將變更後的狀態截圖捕捉至
<lens>/assets/surfaces/<surface-id>/<slug>.png(取代舊的截圖,保留 1–4 張)。 - 更新 Surface 的
screenshots項目:caption、capturedAt(今天)、origin: "app"、version。頁面會標記任何比 Surface 的code最後一次提交時間更早的截圖。 - 如果行為改變,更新
unique/situations;如果檔案移動,更新code/adrs。
一個全新上線的 Surface 是一個新的 surface 節點,帶有 shipped: true、至少一張截圖、指向其所解決問題的 serves 邊,以及指向其所實作的循環步驟的 implements 邊。
新增點子(來自腦力激盪)
一個曾經討論過但尚未建置的 Surface 是一個 surface,帶有 shipped: false;它會顯示在「點子」區域,視覺上有所區別。為它指定 unique(作為 hypothesis 主張)、situations、heard(人們所說的內容,附帶證據),以及作為 screenshots 的 mockups,並帶有 origin: "design"。當它上線時,將 shipped 設為 true,並用真實截圖取代 mockups。
新增內容支柱或點子
一個行銷主題是一個 pillar;一個具體的文章、影片或活動是位於其下的 content-idea,並帶有 format。將支柱或點子連結到其所針對的角色 (speaks-to),點子連結到其所展示的 Surface (features),以及已經在執行類似策略的競爭對手 (like)。在內容觸及人群之前,點子和支柱皆視為未驗證;記錄發生的情況,作為關於該點子的假設 (hypothesis) 上的證據。
新增市場洞察
來自外部研究的趨勢是一個位於「市場洞察」標籤頁的 insight。將文章記錄為「市場研究」來源(選擇性地在 sources/ 下保存快照),將其事實陳述為觀察到的 findings,並將其對角色的意義保留為觀點或假設,同時包含關於該來源限制的發現。將其連結 (bears-on) 到它所影響的所有事物。
新增或更新競爭對手
遵循 $SKILL/competitors.md 的步驟進行研究(使用真實瀏覽器檢查廣告,絕不繞過付費牆)、使用 scripts/add-product.py 新增產品、分階段捕捉廣告、使用 scripts/apply-staged-ads.py 套用(先檢查所有項目,然後一次性套用)、使用 scripts/smoke-ads.mjs 進行冒煙測試,然後提交(不包含 .mp4 檔案)。根據透鏡中的產品目的和重點假設進行比較,而非其行銷頁面,並將該比較標記為未驗證。
可用性發現不屬於透鏡內容
互動問題(一個沒人找到的按鈕、遺失的焦點狀態)應歸屬於團隊的議題追蹤系統。請在該處記錄它們,並僅在透鏡中記錄其產品意義(如果有的話)。
重新命名或移除
ids.lock.json 記錄了上次建置中每個可留言的 ID。消失的 ID 必須在 model.json 的 renamed 項目中進行映射("old-id": "new-id",或者如果是有意移除則設為 null),否則建置會失敗。這是保持現有留言附加到正確項目的關鍵。
變更透鏡本身
任何在 components/ 下的變更(例如視圖顯示的內容、路由、驗證、差異比對)都應從 <lens>/tests/ 中的一個失敗測試開始(使用 node:test;共用測試夾具位於 tests/fixture.mjs,僅使用虛構名稱)。將邏輯保留在純模組中;只有 components/app.js 會操作 DOM。然後執行測試,接著在瀏覽器中檢查相同的場景。
視覺化差異
當擁有者要求查看、審查或視覺化變更時:
node docs/lens/diff.mjs [rev] # 預設為 HEAD;輸出變更列表
python3 -m http.server 8767 --bind 127.0.0.1
open "http://127.0.0.1:8767/docs/lens/index.html"
綠色外框表示新增的項目,黃色表示已變更的項目;已移除的項目會以紅色列在橫幅中。每個新增或變更的列都會連結到其項目。變更是根據 ID 進行匹配的,因此單一主張的變化會凸顯出來,而不會影響整個卡片。在提交之前,請務必清除差異並進行檢查:
node docs/lens/build.mjs
grep -c LENS-V2-DIFF docs/lens/index.html # 必須輸出 0
重新建置與檢查
node docs/lens/build.mjs && node --test docs/lens/tests/*.test.mjs
然後在瀏覽器中查看受影響的視圖。留言是瀏覽器本地端與來源相關聯的;在切換環境前請先匯出它們。最後提供透鏡連結、變更內容、證據以及任何限制。