agentleFS
yangwhaleyangwhale/CloseCrab/skills/lesson-read-aloud/SKILL.md

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.

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
  1. Very specific:

    Write to /tmp/lesson-input.json (one entry per lesson):

    line 25

≈ “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.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Lesson Read-Aloud Generator

Given one PDF per lesson, produce a self-contained multi-tab HTML page where each tab is one lesson containing:

  1. an <audio controls> player that reads the whole lesson aloud (English voice, click-to-play progress bar),
  2. the original PDF page screenshots (kids follow the real textbook), and
  3. 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.json

It 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.html

Defaults / fields

FieldDefaultNotes
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.
titleRead-Aloud LessonPage heading (Chinese is fine — it's display text, not the URL).
voicekoreEnglish 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.
enginegeminiedge 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_VERSION in generate.py invalidates 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, so tts-generate.py passes 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-generator skill (Gemini 3.1 Flash TTS).

Download now (ZIP)

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
What did you use it for? e.g. Reviewing pull requests in a Rails app

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.