First public release of the html-explainer skill: deterministic HTML-to-MP4 explainer video pipeline for AI coding agents. Additions since v1.2.1: - scripts/lint_frames.py: pre-render audit of the eight frame-contract rules - scripts/peek_frame.mjs: single-scene screenshot preview (seconds, not minutes) - scripts/check_integrity.py: version/catalog/count consistency + stray-CDN scan - Bilingual README (README.md Chinese default, README.en.md English) - LICENSE (MIT), THIRD_PARTY_NOTICES.md, licenses/Apache-2.0.txt - CHANGELOG.md, CONTRIBUTING.md, .gitignore, .gitattributes - GitHub CI workflow and issue/PR templates Fixes and docs: - document lint_frames.py and peek_frame.mjs, previously absent from the file table - add the lint stage to the pipeline order - remove references to private client projects so the skill can ship publicly - record the full upstream attribution chain for the style catalog - package_skill.py now excludes repo-hygiene files and keeps licence files
6.4 KiB
Contributing to html-explainer
Thanks for taking the time to contribute. This document covers the practical things: how to get a working environment, what the project's hard rules are, and where different kinds of contributions actually belong.
Ways to contribute
| Kind of contribution | Where it goes |
|---|---|
| Bug report | Open an issue using the bug template |
| Rendering / sync bug you diagnosed | Add a numbered entry to references/lessons.md and fix the code |
| New visual style or a better adaptation recipe | references/style-catalog.md notes + a documented example |
| Documentation fix | Direct PR — typo fixes need no prior discussion |
| New feature | Open an issue first so the approach can be agreed before you write it |
| Platform-specific fix (macOS / Linux paths, shell variants) | Very welcome — the project is developed on Windows + Git Bash |
Development setup
git clone https://github.com/OneMoh/html-explainer.git
cd html-explainer
# Check the environment, then install anything missing
bash setup_env.sh # report only
bash setup_env.sh --install # fetch missing dependencies
# Confirm the toolchain is healthy
node -v && python -V
Requirements: Python ≥ 3.9, Node ≥ 18, and either Chrome or Edge (both are almost always
already present). ffmpeg is used from PATH or falls back to the static binary bundled
with imageio-ffmpeg.
Running an end-to-end check
python scripts/new_project.py demo --topic "人工智能"
cd demo
# fill narration.json, write frames/*.html, set project.json order
python ../scripts/tts_build.py --project .
python ../scripts/timeline_build.py --project .
python ../scripts/subs.py --project .
python ../scripts/lint_frames.py --project .
node ../scripts/render_video.mjs . --preview 30
If all of that completes and out/preview.mp4 plays with synchronised audio, your
environment is good.
The project's hard rules
These are not style preferences. Breaking them produces silent failures — a video that
renders but is wrong. They are enforced by scripts/lint_frames.py where possible.
- No external fonts or CDN resources in any frame. Web fonts are unreachable from
many networks and time out silently. Use system font stacks only, and reference GSAP
from the bundled
../assets/gsap.min.js. - Colours come from
theme.cssCSS variables only. No hex literals in frame code. This is what makes a theme change a one-file operation. - No wall-clock logic.
setIntervalandrequestAnimationFramecounters cannot work under deterministic seeking. Animate with GSAP or CSS@keyframes. - Animate with GSAP timelines, registered on
window.__tl. The renderer seeks this timeline once per frame; without it, nothing animates. - Position animations with
B('block text'), never hardcoded times. The fallback formB('x') || 3.2is forbidden — a missing block should fail loudly at build time, not silently reuse a stale number. - Keep the subtitle safe zone clear. Nothing may render in the bottom 80–170px, and entrance paths must not cross it.
- Use ASCII paths for all project directories and output files. Non-ASCII paths break ffmpeg on Windows. Project and output names are ASCII; rename for presentation later.
The full contract, with the reasoning behind each rule and the counter-examples that get
a frame rejected, is in references/frame-contract.md.
Adding a new lesson
references/lessons.md is the most valuable file in this repository. It exists because
this kind of pipeline fails silently — a bug produces a plausible-looking video rather
than an error.
A good entry contains, in this order:
- The symptom, as you first observed it — including how it misled you.
- The diagnosis, and the evidence that proved it (a probe, a diff, a measurement).
- The fix, and what to check afterwards to confirm it.
- The general rule this implies, if it implies one.
Number entries sequentially and append. Do not renumber existing entries — they are referenced from code comments.
Adding a new visual style
- Record the specification in
references/style-catalog.md(canvas, type scale, timeline structure, colour discipline) andreferences/style-catalog.json. - Classify it as
rich(single file, CSS@keyframestimeline — drivable by the seek renderer with no changes) orgsap(multi-composition — must be re-expressed, not copied). - Add an adaptation recipe to
references/template-guide.mdif the style needs anything beyond the standard three steps (swap the font stack, lift bottom elements out of the subtitle zone, fill in real content). - Verify it renders:
node scripts/peek_frame.mjs <project> <id> --at 25,50,85.
Style identifiers are kebab-case and match the pattern already in use (frame-*,
vfx-*).
Pull request checklist
Before opening a PR, please confirm:
python scripts/lint_frames.py --project <project>reports no FAILs for any frame you touched- You have actually rendered your change. Frame code that "looks right" frequently is not — seek-based rendering has its own failure modes
- Any new lesson is added to
references/lessons.mdwith a number - No external fonts, CDN references, or hardcoded colours were introduced
- If you redistributed or re-derived third-party content,
THIRD_PARTY_NOTICES.mdis updated README.mdandREADME.en.mdare updated together if user-facing behaviour changed
Commit messages
Conventional Commits are preferred (fix:, feat:, docs:, chore:). A body is
encouraged when the change fixes a silent failure — explain what was misbehaving and how
you verified the fix.
Scope note
This project intentionally does not aim to be a framework. It is a pipeline with a small, boring surface: HTML frames in, MP4 out, with audio-video sync that holds. Features that add a build system, a plugin API, or a runtime dependency on a cloud service are generally out of scope — say hello in an issue if you think there's an important exception.
License
By contributing, you agree that your contributions are licensed under the MIT License
(see LICENSE), and you confirm you have the right to submit them. If you are
porting content from another project, add it to THIRD_PARTY_NOTICES.md in the same PR.