Felimet Hub — 網站維護憲章(給 AI 維護者)
這個 repo 是 Felimet Hub 個人網站(線上 www.jmcores.com)的原始碼,平台是 Mintlify(docs.json 驅動的文件站),雙語(繁體中文 zh-Hant 為主、English 為輔)。設計基調 wabi-sabi 暖色。 維護者預設用自然語言下指令(例:「幫我加一篇關於 vLLM 部署的筆記」「把 Schlieren 那篇標成精選」「準備發布」)。本檔 +.claude/skills/ 是把那些自然語言對應到正確、可重現操作的單一事實來源。動手前先讀本檔對應段落,不要憑印象改。
1. 環境與指令(本地驗證不需帳號)
| 動作 | 指令 | 說明 |
|---|---|---|
| 安裝/驗證設定 | npx -y mint@latest validate | strict build 驗證,exit 0 才算過。CI 與發布前必跑 |
| 本地預覽 | npx -y mint@latest dev --port 3001 | port 3000 常被占,固定用 3001。背景跑 |
| 壞連結掃描 | npx -y mint@latest broken-links | 發布前選用 |
| 重產畫廊資料 | node scripts/gen-gallery.mjs | 改任何畫廊文章 frontmatter 後必跑 |
mint dev 起來後 curl 輪詢 http://localhost:3001/ 回 200 再截圖。收工用 PowerShell Get-NetTCPConnection -LocalPort 3001 -State Listen 找 PID kill。
HMR 規則(重要):
.mdx/.css/.svg改動 → dev 熱更新會生效。docs.json/snippets/*.jsx改動 → 必須重啟 dev,HMR 不重載,會 serve 舊 chunk 騙人。
2. 目錄結構與檔案落點
images/,多圖的文章開子資料夾(如 images/cuda-setup/fig1.png),MDX 以絕對路徑引用 /images/cuda-setup/fig1.png。
3. Frontmatter Schema(畫廊靠這些欄位)
每篇納入畫廊的文章(projects / notes / publications,overview 除外)frontmatter 至少:4. 雙語原子規則(i18n 不能半開)
docs.json 的 navigation.languages 一旦啟用,每個語言的內容必須齊全,否則切到該語言會空白破頁。
鐵則:任何納入導覽的頁面,root(繁中)與 en/(英文)必須同時存在、同時登記進 docs.json 的兩個語言區塊。 新增一頁 = 建兩個檔 + 改 docs.json 兩處。只做單語 = 破站。
- root 路徑:
notes/foo/bar.mdx→ 網址/notes/foo/bar - en 路徑:
en/notes/foo/bar.mdx→ 網址/en/notes/foo/bar - 英文頁的內部連結要加
/en前綴。
5. 畫廊維護
- 資料來源:
scripts/gen-gallery.mjs掃本 repo root +en/的 frontmatter,輸出snippets/gallery-data.jsx(exportsprojects/notes/publications+projectsEn/notesEn/publicationsEn)。 - 改了任何畫廊文章的 title/description/tags/featured/order/draft → 跑
node scripts/gen-gallery.mjs,否則畫廊不同步。 - GitHub Action(
.github/workflows/update-gallery.yml)會在 push 改內容時自動重產,但本地驗證前自己先跑一次比較準。 gallery-data.jsx標頭寫「自動產生勿手改」,要改畫廊內容去改來源 MDX frontmatter,不是改這個檔。
6. 設計系統(沿用,不要亂動)
- 色票(docs.json colors):primary
#bf7551(sienna 主互動色)、light#cf8a68、dark#a85f3f。背景 cream#F9F7F2/ slate#1F1F21。 - 字型(docs.json
fonts):heading Crimson Pro、body Noto Sans TC。兩者皆 Google Fonts,採 family-only 寫法 = Mintlify 自動走 Google Fonts API 載入(官方:指定 Google Font family 名即自動載入,無需 source URL)。不要為它們加source,那會切成自架 woff2、脫離 Google Fonts API。要換字型才動 family,否則別碰。 - 圖示(docs.json
icons.library: "lucide"):全站icon=走 Lucide,所有 icon 名稱必須是 Lucide 名(非 FontAwesome)。新增頁面用 Lucide 名(如triangle-alert非warning、mail非envelope、file-text非document)。Lucide 核心已移除 brand icon(github/linkedin 等):brand 用icon={<svg … fill="currentColor"/>}內嵌 SVG(about 頁的 GitHub/LinkedIn/ORCID 即此法),保留品牌外形又隨主題色。 - 社群分享(docs.json
seo.metatags):Open Graph + Twitter Card,全站預設images/og-cover.png(1200x630 品牌卡,由scripts/og-cover.html經 Playwright 截圖產生)。細節見 §8.4。 - logo:一體式 wordmark SVG(
images/logo-wordmark.svg亮 /logo-wordmark-dark.svg暗,含 JM mark + Georgia「Felimet Hub」字)。docs.json logo 指這兩個。mark.svg(純 JM)目前未用於 nav,留作他用。 - 自訂色一律走
style.css的具名 class(如畫廊.g-*),不要用var(--sl-*)(那是 Starlight 變數,Mintlify 沒有,會 fallback 出錯)。暗色模式靠html.dark。
7. 部署(這步要本人,AI 做不了;步驟已查證 Mintlify 官方文件)
新站走 Mintlify 託管(app.mintlify.com),不是 Cloudflare Pages(舊 Astro 站才是)。自訂網域 =felimet-hub.jmcores.com(子網域,非 www)。流程:
- jmcores-docs 推上 GitHub repo(已建:
github.com/felimet/felimet-hub,private)。 - app.mintlify.com → 裝 Mintlify GitHub App 連 repo(Settings → GitHub App → Install)。之後 push 自動 build+deploy。
- dashboard 加自訂網域
felimet-hub.jmcores.com→ 它給兩筆 TXT(_acme-challenge.felimet-hub、_cf-custom-hostname.felimet-hub)先加進 Cloudflare DNS,等兩筆綠勾驗證過再動 CNAME。 - CNAME:
felimet-hub → cname.mintlify.builders。Cloudflare 這筆設 DNS-only(關 proxy/灰雲) — 官方明講開 proxy 會擋憑證簽發。 - (子網域不影響舊站)舊 www/根網域的 Cloudflare Pages 記錄可保留;felimet-hub 是新獨立子網域。
- 等 DNS 傳播(1-24h),docs.json 設
canonical指向 felimet-hub.jmcores.com。
7.1 版本控制與部署流程(每次修改都版控)
- repo:
github.com/felimet/felimet-hub(private)。預設分支main。 - 每次修改後 commit(預設只 commit,不 push):Conventional Commits(
feat:/fix:/docs:/chore:/refactor:),單一職責,body 說 why。改畫廊文章 frontmatter → 先node scripts/gen-gallery.mjs再 commit。 - push 只在使用者明說「push」時才做(使用者偏好,2026-06-08 起)。因為 push = 觸發 Mintlify 自動部署上線,使用者要自行掌控何時上線。平時累積 commit,等他說 push 再一次推。
- push 到
main後才會 → (a).github/workflows/validate.yml跑mint validateCI;(b).github/workflows/update-gallery.yml自動重產 gallery-data;(c) Mintlify GitHub App 自動 build+deploy(這才是「自動部署」,不是 GitHub Actions — Actions 只做驗證與畫廊重產)。push 前若遠端有新 commit(CI gallery 或 PR)先git pull --rebase。 - 機密永不進 git(
.gitignore已排除.env*、node_modules、.mintlify、.playwright-mcp、tmp/)。
8. 踩雷清單(前人流血換的,照做省時間)
- snippet 常數放元件內:Mintlify snippet 只認 export 的元件,module 層級的
const不在 render scope → ReferenceError 整塊空白。常數寫進元件函式內。 - 改 snippet / docs.json 要重啟 dev:HMR 不重載這兩類,會 serve 舊版。
- 沒有
var(--sl-*):Starlight 變數在 Mintlify 不存在,誤用會 fallback(例:暗色卡片變白底、文字隱形)。用 style.css 具名 class。 - 原生 HTML 屬性要轉 JSX:MDX 裡
style="..."字串 /frameborder/class會 React error #62 整頁 500。要style={{物件}}、className、JSX 屬性。 - SVG logo 切邊:先查 SVG 內部殘留的
clipPath(會把內容裁回舊框),不要只調 viewBox。<img>載的 SVG 吃不到 web font(Crimson Pro),文字寬不可靠 → 要嘛 textLength 釘死、要嘛轉 path、要嘛用已內嵌字體的 SVG(現用的 wordmark 內嵌 Georgia)。 - content 頁圖片 404:多圖文章的圖片子資料夾要完整放進
images/,MDX 用絕對路徑/images/<夾>/<檔>。發布前 grep 全站圖片引用對檔案存在性。 - Powered by Mintlify:免費/Pro 用 CSS 隱藏違反 ToS(white-label 是 Enterprise)。現 style.css 有隱藏規則 + 警告註解;反悔刪那條即可。
- draft 文章:
draft: true不上站、不進畫廊。目前約 13 篇草稿刻意不遷,要補才動。 - footer 最多 4 欄:docs.json
footer.links超過 4 個 group → validate 直接擋(maximum of 4 links columns)。要多分類得合併。現況 4 欄=探索 / 學術(ORCID、WoS)/ 連結(GitHub、LinkedIn、Email)/ 實驗室(ISSP & MES LAB、IMES LAB)。 - copyright 行可點連結 = 自訂 JS:Mintlify footer 無自由文字欄、CSS
::after是生成內容不可點。copyright 行(含可點的「隱私權保護政策」→ /privacy)由footer-copyright.js注入真 DOM(#custom-copyright),樣式在 style.css。Mintlify 會自動載入 repo 根目錄任何.js(等同每頁<script>,官方 /customize/custom-scripts)。SPA 換頁用 MutationObserver + id 去重保連結持續存在。改 copyright 文字/privacy 連結就改這支 .js。
8.1 內容標點與用語規範(house style,發布前必檢)
- 全站禁 em-dash(
—U+2014),以及當句中破折號用的 spaced en-dash(–U+2013)。 句中破折號一律改寫:英文內文視語氣用:/;/,,中文內文用全形:/;/,;對偶插入語(A — … — B)改括號或前後逗號。 - 例外(屬正確排版,保留):數字與範圍的 en-dash(
60–100°C、0–250、頁碼2345–2367);程式碼、識別符、CLI 旗標、英文複合詞裡的連字符-。 - 驗收:發布前
rg -n '—' **/*.mdx應 0 命中(數字範圍的 en-dash 可留)。zhtw-writing這類寫作指南也照清,它沒在講 em-dash 本身,內文破折號一樣換掉。 - 固定術語:journey 那組 tag 用
Agency Agents(不是 AI Agency / Agentic AI;About 內文的「Agentic AI」是標準術語,另計);標註(不是標注)。中文用語照 CNS/IEEE 台灣慣例(資料 / 軟體 / 網路 / 演算法 / 畫格 / 位元組)。 - 來源:使用者全域偏好「不用 em dash 跟 en dash」+ 2026-06-08 全站清除指令。新增 / 改寫任何
.mdx都套這條,別把 em-dash 帶回來。 - 英文半形標點(所有頁面):英文片段/語句一律用半形直引號
'"(ASCII),不用彎引號'’“”或全形'"。中文內文照舊用全形標點。驗收:rg -nP '[\x{2018}\x{2019}\x{201C}\x{201D}]' en/應 0 命中。
8.2 專案頁模板(projects/*.mdx,2026-06-08 起固定)
9 個專案頁統一這套結構,新增專案照抄。黃金範本:projects/gpustack-api.mdx + en/projects/gpustack-api.mdx。
- 內容來源:從該 repo 的 README 與
docs/提取真實內容(gh api "repos/felimet/<repo>/readme" -H "Accept: application/vnd.github.raw"),不要憑 frontmatter 或印象編。標題與內文不誇大,像作者本人寫的,去 emoji / badge / 行銷詞。 - 章節順序(名稱可依內容微調):頂部 tag 列(inline code 以
·串,與 frontmatter tags 一致)→ 專案概述 → 核心功能 → 專案架構 → 技術棧(選用)→ 快速開始 → 配置比較(多方案才放,表格)→ 注意事項 / 安全提醒(<Warning>)→ 實際應用面 → 相關連結。 - 專案架構用互動式
<ArchFlow>元件(import { ArchFlow } from '/snippets/arch-flow.jsx';放 frontmatter 後):資料流/管線轉成nodes={[{ label, detail }, …]}(4-7 個,en 頁加lang="en"),點/hover 看各階段說明。目錄/檔案樹不是流程,維持 fenced code block。無真正流程的頁(如 SAM2)不硬塞。 - 快速開始用
<Steps><Step title="…">元件(非 markdown 數字清單),渲染為編號圓圈 + 標題 + 框起內容(使用者指定的呈現,適用所有有步驟的頁面)。 - 相關連結扁平化:底部
## 相關連結/## Links用 markdown bullet 清單,- GitHub:[felimet/<repo>](url)+ 官方外部文件。不用<Card>做連結、不寫「原始碼」、不放內部/notes/...連結(多為死連結)。 - 雙語原子:zh
projects/<slug>.mdx與 enen/projects/<slug>.mdx同步,frontmatterdate/order不動,tags各專案獨立。
8.3 互動元件設計系統(可重用、跨頁含 Notes)
頁面不只放靜態文字,可嵌入量身的互動 React 元件提升理解與記憶點。此概念不限專案頁,Notes、Publications、About 等任何.mdx 都能用。 參考來源:Claude Code docs 的 Explore-the-directory / context-window 互動 widget。
設計語言(所有互動元件共用):
- 放
snippets/<name>.jsx,export const Name = ({ ...props, lang = "zh" }) => {…}。 - Hooks 直接用(
useState、useEffect為 Mintlify snippet 全域,免 import);常數寫元件函式內(module 層級 const 會 ReferenceError 整塊空白)。 - 自帶
<style>{css}</style>:用 CSS 變數定義 wabi-sabi 暖色(sienna#bf7551/亮#cf8a68),.dark .x-root{…}覆寫暗色,不要用var(--sl-*)。手機加@media (max-width:…)降為單欄。 - 雙語:吃
langprop(en 頁傳lang="en"),UI 字串與資料分 zh/en。資料盡量由 props 傳入,元件本身與內容解耦以利重用。 - 接入:MDX frontmatter 後
import { Name } from '/snippets/name.jsx';,內文<Name … />。 - 圖示:元件內用 Lucide,但 不要
importlucide-react(Mintlify snippet 沙箱無 bundler,import npm 套件會整塊空白)。改為內嵌 Lucide SVG(fill="none" stroke="currentColor",JSX camelCase 屬性strokeWidth/strokeLinecap/strokeLinejoin),靠 CSS 變數上色。現況:ArchFlow=workflow、OptionPicker=layers、StaleValidator=signal各一個 header icon;UploadDemo 的上傳(cloud-upload)/ 檔案(file/package)/ 完成(check)全為內嵌 Lucide。 - 驗收:
mint validate綠 +mint dev起來用 Playwright 實測互動(點擊/切換/動畫)與明暗兩模,截圖存證。
ArchFlow(arch-flow.jsx):資料流/管線,點階段看說明。資料流貼切的頁用。OptionPicker(option-picker.jsx):可重用多方案/版本選擇器,options=[{name,badge?,recommend?,specs:[[k,v]],note}]。Bitwarden 已用;RustDesk 版本、SAM2 安裝路徑、Label Anything 後端等都餵不同資料共用。StaleValidator(stale-validator.jsx):溫濕度頁專用,撥四訊號看 stale 判定。UploadDemo(upload-demo.jsx):R2 頁專用,上傳進度動畫 mock。
8.4 SEO 與 Open Graph(社群分享卡,docs.json seo)
- 全站 meta 在 docs.json 頂層
description+seo.metatags(key-value)。seo.indexing: "all"允許索引。 - Open Graph / Twitter Card:
og:type/og:site_name/og:title/og:description/og:image(+width/height/alt)/og:locale+twitter:card: summary_large_image/twitter:image/theme-color。圖一律用絕對網址https://felimet-hub.jmcores.com/images/og-cover.png。 - 全站預設一張 og 圖:
seo.metatags.og:image對所有頁面生效(品牌一致)。要讓某頁有專屬卡,在該頁 frontmatter 設"og:image": "…"覆寫(key 帶冒號要加引號,見 §8.1 / Mintlify pages)。 - og 圖產生流程:
scripts/og-cover.html(1200x630,wabi-sabi,字型走 Google Fonts API)→ Playwright 開(file:// 被擋,先python -m http.server <port> --directory <repo>餵,navigatehttp://localhost:<port>/scripts/og-cover.html)→ viewport resize 1200x630 → 等字型 → 截圖 → 存images/og-cover.png。改品牌文案就改 HTML 重截。 - 驗收:
mint validate綠;上線後用各平台 OG debugger 或 opengraph.xyz 抽驗。
9. 常見任務 → 對應 skill
- 新增/更新文章(雙語、frontmatter、登記、重產畫廊)→
.claude/skills/add-content - 發布前完整檢查(validate + 畫廊同步 + 壞連結 + render 抽驗)→
.claude/skills/publish-check