lesson-read-aloud
Skill5 starsChanged 3 months agoApache-2.0View on GitHub
Turn lesson PDFs into a read-aloud study page — extract the text from each PDF, embed the original page screenshots, and attach an English audio player that reads the whole lesson aloud (a real click-to-play progress bar). Built for Hong Kong primary-school 常識科/General Studies lessons but works for any subject. Use when the user says "朗讀"、"課文朗讀"、"朗讀教學"、"常識科"、"小學常識"、"read aloud"、"配個朗讀音頻"、"念課文", or drops one-or-more lesson PDFs and asks for an audio read-along page.
In this repository54 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- agent-teamsSkill
- bilibili-channelSkill
- bot-configSkill
- browser-cliSkill
- bwrap-bypassSkill
- cc-pages-backupSkill
- chat-styleSkill
- chinese-dictationSkill
- code-wiki-reconSkill
- deck-builderSkill
- docx-form-fillerSkill
- evolutionSkill
- explainer-distillSkill
- feishu-bitableSkill
- feishu-docSkill
- feishu-mailSkill
- feishu-sheetSkill
- feishu-user-msgSkill
- fireworks-tech-graphSkill
- frontend-slidesSkill
- gemini-ui-reviewerSkill
- hk-busSkill
- hk-share-award-tax-dipn38Skill
- imagen-generatorSkill
- issue-handlerSkill
- lecture-videoSkill
- lecture-voiceSkill
- live-canvasSkill
- lustre-mounterSkill
- manim-teaching-figuresSkill
- math-video-tutorSkill
- memory-gcSkill
- memory-lintSkill
- multimodal-explainerSkill
- music-generatorSkill
- notifySkill
- page-styleSkill
- paper-explainerSkill
- session-handoffSkill
- skill-creatorSkill
- smoke-testSkill
- study-materialSkill
- tmux-installerSkill
- tmux-orchestratorSkill
- tpuguruSkill
- tts-generatorSkill
- veo-generatorSkill
- vscode-referenceSkill
- weather-forecastSkill
- wechat-readerSkill
- wikiSkill
- youtube-channelSkill
- zsh-installerSkill
The file
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 25
Write to /tmp/lesson-input.json (one entry per lesson):
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Lesson Read-Aloud Generator
Given one PDF per lesson, produce a self-contained multi-tab HTML page where each tab is one lesson containing:
- an
<audio controls>player that reads the whole lesson aloud (English voice, click-to-play progress bar), - the original PDF page screenshots (kids follow the real textbook), and
- the extracted lesson text (large, clean, for reading along).
The user (Chris) typically drops several PDFs at once — each PDF is one lesson → each becomes its own tab.
Workflow
Step 1 — Extract each lesson's text (you, Claude)
Read every PDF the user sent with the Read tool. For each lesson, extract the English text faithfully, word-for-word, split into natural paragraphs. Preserve the reading order; skip page numbers, running headers, and pure decoration. If a word is illegible, transcribe your best guess — don't drop it.
You do not screenshot the pages yourself — the script does that via pdftoppm. Just keep each lesson's PDF path.
Step 2 — Build the input JSON
Write to /tmp/lesson-input.json (one entry per lesson):
{
"title": "P1 常識科朗讀",
"slug": "gs-p1-unit1",
"voice": "kore",
"lessons": [
{
"id": "L01",
"title": "Lesson 1: My Body",
"pdf": "/tmp/lesson1.pdf",
"paragraphs": [
"Our body has many parts.",
"We use our eyes to see and our ears to hear."
]
},
{
"id": "L02",
"title": "Lesson 2: My Family",
"pdf": "/tmp/lesson2.pdf",
"paragraphs": ["..."]
}
]
}Step 3 — Run the generator
python3 ~/.claude/skills/lesson-read-aloud/scripts/generate.py /tmp/lesson-input.jsonIt prints the public URL on stdout (stderr shows per-lesson progress). Send that URL to the user bare, no quotes (Feishu turns quotes into part of the link → 404).
https://www.closecrab.com/pages/lesson-gs-p1-unit1.htmlDefaults / fields
| Field | Default | Notes |
slug | (required) | ASCII-only; the URL is lesson-{slug}.html. Same slug = same URL = updates in place. Use gs-p1-unit1, 2026-spring-week3, etc. |
title | Read-Aloud Lesson | Page heading (Chinese is fine — it's display text, not the URL). |
voice | kore | English read-aloud voice. kore (clear, steady) is the default; leda (younger), achernar (softer), charon (knowledgeable) also work. Let the user hear it, then swap if they want a different one. |
engine | gemini | edge is the fallback (no style control). |
lessons[].id | (required) | Short stable id like L01 — used for filenames and tab anchors. |
lessons[].pdf | (optional) | PDF path → page screenshots. Omit for a text-only read-along page. |
lessons[].paragraphs | (one of two) | List of paragraph strings. Or use lessons[].text (a single string split on blank lines). |
Caching & incremental updates
- Audio is hash-named on the full lesson text + voice + engine. Re-running with an unchanged lesson skips TTS for it — only changed/new lessons re-synthesize. Adding a lesson later = append it to the JSON and re-run; existing lessons stay cached.
- Bumping
PROMPT_VERSIONingenerate.pyinvalidates all cached audio (only needed if the director prompt changes). - Page screenshots re-render every run (cheap); stale pages for a lesson are cleared first.
Notes
- English voice mode: the script wraps the text in a plain-English director prompt with no
[...]tags, sotts-generate.pypasses it through (its single-tag mode hardcodes "Say ... in Chinese", which would mangle English). Don't add bracket tags to lesson text. - One audio per lesson: the whole lesson is synthesized in one call (paragraphs joined with blank lines for natural pauses). Fine for typical primary-school lessons (<~300 words). If a lesson is very long and TTS fails, split it into two lesson entries.
- Tab switching is pure CSS (radio inputs), no JavaScript — works offline and prints cleanly.
- Output goes to GCS-mounted
/gcs/cc-pages/; writing the file is the upload. The only external resources are the PDF page PNGs under/assets/lra-{slug}/.
Files
scripts/generate.py— JSON → page screenshots + per-lesson TTS → multi-tab HTML on CC Pages.- Dependencies:
pdftoppm(poppler-utils),tts-generatorskill (Gemini 3.1 Flash TTS).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

