Felimet Hub — 網站維護憲章(給 AI 維護者)
這個 repo 是 Felimet Hub 個人網站(線上 www.jmcores.com)的原始碼,平台是 Mintlify(docs.json 驅動的文件站),雙語(繁體中文 zh-Hant 為主、English 為輔)。設計基調 wabi-sabi 暖色。 維護者預設用自然語言下指令(例:「幫我加一篇關於 vLLM 部署的筆記」「把 Schlieren 那篇標成精選」「準備發布」)。本檔 +.claude/skills/ 是把那些自然語言對應到正確、可重現操作的單一事實來源。動手前先讀本檔對應段落,不要憑印象改。
1. 環境與指令(本地驗證不需帳號)
需求:Node >= 20.17(實測 v24 OK)。
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,否則別碰。 - 西文散文字形 Noto Serif(2026-06-12 使用者指定):docs.json fonts 只有兩槽,第三 family 由根目錄
fonts-noto-serif.js注入 Google Fonts 載入,style.css散文堆疊把"Noto Serif"插在"Noto Sans TC"前(拉丁碼位走 serif,CJK 自然回退)。標題仍 Crimson Pro、code 仍等寬,皆不受影響。 - 圖示(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+thumbnails):逐頁 OG(Mintlify 自動產,品牌底圖images/og-background.png+thumbnails.theme),首頁用完整設計卡images/og-cover.png。細節見 §8.4 與.claude/rules/og-cards.md。 - 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。 - 散文排版:段落級散文(含 Mintlify 的
span[data-as="p"]、p、li、blockquote、dd)兩端對齊(justify + 英文 hyphens 斷字),標題/表格欄/圖說/code 維持 start(實作在style.css「散文兩端對齊」段,2026-06-11 定案)。渲染層引號規則(直引號 JS、QuoteLatin 備援)見 §8 踩雷 11 與 §8.1;細節住.claude/rules/house-style.md。
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。 - 線上英文出現彎引號 ≠ 源碼髒:Mintlify 的 MDX 渲染器在 build 期對英文散文套 smartypants,把源碼直引號轉成彎引號(U+2018/9、U+201C/D),無 docs.json 開關。別回頭改 .mdx 源碼,源碼本來就直、grep 也會證明 0 命中。修法已就位:
quotes-straight.js(根目錄,自動載入)前端換回直引號,勿刪;style.css的QuoteLatin@font-face 為 no-JS 備援。注意 Mintlify 把根目錄 .js inline 注入多份(實測同頁 3 份),自訂 script 開頭要window.__xxxLoaded旗標去重;且 .js 內禁寫字面彎引號(用\u跳脫 /String.fromCharCode),否則 §8.1 驗收 grep 自觸發。細節見.claude/rules/house-style.md渲染段。
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 直引號
'(U+0027)與"(U+0022);英文 contraction/所有格撇號同理(heater's、model's,不是彎撇號)。不用彎引號(U+2018/U+2019/U+201C/U+201D)或全形(U+FF07/U+FF02)。中文內文照舊用全形標點與全形引號「」『』(U+300C/D、U+300E/F),「修引號」時不要把中文全形引號誤改成 ASCII(不同字元、不在驗收 regex 命中範圍)。 - 驗收(全 repo,非僅
en/):rg -nP '[\x{2018}\x{2019}\x{201C}\x{201D}]' .應 0 命中。列舉禁用彎引號給人看時一律用U+xxxx記法、不貼字面彎引號,否則 grep 永遠有殘留、規範自打臉(本檔即如此書寫)。完整標點與引號規範見.claude/rules/house-style.md。 - 渲染面(與源碼分開判斷):線上彎引號是 build 期 smartypants 轉的,不是源碼髒(見 §8 踩雷 11)。渲染結果要求直引號(2026-06-11 定案):
quotes-straight.js前端逐字換回 ASCII,code/pre/kbd/samp 跳過、中文「」『』不在範圍;QuoteLatin@font-face(style.css)為 no-JS 備援。驗收:本地mint dev起來後以瀏覽器檢查英文散文document.body.innerText無 U+2018/9、U+201C/D,中文頁「」對數不變。
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。LamenessGrades(lameness-grades.jsx):乳牛跛行專用,四等級晶片(Normal/Slight/Severe/Stationary,依嚴重度著色)+ GEI/HEI 融合權重滑桿(純示意,不做預測)。CertDecision(cert-decision.jsx):Synology 專用,選流量路徑(橘雲 proxy / 直連)→ 即時給建議憑證與原因。CiteSwitch(cite-switch.jsx):可重用論文引用切換器,解析 BibTeX 推導 IEEE / APA 三式互換 + 一鍵複製。publications 頁用。TerminalDemo(terminal-demo.jsx):可重用模擬終端機,逐行打字動畫 + mock 輸出 + play/step/reset 控制,行首✓自動綠、✗自動紅。commands=[{cmd, output}](output 為字串或行陣列)餵任意指令序列;無 props 時內建 CUDA 驗證流程(nvidia-smi → nvcc -V → gpu_test.py)。cuda-setup §4 已用,呈現「成功時每步該出現的輸出」。
8.4 SEO 與 Open Graph(社群分享卡,docs.json seo)
- 全站 meta 在 docs.json 頂層
description+seo.metatags(key-value)。seo.indexing: "all"允許索引。 - 逐頁 OG(現行做法):Mintlify 預設會用 site logo + 該頁
title/description+ primary color 自動為每頁產 OG 圖。前提是seo.metatags不設og:image/og:title/og:description(設了會壓掉逐頁,全站變同一張)。現況seo.metatags只留og:type/og:site_name/og:locale/twitter:card/theme-color。 - 品牌底圖 + 主題:
thumbnails.background: "/images/og-background.png"(無文字暗底圖,留白給疊字)+thumbnails.theme: "dark"(OG 卡明暗,全站單一選擇,非依瀏覽者切換 — OG 是爬蟲抓的靜態圖,無法 per-viewer;亮版需同步改兩個產生器與底圖回 cream)。 - 首頁專屬卡:
index.mdx/en/index.mdxfrontmatter 設"og:image"指向images/og-cover.png(完整設計卡)。其他頁需專屬卡同法在該頁 frontmatter 覆寫(key 帶冒號要引號)。 - og 圖產生器:
scripts/og-cover.html(首頁完整卡)+scripts/og-background.html(逐頁無文字底圖)+scripts/og-logo.svg(共用 JM 標記)。流程:file://擋 svg → 先python -m http.server <port>→ Playwright navigatehttp://localhost:<port>/scripts/<檔>.html→ resize 1200x630 → 等字型/圖 → 截圖 → 存對應 PNG。 - 驗收:
mint validate綠驗 schema;逐頁自動卡只在 Mintlify 託管 build 時產生,本地 dev/validate 看不到,上線後用 opengraph.xyz / 各平台 OG debugger 抽驗疊字是否與底圖打架。完整機制與規範見.claude/rules/og-cards.md。
9. 常見任務 → 對應 skill 與 .claude/ 分工
- 新增/更新文章(雙語、frontmatter、登記、重產畫廊)→
.claude/skills/add-content - 發布前完整檢查(validate + 畫廊同步 + 壞連結 + render 抽驗)→
.claude/skills/publish-check
.claude/ 目錄分工(沿官方慣例,2026-06-11 對齊)
依 Claude Code 官方 .claude 目錄結構(code.claude.com/docs/zh-TW/claude-directory)配置;各層職責固定,新增設定先查表再落點,不自創目錄名:
分層原則:AGENT.md 留鐵則與指標,機制細節住
rules/,流程住 skills/;互引不重複(單一事實來源)。歷史備註:rules/ 前身為自創的 roles/,那個位置 Claude Code 不會自動載入,2026-06-11 遷移正名。