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

2026年10月19日

Periodic 3D 互動式元素週期表

為什麼做這個專案

網路上的元素週期表很多,但大多是英文介面,或者中文資料來源不明、讀音和用字也不一致。想做一個繁體中文優先的互動式週期表:每個元素都有正確的中文名稱、注音、可查證的資料,還能用 2D 和 3D 兩種方式探索。


主要功能

2D 週期表

  • 搜尋:可以用原子序、符號、英文名稱或中文名稱查詢,結果依「原子序完全相符 → 符號完全相符 → 名稱完全相符 → 名稱開頭相符 → 包含」排序
  • 分類標示:點選分類圖例,其他分類的元素會淡出
  • 元素資訊面板:原子量、電子排布、注音與同音字,以及電子殼層的 3D 原子模型;寬螢幕上可以拖曳面板
  • 鍵盤操作:方向鍵在元素之間移動,會自動跳過週期表中的空格;Enter 選取、Esc 取消
  • 手機版:元素資訊改成從下方滑出的卡片,左右滑動就能切換上一個、下一個元素

3D 週期表

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)
3Dthree.js + React Three Fiber
樣式Tailwind CSS 4,支援深色模式
測試Vitest + Testing Library(17 個測試檔,涵蓋資料完整性、版面、搜尋、元件互動與內容查證)
部署Vercel

npm run check 會依序跑資料檢查、型別檢查、lint、測試和建置,全部通過才算完成。


小結

做這個專案最大的體會是:教育類內容,正確性就是使用者體驗的一部分。畫面再漂亮,資料錯一個字就失去信任。所以這次把「可查證」做成了自動化的檢查:資料對不上來源、故事引用了沒讀過的文獻,測試就不會通過。

🌐 線上體驗 | 💻 GitHub

覺得有幫助可以按個喜歡