Periodic 3D:一個每筆資料都要對得上來源的互動式元素週期表
2026年10月19日

為什麼做這個專案
網路上的元素週期表很多,但大多是英文介面,或者中文資料來源不明、讀音和用字也不一致。想做一個繁體中文優先的互動式週期表:每個元素都有正確的中文名稱、注音、可查證的資料,還能用 2D 和 3D 兩種方式探索。
主要功能
2D 週期表
- 搜尋:可以用原子序、符號、英文名稱或中文名稱查詢,結果依「原子序完全相符 → 符號完全相符 → 名稱完全相符 → 名稱開頭相符 → 包含」排序
- 分類標示:點選分類圖例,其他分類的元素會淡出
- 元素資訊面板:原子量、電子排布、注音與同音字,以及電子殼層的 3D 原子模型;寬螢幕上可以拖曳面板
- 鍵盤操作:方向鍵在元素之間移動,會自動跳過週期表中的空格;Enter 選取、Esc 取消
- 手機版:元素資訊改成從下方滑出的卡片,左右滑動就能切換上一個、下一個元素
3D 週期表

同樣 118 個元素,可以切換成週期表、球體、螺旋、格狀四種 3D 排列,並自由旋轉、縮放。系統若偵測到使用者偏好減少動態效果,會降低動畫。
元素故事

- 10 篇分類導讀:鹼金屬、過渡金屬、鑭系……每篇說明定義、規則與例外
- 118 篇元素故事:每個元素一篇短文,最後附一個延伸思考題
- 依「先導讀、再依原子序」排列,可以從頭讀到尾
資料:每一筆都要對得上來源
這個專案最花心思的地方是資料。元素資料由多個權威來源合併而成:
| 欄位 | 來源 |
|---|---|
| 符號、英文名稱、分類、電子排布 | PubChem |
| 標準原子量 | CIAAW 2024 |
| 放射性元素的質量數 | CIAAW(NUBASE2020) |
| 電子排布交叉核對 | NIST Atomic Spectra Database |
| 中文名稱、注音 | 國家教育研究院公布用字,並與教育部《重編國語辭典》交叉核對 |
建置腳本把這些來源合併成一份 elements.json,而且遇到不一致就直接報錯,不會默默修正。例如電子排布會逐一和 NIST 比對:
function checkAgainstNist(z, config) {
const tail = nist[String(z)];
if (!tail) return;
const ours = new Map(expandConfig(config).map((s) => [`${s.n}${s.l}`, s.count]));
for (const token of tail.split(".").filter((t) => !t.startsWith("("))) {
const m = token.match(/^(\d)([spdf])(\d*)$/);
// ...
if (ours.get(key) !== count) throw new Error(`Z=${z}: ... disagrees with NIST ...`);
}
}其他檢查還包括:電子數總和必須等於原子序、殼層數必須等於週期、一共必須剛好 118 個元素。npm run data:check 會在記憶體中重新建置一次,如果版本庫裡的資料檔過期,就讓檢查失敗。
科學上仍有爭議的地方,資料會明確標示,而不是假裝確定:
- 第 3 族採 IUPAC 2021 臨時建議(Sc、Y、Lu、Lr)
- 鐒(Lr)的電子排布採 NIST 的 7p¹,而不是 PubChem 的 6d¹
- 109~118 號元素的分類與電子排布是理論預測值,會另外標示
內容:沒讀過的來源不能引用
118 篇元素故事與 10 篇導讀,同樣有一套查證規則:
- 每篇故事引用的 PubChem 頁面都必須登記為「已閱讀」,否則測試會失敗
- 內容狀態分為:待處理 → 部分查證 → 已對照來源 → 專家審閱;「專家審閱」不能自行標記
- 不杜撰歷史或引言;有毒、放射性元素以安全為前提撰寫;來源說法不一時,兩者並陳或乾脆不寫
開發過程中,碳和金的故事原本引用了一本沒有讀過全文的教科書和一篇論文,後來全部改寫成只使用實際讀過的來源。分類導讀也是一樣,找不到可讀來源的解釋就刪除,或改寫成問題。
效能:3D 只在需要時才載入
three.js 體積不小,所以 3D 元件用動態載入,只有打開 3D 視圖時才下載。載入前先確認瀏覽器支援 WebGL 2:
export function supportsWebGL2(): boolean {
if (typeof window === "undefined" || !window.WebGL2RenderingContext) return false;
try {
const context = document.createElement("canvas").getContext("webgl2");
if (!context) return false;
context.getExtension("WEBGL_lose_context")?.loseContext();
return true;
} catch { return false; }
}檢查完立刻釋放這個測試用的 WebGL context,避免佔用瀏覽器有限的 context 數量。
技術架構
| 項目 | 使用技術 |
|---|---|
| 框架 | Next.js 16 + React 19 + TypeScript(strict) |
| 3D | three.js + React Three Fiber |
| 樣式 | Tailwind CSS 4,支援深色模式 |
| 測試 | Vitest + Testing Library(17 個測試檔,涵蓋資料完整性、版面、搜尋、元件互動與內容查證) |
| 部署 | Vercel |
npm run check 會依序跑資料檢查、型別檢查、lint、測試和建置,全部通過才算完成。
小結
做這個專案最大的體會是:教育類內容,正確性就是使用者體驗的一部分。畫面再漂亮,資料錯一個字就失去信任。所以這次把「可查證」做成了自動化的檢查:資料對不上來源、故事引用了沒讀過的文獻,測試就不會通過。