This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
台灣學習者日文學習系統——假名記憶、單字管理、測驗工具維護。學習者母語台語、華語,略懂粵語,熟悉注音符號和漢字。平假名、片假名五十音(含濁音、半濁音)皆已完成,目前進入單字擴充與會話學習階段。
每個假名必須附漢字來源 + 記憶鉤(依以下優先順序選擇):
- 台語文言音——子音母音都對才用
- 台語白話音——補充或替代
- 華語——台語子音不對時(例:奴 nú → ぬ、祢 nǐ → ね)
- 粵語——漢音層接近(例:知 zi → ち chi)
- 注音字形——形近但音不近時(例:へ 像 ㄟ)
- 英文聯想——以上都不近時
- 純字形規則——濁點、合讀等
台語子音不對就不用台語,改用其他工具。漢字來源是最優先的字形聯想。
- 濁點(゛)——清音加兩點,子音變有聲(た→だ、か→が)
- 半濁點(゜)——は行專用,回到古代 p 音(は→ぱ);は行古代念 p,演變成 h(清)/b(濁)/p(半濁)
- 小字合讀(拗音)——ょゅゃ 縮小跟前面合讀,母音被取代
- 長音——a/i/u 用同母音延長;e 行用い;o 行用う
- ん 特殊性——打字要打 nn
- っ 促音——停頓一拍再爆發,台語入聲音感接近
- 助詞雙重發音——は念 wa、を念 o
- 母音無聲化——i 和 u 在特定位置消音(です→des)
- 清音弱化——單字中間的清音自然有聲化
| 檔案 | 用途 |
|---|---|
hiragana-quiz.html |
平假名互動測驗(五十音+單字,SRS) |
katakana-quiz.html |
片假名互動測驗(五十音+單字,SRS) |
hiragana.md |
平假名字表、發音規則、語法筆記 |
katakana.md |
片假名字表、單字分類 |
vocabulary.md |
所有單字,依主題分類(疑問詞、飲食、時間、顏色等) |
conversation.md |
會話筆記(基本用語、購物、點餐等情境) |
language-notes.md |
台語/粵語/注音記憶鉤對照表 |
already-known.md |
已知單字片語,在測驗中減少出現頻率 |
kanji.md |
漢字筆記(字表、發音規則、單字分類) |
grammar.md |
N5 語法筆記(句型、活用、例句)——文法內容的唯一正本,章節頁由它生成 |
grammar/ |
文法章節 HTML(NN.html+index.html,由 tools/build_grammar_pages.py 從 grammar.md 產生,不要手改;chapters.json 是「進度項編號→grammar.md 標題」登錄表、chapter.css 是手寫樣式) |
grammar-quiz.html |
文法 SRS 測驗(填空輸入+語感選擇;題庫 grammarCards 內嵌,SRS 走 quiz-common.js) |
tools/build_grammar_pages.py |
章節頁產生器(--check 供驗證器比對是否過期);會把配對的單字批次嵌進章節頁 |
grammar/pairings.json |
文法項 → 單字批次的配對表,一課=一個文法項+一批單字 |
vocab-lessons.md |
每日單字教學的唯一正本(一批一節),課程頁由它生成 |
vocab/ |
單字課程 HTML(NN.html+index.html,由 tools/build_vocab_pages.py 產生,不要手改;batches.json 是登錄表;樣式沿用 grammar/chapter.css) |
tools/build_vocab_pages.py |
單字課程頁產生器(渲染器 import build_grammar_pages,同一份實作) |
vocab-quiz.html |
課程單字 SRS 測驗(只收每日課程教過的字,依批次篩選;卡片內嵌 vocabCards,SRS 走 quiz-common.js) |
PRODUCT.md |
設計策略文件(受眾、品牌個性、設計原則,impeccable skill 使用) |
參考文件(.claude/skills/japanese-learning/references/ 目錄):
quiz-structure.md— 測驗 HTML 結構與更新方法language-correspondences.md— 台語/粵語音對應詳表vocab-categories.md— 單字分類與 topic 標籤說明
- Explore first, plan, then code — read relevant files and understand the current state before making changes.
- Smoke test before commit — for scripts, a dry-run counts; for notes/edits, verify the output looks correct before staging.
- Check git status before starting work — confirm the correct branch and no unexpected prior changes.
- Read an existing note before creating a new one — match frontmatter format and conventions rather than guessing.
- One concern per commit — keep commits focused; don't bundle unrelated changes.
每次只介紹 5–10 個,確認記熟後再進下一批。不要一次把整行或整個五十音全部教完。
漢字來源 → 記憶鉤(依優先順序)→ 清濁音一起介紹 → 形近字提示 → 更新筆記和測驗
拆解格式:
| 假名 | 發音 | 新/舊 |
|---|---|---|
| X | Y | ✅/🆕 |
有新字就單獨介紹,全部學過才說「全學過!」。
- 拆解每個假名(標明新/舊)
- 說明漢字來源和台語連結(如有)
- 同音異義詞提示
- 更新測驗 vocabCards,格式:
{ meaning, display, reading, kanji?, topic, round }meaning:純中文意思,不能夾雜日文假名(填'哪裡',不是'どこ(哪裡)')kanji:有常見漢字寫法就必須加(一杯、何処、服、耳等);純口語/擬聲語/純假名詞可省略(ゆっくり、じゃあね);片假名外來語不加
- 將單字加入
recentBatch(見下方說明);若這批字屬於某個課程批次,同時登錄進lessonBatch('單字': 批次號),否則單字測驗的批次篩選會漏掉它們 - 將單字加入對應筆記檔,並更新 frontmatter 的
date > updated:- 一般單字 →
vocabulary.md對應主題區塊 - 會話句型/口語表達 →
conversation.md對應情境區塊 - 片假名外來語 →
katakana.md對應單字區塊
- 一般單字 →
單字表格式:漢字 | 假名 | 羅馬拼音 | 意思
topic 標籤:greeting / food / family / time / color / number / nature / daily / question
hiragana-quiz.html 和 katakana-quiz.html 各有一個 recentBatch 物件,控制未被 SRS 記錄的單字出現優先度:
const recentBatch = {
'單字': 批次號, // 數字越大 = 越近加入 = 越優先
};- 批次規則:同一天加入的算同一批——當天若已有批次號就沿用,否則用目前最大批次號 + 1
- 目前最大批次號以該測驗 HTML 內 recentBatch 的實際最大值為準(新增前先查,不在此記死數字)
- 批次號轉換為
nextReview = -(批次號 × 5),確保新字在pickFromQueue排序中優先 - 已被 SRS 記錄過的字不受影響
使用者說某個單字「本來就會」時,需同時更新兩處:
already-known.md:加入表格(漢字 | 假名 | 羅馬拼音 | 意思)- 對應測驗的
alreadyKnownSet:加入假名(hiragana 用display、katakana 用word)
alreadyKnown 中的字初始 SRS 等級為 2(間隔 8 題),降低出現頻率。
每次修改任何 .md 筆記檔後,在 log.md 新增條目:
- 標題格式:
## YYYY-MM-DD HH:MM:SS(GMT+8,精確到秒) - 內容:更新了什麼(學了哪些假名/單字,或修正了什麼)
詳見 .claude/skills/japanese-learning/references/quiz-structure.md。更新時用 Python 處理中文字串避免編碼問題,覆寫前先確認。
每次更新 vocabCards/alreadyKnown/recentBatch 後,必須跑 python3 tools/validate_quiz_data.py——它會重算所有 round、查重複條目、比對 already-known.md 與 alreadyKnown Set,全部通過才能 commit。
單字輪次(round)計算規則(嚴格字符規則):
word_round = max(所有字符的輪次)- 平假名輪次:R1(あ・ら行・ん)、R2(か・が・な行)、R3(さ・ざ・や・わ行)、R4(た・だ・ま行)、R5(は・ば・ぱ行)
- 小假名 ゃゅょ 及 っ 依所屬行計算(ゃゅょ → R3,っ → R5)
- 片假名輪次規則相同
index.html 採現代日式風格,設計原則詳見 PRODUCT.md。UI 設計任務使用 /impeccable skill。
- 配色:OKLCH,禁用純
#000/#fff;底色微暖白、墨色深靛、強調磚紅 - 字型:Klee One(標題,與 index.html 一致)+ Noto Sans TC(內文)
- 無障礙:最小字體 18px,WCAG AA,互動目標 ≥ 44×44px,尊重 prefers-reduced-motion
- 禁止:gradient text、glassmorphism、等高卡片格、side-stripe border
-
一課=文法+單字(2026-09-08 起):
grammar/pairings.json把每個文法項配一個單字批次,build_grammar_pages.py會把該批單字用render_section(demote=1)嵌成章節頁底部的 「這一課的單字」一節,CTA 多一顆vocab-quiz.html?batch=N。動機是量出來的——未教的 22 批 共 135 字裡,有 45 字已經出現在已上架的文法章節(動詞批次 11–16 的 48 字中就佔 34 字), 文法為了示範活用會提前把動詞拉進來,單字軌兩個月後再教一次,等於重背。vocab/NN.html仍照常產生,當依主題查詢的存檔(同grammar.md/grammar/的關係)。一課配到兩批以上時,每批的逐字講解會收進<details>,只留完整表展開(切點是該批第一個含「完整」的###小標;沒有###就退而找####——用「第一個」而非「最後一個」,否則批次6 巢狀在完整表底下的#### 半 はん 的完整用法會把那一節從中間切開)。summary 標出藏了幾節,否則收起時直接看到「四、完整表」會摸不著頭緒。單批的課不收合。配對值可以是陣列——一個文法項配多批單字(第 5 項 あります/います 同時帶場所設施 A 與 B,因為那才是「東西在哪個地方」的文法;原本 B 掛在第 6 項 ます形上,與動詞活用無關又讓那頁變成 20KB,2026-09-08 移走)。 兩軌同一天跑、文法先跑,那時該批還沒上架,所以vocab_section_html()找不到就回 None 出純文法頁;build_vocab_pages.py收尾時會重建文法頁補上——少了這一步,驗證器會在單字軌 收尾時判文法頁過期,讓整輪還原。批次編號因重排而跳號是正常的。 -
grammar.md 是文法內容的唯一正本;
grammar/NN.html與grammar/index.html是tools/build_grammar_pages.py的建置產物,絕對不要手改(改了下次重建就沒了,驗證器也會報「過期」)。_sidebar.md與notes/(docsify)照舊渲染 grammar.md 當完整筆記檢視,兩者並存是刻意的,不要「修掉」。 -
grammar.md 只能用這個 markdown 子集:
###/####小標、段落、行尾兩空格換行、**粗體**、`行內程式碼`、GFM 表格、>引言、``` 圍欄、單層-/`1.` 清單、`---`。產生器認不得的語法會直接建置失敗。 -
改了 grammar.md(已上架章節的部分)→ 必跑
python3 tools/build_grammar_pages.py重建,再跑python3 tools/validate_quiz_data.py;precommit hook 會擋住過期頁面的 commit。 -
單字同一套:
vocab-lessons.md是單字教學正本、vocab/NN.html是產物(勿手改)、vocab/batches.json是登錄表,產生器tools/build_vocab_pages.py直接 importbuild_grammar_pages的渲染器——markdown 子集與版型兩邊完全相同,改一支兩邊同時生效。vocabulary.md(主題總表)與vocab-lessons.md(課程順序)刻意並存,同grammar.md/grammar/的關係。課程單字的練習在獨立的vocab-quiz.html(2026-09-06 拆出):它只收每日課程教過的字,篩選軸是課程批次;卡片上的batch欄位一物二用——既是篩選軸,也是新字的出現優先度(未做過的字nextReview = -(batch×5)),所以不需要lessonBatch/recentBatch那兩張對照表。lessonTitles只供按鈕 tooltip,驗證器會比對vocab/batches.json。hiragana-quiz.html則回到原本的樣子:五十音與舊單字都依假名輪次 R1–R5 篩選,recentBatch凍結在批次 21 不再成長。兩頁的單字池互斥(驗證器有這條不變量)——同一個字若兩邊都在,會被各自排程、等於每天複習兩次。互斥是比對「假名+漢字」成對,不是只比假名:同音異字是不同的字(批次28 的 橋/虫/鳥/一回 對上舊頁的 箸/蒸し/鶏/一階),只比假名會把它們誤判成重複,讓當天的 pipeline 整天失敗。batch: 0是預習——還沒教到但已經在字池裡的字(目前三張:もらう→批次12、こわれる→批次14、ちかい→批次18),篩選列顯示為「預習」按鈕,教到那批時把 batch 從 0 改成該批編號即可。篩選「全部」的哨兵值因此是 -1 而不是 0。另外getVocabDistractors()的干擾項按語意分層取(同批 → 同主題 → 其餘),避免選項一眼就能刪掉。 -
grammar-quiz.html的題庫grammarCards一行一題:id(cNN-qM,NN=進度項編號)是 SRS key——修錯字保留 id、改題意換新 id 並刪舊行;batch同天同批、越大越新(未做過的題nextReview = -(batch×5)優先出現);cloze 題目必含___且accepted含answer;mcchoices≥3 且含answer;每題必有explain。作答後頁面會自動把答案句轉羅馬字顯示(wapuro 慣例、句中 は→wa 啟發式);句子含漢字或非助詞的 は 開頭單字(はなし系以外)時,加選填的romaji欄位手動指定,覆寫自動轉換。頁內chapters陣列必須與grammar/chapters.json一致(驗證器會比對)。
每天 17:30,vault 的 com.didiowen.nihongo-grammar-daily 排程(~/LFCxBVB/X/scripts/nihongo-grammar-notify.sh)為文法與單字各起一個獨立的 headless session:
- 文法軌(2026-09-05 起改版):依
grammar-daily-progress.md的規則推進一章——(新增類先寫進 grammar.md)→ 登錄grammar/chapters.json與grammar-quiz.html的chapters、追加 3–5 題進grammarCards→ 跑產生器+驗證器 → Telegram 只發短通知+連結(章節頁+測驗頁),教學內容在網頁、複習交給測驗頁的 SRS。grammar-daily-latest.md只是 10 行紀錄(日期/編號/連結/新題 id)。 - 單字軌(2026-09-06 起同樣改版):教學內容寫進
vocab-lessons.md正本 → 登錄vocab/batches.json→ 跑build_vocab_pages.py產出課程頁 → 完成收錄(vocabulary.md/kanji.md/vocab-quiz.html的vocabCards(每張卡帶batch)+lessonTitles)並跑validate_quiz_data.py。新字一律加進vocab-quiz.html,不要再加進hiragana-quiz.html。 - Telegram 合併成一則:兩軌各自把內容做完、各自 commit,最後由腳本組出單一通知(今日文法第 N 章+單字批次 M、各自連結、測驗提醒)。單軌失敗時另一軌照常出現在訊息裡。
批改規則(2026-09-06 起):Telegram 不再批改任何題目——文法題在 grammar-quiz.html、單字題在 hiragana-quiz.html,答對答錯都由測驗頁自己記 SRS。兩張進度表的備註欄改記概念性觀察(哪類文法點/哪類字反覆卡住),不再逐題記分。狀態 ✅ 與完成日期排程已填好,不要重複標。
每完成一次更動就 commit + push,不要累積在工作區。 未 commit 的改動是最脆弱的狀態——並行的 session、排程、或下一輪操作都可能把它掃掉。
- push 一律推
claude-playground,不要推main。main有分支保護(Changes must be made through a pull request),直推只是靠管理者權限 bypass 掉自己設的規則;本機的 branch guard 也會擋下在main上的 commit。工作樹平常就停在claude-playground - 一次更動=一個 concern:新增一批假名/單字、修一個筆記錯誤、更新一次測驗資料,各自成一個 commit,不要把不相關的改動綁在一起
- 照原有流程做完再提交:檔案修改(
vocabulary.md/kanji.md/hiragana-quiz.html/katakana-quiz.html/log.md)、validate_quiz_data.py驗證、frontmatter 的updated更新,全部通過才 commit - commit + push 不必先問使用者,那是預設動作;要問的是下面的 PR
不要每次 push 都開 PR。 讓 commit 在分支上累積,等到一段工作告一段落、或使用者開口時,再一次開 PR 並合併。GitHub Actions 額度是共用且有限的,一個小改動開一個 PR 純粹浪費。
- PR 一律
claude-playground→main - 每日 23:30 會自動開 PR 並合併(vault 排程
com.didiowen.nihongo-daily-merge→~/LFCxBVB/X/scripts/nihongo-daily-merge.sh):claude-playground有領先main的 commit 就開 PR、合併、把分支快轉回 main;沒有就靜默結束。所以平常不需要手動開 PR,push 完就交給它 - GitHub Pages 從
main根目錄發佈,所以測驗網站(hiragana-quiz.html等)的更新要等合併後才上線——正常情況就是當晚 23:30。使用者若急著看到某個改動,才需要立刻手動開 PR - 手動 merge 之後記得把
claude-playground快轉回main(git fetch origin && git push origin origin/main:claude-playground),否則它會越拖越舊,下次 PR 開始出現無謂的衝突;23:30 那支排程自己會做這一步 - 使用者明確說「開 PR」「merge」「cpprm」時直接照做,不需再問
- 一段工作結束時可以主動問一句「要開 PR 嗎」,但不要停在那裡等——commit + push 該做的照做
- 同一批的多個 commit 合併在同一個 PR;建立後把 PR 網址回報給使用者
- smoke test 通過即視為可合併;PR 建立後不需要主動檢查 CI 狀態或 review 意見,等使用者通知再處理
PR 描述格式:
## 使用者指令
(根據上下文完整理解語意而不是單純逐字)
## 修改摘要
(每個 commit 對應做了什麼改動)
- 繁體中文回答
- 解釋新假名:漢字來源 + 記憶鉤 + 清濁音一起介紹
- 形近字主動提示
- 語法說明穿插在真實單字裡,不抽象解釋
- 台語連結是核心優勢,積極找對應
- 日語音読み和台語文言音同樣保留中古漢語,高度對應
- 台語日語借詞超過 1000 個(歐巴桑、便當、名刺、運將等)
- 平假名是漢字草書演變,片假名是漢字楷書演變
- 台語有文言音和白話音兩套,文言音更接近日語音読み