
Teaching Site
- 47 installs
- 47 repo stars
- Updated May 15, 2026
- kevintsai1202/teaching-site-skills
Helps with ai & agent building tasks.
About
teaching-site is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- teaching-site
- AI & Agent Building
- AI-coding skill
Teaching Site by the numbers
- 47 all-time installs (skills.sh)
- +4 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #7,551 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/kevintsai1202/teaching-site-skills --skill teaching-siteAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 47 |
|---|---|
| repo stars | ★ 47 |
| Last updated | May 15, 2026 |
| Repository | kevintsai1202/teaching-site-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
Teaching Site — Main Entry Point
Schema authority: all primitive field names (unit / concept / prompt / task / material / quiz / faq / illustration) and the canonical project layout come from `_shared/domain-primitives.md`. When dispatching to any sub-skill, expect the agent to consult that file first.
>
Filename convention (English-first): all generated files use English names (course-package/,day{n}/outline.md,materials/, etc.). Trigger phrases users say in chat may stay Chinese, but anything written to disk is English. See_shared/domain-primitives.md§0 for the full mapping.
>
Reference implementation: d:/GitHub/ai-workshop/ is the production reference (4-day workshop, 4125-line index.html, 1728-line course-data.js). Use it as visual + render-pattern reference; do not copy course-specific content from it.This is the top-level skill for producing an interactive teaching website. It coordinates 10 specialised sub-skills covering every stage from blank-slate outline to delivered PDF ebook.
When This Skill vs. a Sub-Skill
- Use this skill (
teaching-site) when: - The user's request is broad ("做一套課程網站", "我想做工作坊").
- You're starting from scratch and don't know where to begin.
- The user is jumping between stages and needs orchestration.
- You need to check cross-artifact consistency after a change.
- Use a sub-skill directly when:
- The user names the artifact ("做電子書" →
course-ebook-publishing). - You're already deep into one stage and don't need pipeline overview.
- Another skill is dispatching here for a focused subtask.
Both paths converge — sub-skills can be reached either by direct trigger or via this skill's dispatch.
The Production Pipeline
A teaching site is built in five core layers, with two optional derivative layers at the end:
[Stage 1] outline (.md)
↓ produces: meta, day list, unit skeleton, learning goals, shared scenario
[Stage 2] content authoring (.md / .csv / .yaml)
↓ produces: lecture notes, sample materials, quiz items, optional prompt templates
[Stage 3] SPA conversion (.js + .html)
↓ produces: course-data.js (data) + index.html (renderers), local serve setup
[Stage 4] interactions (.js + .css inside index.html)
↓ produces: progress persistence, sidebar/scrollspy, theme, RWD, quiz UX
[Stage 5] visual assets (.png / .svg / scraping scripts)
↓ produces: illustrations, screenshots, QR codes, maps
▼
─── site is now feature-complete ─── (optional derivatives below)
▼
[Stage 5b] Corporate Edition branch ← optional, parallel to ebook
↓ produces: corporate-editions/ folder, condensed units, inlined COURSE, asset fallback chain
[Stage 6] Ebook Publishing ← optional, ALWAYS after site is stable
↓ produces: dist/{name}.pdf + .docx via single composed master.mdStages 1–5 are usually traversed in order, but users often jump back (add a unit → must update outline AND course-data.js AND any related visual). Catching these back-references is this skill's main value-add.
Stages 5b and 6 are downstream consumers of the finished site. They read but never modify the canonical site. Do not invoke them while Stages 1–5 are still in flux — the rework cost is high.
Sub-Skill Dispatch Table
Invoke the matching sub-skill via your agent's skill activation mechanism (Claude Code: Skill tool, Codex: skill tool, Antigravity / Gemini CLI: activate_skill) when the matching stage is active:
| Stage | Sub-skill | Trigger phrases |
|---|---|---|
| 1 | course-outline-design | "規劃課程", "課程大綱", "幾天怎麼排", "學習目標" |
| 2 | course-content-authoring | "寫講義", "補素材", "出測驗題", "提示詞範本" |
| 3 | static-spa-conversion | "做成網頁", "轉成 SPA", "course-data.js", "render 函式" |
| 4 | static-spa-interactions | "加進度勾選", "響應式", "暗色模式", "縮放", "scrollspy" |
| 5 | web-visual-assets | "插圖", "工具截圖", "QR", "講師卡", "地圖" |
| 5b | course-corporate-edition | "企業包班", "濃縮版", "客製化", "壓縮成一天" |
| 6 | course-ebook-publishing | "做電子書", "產 PDF", "印給學員", "DOCX 交付" |
| ╳ | web-visual-verification | "驗證網頁", "RWD 驗證", "Playwright 測試", "截圖比對" |
| ╳ | web-content-audit | "盤點內容", "稽核資產", "找缺圖", "三處同步檢查" |
| ╳ | teaching-site-design-system | "視覺風格", "設計系統", "色票", "字體", "玻璃卡片" |
The last three (marked ╳) are cross-cutting — not tied to a stage. The first two (verification / audit) are the safety net for runtime behaviour and cross-file references. The third (design-system) is the visual authority every stage reads from.
Stage 1 Gate (Hard Rule — read before any dispatch)
Before dispatching to ANY stage (including 2–6, 5b, and the cross-cutting skills), confirm Stage 1 deliverables exist on disk:
- [ ] An overview file (e.g.
overview.md) with populated對象/總時數/每日主題fields — not just a heading. - [ ] At least one per-day outline file (e.g.
day1/outline.md) listing unit IDs and learning goals.
Shared scenario (shared-scenario.md) is optional — it's a downstream decision handled bycourse-outline-design's Completion Gate, not an entry requirement here.
If either of the two is missing or only a stub: do NOT dispatch downstream, even if the user explicitly named a later stage ("做電子書", "幫我寫 quiz"). Dispatch to course-outline-design first and tell the user:
「我看到還沒有完整的課程綱要 — 直接跳到 Stage N 會讓後面每改一次 outline 就連動多個檔案重做。先用 course-outline-design 把 outline 鎖定,大概 10 分鐘決策,省下後續數小時 rework。」Stage 1 Override Policy (3-bullet escape hatch)
If the user explicitly insists on skipping the gate ("我知道,先做就好", "skip the outline, just do X"), proceed under these conditions:
1. Ask them to paste 3 bullets in chat before any downstream action:
- 對象:一句話描述學員是誰 + 先備知識
- 總時數 + 每日時段:例如「2 天 × 6 小時」
- 每日主題:Day 1 / Day 2 / ... 各一行
2. Save those 3 bullets verbatim into a stub overview.md (mark it <!-- stub created via Stage 1 Gate override on YYYY-MM-DD -->) before dispatching to the requested stage. 3. If the user refuses even the 3-bullet stub, fall back to the strict path — refuse the override and dispatch to course-outline-design.
The stub is the audit trail: future sessions reading this site can immediately see Stage 1 was bypassed and recover context.
Stage 2 Gate (Hard Rule — read before dispatching to Stage 3+)
After Stage 1 Gate passes, before dispatching to Stage 3 (static-spa-conversion), Stage 5b, or Stage 6, confirm Stage 2 deliverables exist on disk:
- [ ] Each
day{n}/content.mdexists (one per Day listed inoverview.md). - [ ] Each
content.mdcontains a## u-{id}section for every unit ID declared in the matchingday{n}/outline.md— not just one. - [ ] Each unit section has substance: at least one of (a) lecture script ≥ ~10 lines, (b)
任務 (tasks)list, (c)素材需求references. Heading-only units fail. - [ ] Each unit section declares
**圖片需求 (illustrations)**listing 1–3 entries with filename + brief spec — see Stage 5 Image Coverage Floor below.
If any item fails: do NOT dispatch to Stage 3+, even if the user explicitly named a later stage. Dispatch to course-content-authoring first and tell the user:
「outline 在,但 Day {n} 的content.md{缺/空殼/單元 u-{id} 沒寫}。直接做網頁會生出薄薄的殼 — 學員看到的只是標題清單,沒有實質教學內容。先用course-content-authoring把每個單元的 lecture / tasks / 圖片需求補完,比之後重做整套網頁省好幾倍時間。」
Stage 2 Override Policy (thin-demo escape hatch)
If the user explicitly insists on a thin demo ("先做殼就好", "我只要 demo 給客戶看版型", "skip content"), proceed under these conditions:
1. State explicitly in chat what they're trading away: thin demo will have unit titles only, no lecture body, placeholder <div> instead of illustrations, tasks as empty checkboxes. 2. Mark every affected day{n}/content.md (create as stub if missing) with header comment <!-- thin-demo stub: Stage 2 bypassed on YYYY-MM-DD — re-enter course-content-authoring before any real student sees this -->. 3. When generating course-data.js, set __thinDemo: true on each affected unit so the SPA renders a "本單元尚未填內容" badge — students who somehow land on a demo build can see it's not real.
Without all three, do not proceed. Refuse and dispatch to course-content-authoring.
Stage 5 Image Coverage Floor (Hard Rule — applies before declaring "site feature-complete")
A site that ships with only a cover image and bare text feels skeletal — learners disengage in the first scroll. Before declaring Stages 1–5 done (and therefore eligible for Stage 5b / 6 dispatch), confirm:
- [ ] Every unit in
course-data.jshas anillustrations[]array with 1–3 entries. (The legacy singleillustration: 'foo.png'field counts as 1; treat it asillustrations: [{ name: 'foo.png', kind: 'hero' }]for this check.) - [ ] At least one entry per unit resolves to an existing file under
assets/(the others may still be SVG fallback stubs while Stage 5 is mid-flight). - [ ] If a unit genuinely needs no illustration (rare — e.g. a 5-min administrative slot, a quiz-only unit), record an explicit waiver:
illustrations: [{ kind: 'waived', reason: '...' }]. Silence does not pass. - [ ]
assets/illustrations/(or your project's equivalent) contains the cover plus the per-unit images — not just the cover.
If unmet: dispatch to web-visual-assets and tell the user:
「目前有 N 個單元沒插圖(或全站只有封面)。學員一打開會覺得內容很空、像草稿。建議先用 web-visual-assets 跑一輪批次生圖(每單元 1–3 張,搭配 PNG-first / SVG-fallback),再進入電子書/企業包班分支 — 否則 PDF 一印出來就是大片留白。」This floor is checked after Stage 4 finishes (interactivity wired) and before dispatching to Stage 5b or 6. Stage 5b / 6 inherit whatever images exist; if you skip the floor, the corporate brochure and the PDF ebook will both ship empty.
How to Detect the Current Stage
After Stage 1 Gate AND Stage 2 Gate pass, look for these signals to pick the right downstream stage:
- Outline `.md` exists, but `day{n}/content.md` is missing or thin → Stage 2 (
course-content-authoring). Skipping to Stage 3 is gated — see Stage 2 Gate above. - Content `.md` complete, but no `course-data.js` → Stage 3 (
static-spa-conversion). - `course-data.js` exists, but `index.html` has no renderers / no local serve → Stage 3.
- SPA renders, but progress isn't persisted / no responsive / no theme → Stage 4.
- Site works but has placeholder `<div>` for images / 404 thumbnails / units missing illustrations → Stage 5 (
web-visual-assets). - Site appears feature-complete but Stage 5 Image Coverage Floor not met → Stage 5 first; do NOT dispatch 5b/6 yet.
- Site is feature-complete (all gates + floor pass), user mentions corporate / in-house / shorter version → Stage 5b.
- Site is feature-complete (all gates + floor pass), user wants a printed / archived / shareable file → Stage 6.
Ambiguous? Ask one short question, then dispatch. Don't try to do all stages at once — the cross-stage rework cost is high.
Operating Principles
1. Never skip stages forward. Don't generate Stage 3 SPA from a half-baked Stage 1 outline — the structural mismatches multiply. If the user wants to skip, say so explicitly.
2. Always trace back-references. When the user modifies a downstream artifact (e.g. "add unit u-6 to day 2"), update upstream (outline.md) AND downstream (course-data.js, related visuals) in the same change. Half-updated sites accumulate technical debt very fast.
3. Course-specific knowledge belongs to the user's content, not to a skill. The sub-skills are intentionally agnostic to the topic of the course (AI workshop / cooking class / accounting training — same pipeline). If a sub-skill seems to be hardcoding domain examples, that's a smell.
4. Verification commands are part of the deliverable. When dispatching to Stage 3+, remind the user how to verify (npm run serve, then visit http://localhost:3000). Static sites often fail silently when opened with file:// (localStorage blocked).
Reference Files (Read When Needed)
When you need deeper detail than this entry point provides, read the appropriate reference:
- `references/consistency-checklists.md` — Read after every stage transition. Contains the full per-stage cross-artifact checklist (what to verify after Stage 1, 2, 3, ... 6, 5b). Catches "I changed X but forgot to update Y" bugs.
- `references/scenarios.md` — Read when the user's intent is ambiguous. Contains a dozen typical user prompts ("我有講義 .md 了", "客戶要濃縮版 + PDF") mapped to the exact sub-skill dispatch flow.
- `references/troubleshooting.md` — Read when something is reported broken. Maps symptoms ("素材連結 404", "進度勾選跑掉", "PDF 沒頁碼") to the most likely sub-skill / audit / verification path.
- `references/design-rationale.md` — Read when explaining the skill architecture itself, or when deciding whether a new feature deserves its own sub-skill vs. fitting into an existing one. Captures why the pipeline is shaped this way.
What This Skill Does NOT Do
- Does not write any code itself — always dispatches to a sub-skill.
- Does not pick a CSS framework or build tool — assumes vanilla HTML/JS by default (see
static-spa-conversionfor why). - Does not decide the course topic, audience, or pedagogy — that's the user's domain.
Cross-Artifact Consistency Checklists
The actual hard part of teaching site maintenance: every change ripples to other files. Run the appropriate checklist after each stage finishes.
After Stage 1 (outline change)
- [ ] Day count / hours / schedule consistent in:
overview.md, eachday{n}/outline.md, and (if Stage 3+ exists)course-data.js:meta.days[] - [ ] Shared scenario references match across all days
After Stage 2 (content change)
- [ ] New material file dropped into
course-package/materials/folder → added tocourse-data.js:materials[]AND in the SPA's material URL router (getMaterialUrl()) - [ ] Quiz item count change → updates BOTH
quiz[]array AND every hardcoded "(N題)" / "— / N" / "passing score" string in the SPA (typically 5 places) - [ ] Per-unit
materials[]references matchcourse-data.js:materials[]item IDs - [ ] Every outline unit ID has a matching
## u-{id}section in the correspondingday{n}/content.md(no orphaned outline units) - [ ] Every unit section declares
**圖片需求 (illustrations)**with 1–3 entries (or an explicitwaivedline) — this is the Stage 5 input contract
After Stage 3 (SPA wiring)
- [ ] Task IDs in
course-data.js:tasks[]are stable (they're localStorage keys; renaming wipes student progress) - [ ] Material router has fallback for unknown types
- [ ]
window.COURSE.day1/day2/day3/day4keys matchmeta.days[].id - [ ] Each
unit.idis unique within its day
After Stage 4 (interactivity)
- [ ] Sidebar collapse logic does NOT merge desktop and mobile into one class — they have opposite default states (see
static-spa-interactions) - [ ] Zoom variable only on
.content, never onhtml(cascades multiplicatively) - [ ]
prefers-color-schemeNOT used as theme source of truth — only[data-theme]attribute - [ ] localStorage key has a version suffix (e.g.
-v1) so future schema changes are non-destructive
After Stage 5 (visuals)
- [ ] Coverage Floor: every unit in
course-data.jshasillustrations.length >= 1(and<= 3); units that genuinely need no image carryillustrations: [{ kind: 'waived', reason: '...' }]— empty arrays fail - [ ] Every image referenced by
course-data.js:illustrations[].name(or legacyillustration) actually exists on disk - [ ] PNG-first + SVG fallback path is intact for AI-generated images
- [ ] All AI illustrations use the same style prompt (consistency across the course)
- [ ] No image embeds Chinese text inside the PNG (AI usually fails this — use SVG instead)
- [ ] Cover image exists in addition to per-unit images (cover does NOT count toward any unit's 1–3 quota)
After Stage 5b (Corporate Edition)
- [ ] Corporate folder is self-contained (no
../paths except documented fallback chain) - [ ] Inlined
window.COURSEis consistent with the source it was condensed from (runweb-content-audit) - [ ] Asset fallback chain (corporate
assets/→ publicassets/) resolves every reference - [ ] Brand customisation variables (client name, scenario) updated everywhere, including the corporate
README.md - [ ]
index.htmlopens via double-click (nofetch()of local JSON, no features requiring HTTP)
After Stage 6 (Ebook)
- [ ] PDF cover has no page number (
@page :first { margin: 0 }works in Playwrightpage.pdf()) - [ ] Quiz / pre-test / post-test content is excluded from ebook (avoid leaking assessment)
- [ ] Every image in composed markdown resolved to a real file (no broken-image squares)
- [ ] If both PDF and DOCX produced, content is identical (same composed
master.md) - [ ] DOCX inner structure inspected (
inspect-docx-images.mjsconfirms expected image count)
Universal Checklist (Run After Any Change)
Regardless of which stage was touched:
- [ ]
web-visual-verificationpasses (UI doesn't break, noconsole.error) - [ ]
web-content-auditproduces an empty / clean report (no orphaned references) - [ ] Manually visit the site once at desktop + mobile viewport before claiming "done"
The audit doesn't block release, but the human must read the report and make an explicit go/no-go call. The verification gates release — if it fails, block.
Design Rationale — Why This Skill Architecture
If you're wondering "why is this skill organised the way it is", "should this new feature be a new sub-skill or fit into an existing one", or "the user wants X — does that map to my architecture cleanly", read this.
Why One Top-Level Skill + 10 Sub-Skills (Not One Mega-Skill, Not 11 Flat)
Considered alternatives:
1. One mega-skill (teaching-site does everything inline) — rejected because:
- Single SKILL.md would be > 1500 lines, busting skill-creator's < 500-line recommendation.
- Every conversation that mentioned "做電子書" would load all 1500 lines into context, even though only ebook content is relevant.
2. 11 flat skills, no entry point (the original design) — partially worked but:
- Users with broad requests ("做一套課程網站") got triggered into one specific stage, miss the orchestration.
- 11 descriptions permanently in
available_skillsis heavier than 1+10 with the top-level as the broad trigger. - "What is this set of skills?" had no canonical answer; you had to read 11 SKILL.md to find out.
3. Current design (teaching-site top + 10 sub-skills) wins because:
- Top-level handles broad requests with orchestration.
- Sub-skills remain independently triggerable for narrow requests.
- Top-level's
references/provides scaling-without-mega-skill: detailed scenarios / troubleshooting / checklists live in references that are only loaded when needed.
Why Connect Rules Live in Sub-Skills, Not the Orchestrator
The big "three-place sync" knowledge could go in teaching-site orchestrator, but it lives in course-content-authoring and static-spa-conversion. Reason:
- The rule "every new material needs file + course-data.js entry + router rule" is triggered by an action (adding a material). The skill that handles that action (
course-content-authoring) is where the rule belongs. - If the rule lived in the orchestrator, every sub-skill invocation would need a "did I follow the orchestrator's rules?" check — that creates fragile coupling.
- This is the "co-locate rules with the action that triggers them" principle. Orchestrator only owns rules that span sub-skills (e.g. "verify after every stage").
Why "Verify vs Audit" Are Two Separate Skills
Tempting to merge them ("they both check things"). Wrong because:
- They have opposite failure modes (verify blocks CI on non-zero exit; audit always exits 0 and produces a report for humans).
- They're invoked at different cadences (verify on every change; audit at release milestones).
- They have different intended consumers (verify is for the CI / pre-deploy gate; audit is for human judgement).
Skills must have a single dominant operating mode. A skill that's "sometimes blocks, sometimes informs" produces unclear behaviour.
Why course-corporate-edition Is Stage 5b Not a Subset of Stage 3
A corporate edition isn't "Stage 3 with different course-data". It's a fundamentally different artifact:
- Single-file delivery (inlined COURSE) vs. multi-file (external course-data.js)
- Asset fallback chain (corp → public) vs. single asset folder
- Audience: client IT who unzips and self-hosts vs. learners visiting a URL
If static-spa-conversion had a "corporate flag" it would be 30% configuration switches. Separating them keeps both clean.
Why Ebook Is Stage 6 Not a Sub-Step of Stage 5
The ebook reads window.COURSE from the deployed site (web or corporate). It's a derivative consumer, not a step in producing the site itself. Stage 5 (visuals) leaves the site complete; Stage 6 derives a new artifact from it.
If we'd called the ebook "Stage 5.5", users would assume building the ebook is a normal part of the site pipeline — but it's optional and runs only at release milestones.
When to Create a New Sub-Skill vs. Extend an Existing One
Create a new sub-skill if all three are true:
- It has its own distinct trigger phrases that don't overlap existing ones.
- It produces a distinct artifact or operates on a distinct concern.
- Its concerns are not naturally scoped by an existing stage (e.g. design-system is cross-cutting, so couldn't fit into any single stage).
Extend an existing sub-skill otherwise. Common case: a new variant of corporate edition (e.g. corporate-edition with custom case studies). That's a parameter of course-corporate-edition, not a new skill.
Special case: References inside this top-level skill: If the knowledge is more about "how to orchestrate" than "how to do" the work, add a reference file here instead of a new sub-skill.
Why the Design System Is Cross-Cutting Not Stage-Specific
Design tokens (colors, typography, components) are referenced by:
- Stage 3 SPA (visual style of every page element)
- Stage 4 interactions (hover states, transitions reference token timings)
- Stage 5 visuals (illustration style consistency)
- Stage 5b corporate edition (must keep the brand)
- Stage 6 ebook (print CSS overrides token surfaces but keeps badge / typography)
A skill referenced by 5 other skills shouldn't live inside any one of them. Cross-cutting placement is right.
The Domain-Agnostic Principle
Critical: none of these skills hardcode "AI workshop" content. The example workshop ("行政與財務 AI 自動化") was the data source, but every skill describes the shape of teaching sites, not the topic of any specific course.
This means:
- A cooking class could use these skills unchanged.
- An accounting training could use these skills unchanged.
- The user's
content.mdcarries all topic-specific knowledge; the skill prompts carry only structural knowledge.
If you find yourself adding "this is about AI workshops" to a sub-skill prompt, refactor — that example belongs in the user's content.
The Bilingual Trigger Strategy
Every sub-skill's description has both Chinese and English trigger phrases. Reason: skill matching across most agents (Claude Code, Codex, Antigravity, etc.) is keyword-based against the description; users will type whichever language they're comfortable in. Halving the phrase list to one language halves the recall rate.
Format: "Triggers on phrases like \"中文\", \"中文 2\", \"english\", \"english 2\"."
When the Architecture Breaks
These signs suggest the skill set needs revision (not just patching):
- A request consistently fails to dispatch correctly — the top-level skill's detection rules need clarification, or a new sub-skill is needed.
- Two sub-skills constantly need to be invoked together — they should probably merge, or one should reference the other in its description.
- A user concept doesn't fit any sub-skill — either it's outside the domain, or you need a new sub-skill.
- A sub-skill's SKILL.md exceeds 600 lines — split it (create variants or use
references/like this top-level skill does).
The architecture is meant to be revised. Skills are not contracts; they're living documents. When they fail to serve, change them.
Typical Session Patterns — User Prompt → Dispatch Flow
When the user's request is one of the patterns below, you already know which sub-skills to invoke in what order.
Build From Scratch
"幫我從零做一個 4 天工作坊網站" → Stage 1 (course-outline-design) → Stage 2 (course-content-authoring) → Stage 3 (static-spa-conversion) → Stage 4 (static-spa-interactions) → Stage 5 (web-visual-assets).
- Pin design tokens before Stage 3 (
teaching-site-design-system). - Confirm scope at each stage boundary; don't auto-progress.
Migrate Existing Markdown to Web
"我有講義 .md 了,幫我做成網頁" → Skip 1–2 (the markdown IS the outline+content). Go straight to Stage 3 (static-spa-conversion). Read existing .md files first to extract meta / units / materials. Then Stage 4 → 5 as normal.
Incremental Changes
"加一個新單元" → Stage 1 update (add unit ID to outline) → Stage 2 (write its content) → Stage 3 (add to course-data.js:units[]) → web-content-audit to confirm three-place sync.
"網站可以動了,但手機版很爛" → Stage 4 (static-spa-interactions) only. Don't touch content or SPA structure. After: run web-visual-verification multi-viewport.
"課程素材連結 404" → This is the three-place sync bug. Invoke web-content-audit first to identify which place is missing; then patch in Stage 2 / 3 as the audit indicates.
"插圖看起來不一致" → web-visual-assets for asset-level regen, or teaching-site-design-system for the system-level decision (illustration style spec).
Derivative Deliverables
"幫我把公開班濃縮成企業包班 6 小時版" → Stage 5b (course-corporate-edition). Pre-requisite: public-class site is feature-complete and stable. Output: a new corporate-editions/{client}_{hours}h/ folder.
"網站做完了,幫我印一份 PDF 給學員" → Stage 6 (course-ebook-publishing). Verify site is stable first; if it's not, defer. Mention to user that the ebook is a derivative — site changes after this point require re-running the ebook build.
"客戶要一份濃縮版 + 配套的 PDF" → Stage 5b first (produce corporate folder), THEN Stage 6 (build ebook against the corporate folder). The ebook builder's loadCourseFromIndexHtml() works for both inline (corporate) and external (public) course-data sources.
Verification / Audit
"我剛改了 sidebar,要怎麼確認沒壞" → web-visual-verification with multi-viewport profile (iPhone SE / 13 / iPad Mini / Desktop).
"我刪了一個 unit,影響有多大" → web-content-audit: id-stability audit + material-references audit. Both produce markdown reports. Read both before deciding which downstream files to patch.
"網頁跟 PDF 看起來不一樣" → teaching-site-design-system: cross-format token reuse section. The two formats must consume the same token file; if PDF diverges, the style-ebook.css @media print block has overrides that shouldn't be there.
Visual Style Decisions
"PROMPT 區塊要用什麼顏色" → teaching-site-design-system. Specifically the "Why orange for PROMPT" rationale. Don't ad-hoc pick — read the dual-accent strategy first.
"我想改字體" → teaching-site-design-system. Read the "one font stack to rule them all" section before fragmenting the typography system.
Ambiguous / Exploratory
"我不知道從哪裡開始" → Read references/troubleshooting.md to gauge user's current state. Likely Stage 1, but confirm with 1–2 clarifying questions about: existing materials? target audience? delivery format (web only / web+PDF / corporate)?
"這個專案我之前做到一半,繼續" → Inspect the file tree first. 課程包/ exists? Stage 1+. course-data.js? Stage 3+. assets/illustrations/? Stage 5+. dist/*.pdf? Stage 6 was done. Pick up at the first incomplete stage.
Troubleshooting — Symptom → Likely Skill Path
Map common reported symptoms to the sub-skill / audit / verification path most likely to resolve them.
Symptom: "素材連結 404" / 學員點素材打不開
Diagnosis: Three-place sync was incomplete.
Path: web-content-audit (run material-references audit) → identify which of the three places is missing → patch:
- If file missing → put it in
course-package/materials/ - If
course-data.js:materials[]missing →course-content-authoring - If
getMaterialUrl()rule missing →static-spa-conversion
Symptom: "進度勾選跑掉" / 我打勾的任務又變空
Diagnosis: Task ID was renamed (almost always). localStorage key for the old ID still exists but the new render uses a different ID.
Path: 1. git log -p course-data.js | grep -i task — find the renamed ID 2. Either revert the rename, OR migrate by retiring the old ID and educating users that progress restarts 3. Add a web-content-audit id-stability check to your CI to prevent regression
Symptom: "結訓測驗分數顯示錯誤"
Diagnosis: Quiz item count changed but one of the 5 hardcoded "N題" strings wasn't updated.
Path: course-content-authoring — search index.html for all of:
- "結訓測驗(N 題)" in the section title
- "— / N" in the score display (usually 2 places)
- The toast message after submission
- The passing threshold
s >= K
All 5 must match window.COURSE.quiz.length.
Symptom: "手機版 sidebar 卡死 / 不能滾動 / 看不到漢堡鈕"
Diagnosis: Most likely the dual-class antipattern — someone merged sidebar-closed (desktop) and sidebar-open (mobile) into one class.
Path: static-spa-interactions — read the "Sidebar — Two Modes, Don't Merge Them" section. They MUST remain separate classes with opposite default states.
Symptom: "window 不能滾動 / scrollY 永遠是 0 / topbar sticky 失效"
Diagnosis: An ancestor has overflow-x: hidden which implicitly sets overflow-y: auto, hijacking scrolling away from window.
Path: static-spa-interactions — see "Pattern 2 Why position: fixed not sticky" and the overflow-x: hidden trap. Move overflow-x to body or html, or use a different containment strategy.
Symptom: "Day hero 數字消失 / 進場後不見了"
Diagnosis: IntersectionObserver didn't fire (often because CSS zoom is active and breaks the observer), and the fade-in used opacity: 0 transition without a fallback.
Path: teaching-site-design-system — Day hero section. Switch from opacity: 0 → transition to @keyframes. Default state visible; animation just decorates.
Symptom: "sidebar 跟著 zoom 一起放大"
Diagnosis: zoom was applied at html or :root, cascading to all descendants including sidebar.
Path: static-spa-interactions — Pattern 5 (Content Zoom). The --content-zoom variable must only be consumed by .content, never by ancestor html. Sidebar is outside .content.
Symptom: "PDF 封面也有頁碼"
Diagnosis: @page :first { margin: 0 } not present, or Playwright page.pdf() is called without displayHeaderFooter.
Path: course-ebook-publishing — the "Cover page without page number" section. Both the CSS rule AND the footerTemplate configuration matter.
Symptom: "DOCX 圖片很少 / 排版亂"
Diagnosis: pandoc raw-HTML support is partial. <figure-grid> and other custom layouts get dropped; images via markdown  survive but custom HTML doesn't.
Path: course-ebook-publishing — DOCX section. Inspect with inspect-docx-images.mjs to count actual embedded images vs expected.
Symptom: "企業包班版圖片有些 404"
Diagnosis: Asset fallback chain is broken — either the corporate assets/ doesn't have the override AND the public-class assets/ doesn't have it either.
Path: course-corporate-edition — verify the ASSET_ROOTS array iterates correctly. Run web-content-audit for asset coverage on the corporate folder.
Symptom: "console 有錯誤但網站看起來正常"
Diagnosis: Verify script is missing pageerror / console.error listeners.
Path: web-visual-verification — every verify script must collect runtime errors and assert empty at end. The "Skeleton: Multi-Viewport Verify Script" section has the pattern.
Symptom: "我不知道哪裡壞了,網站看起來怪怪的"
Diagnosis: Need broad diagnostic first, not targeted fix.
Path: 1. web-visual-verification multi-viewport — catches the obvious renders 2. web-content-audit — surfaces invisible drift 3. If both clean, ask user to be more specific ("can you point to a screenshot or a URL?")
Symptom: "電子書跟網頁不一致 / 同一個東西長得不一樣"
Diagnosis: Design tokens diverged between web CSS and style-ebook.css. Likely the print CSS has overrides that shouldn't be there.
Path: teaching-site-design-system — Cross-Format Token Reuse section. The @media print block should only override surface tokens (white background) for print, NOT badge / prompt colors which must stay identical.