Open Free Books is sustained by contributors and sponsors. Thank you to everyone supporting this mission through GitHub Sponsors.

Chapter builds are full by default with bun run build:chapter (no --full flag needed).

Community

Contribute

Help grow free, open textbooks. Most contributions add curriculum data (what exists on the catalog) or publish a live chapter (readable lesson pages). This guide matches the repo’s CONTRIBUTING.md.

How the catalog fits together

data/{subject}-curriculum.json → catalog + graph (status, curriculumCoverage, edges)
content/{subject}/{slug}/      → live page (one folder)
  _index.md, core.html, supplement.html, assets/, widgets/
  • List — numbered cards; live chapters link from the whole card.
  • Map (?view=tree) — Mermaid map with strand columns; live chapters link from the title only ( + hover underline).
  • Compare (?view=compare, Mathematics only) — curricula comparison doc (HTML partial, not JSON).
  • Curriculum names (DSE, IB, …) appear only in the catalog, never inside lesson prose.
  • Every chapter needs a description (1–2 sentences; map clamps to three lines).
  • Adding a subject should only require updates in data/ and content/; templates stay unchanged.

Add a planned chapter

Use this when the lesson is not written yet but should appear in the catalog roadmap.

  1. Open data/{subject}-curriculum.json (e.g. data/math-curriculum.json).
  2. Find the right strand and add a chapter object:
{
  "slug": "your-chapter-slug",
  "title": "Human-readable title",
  "description": "One or two sentences for list and map cards.",
  "status": "planned",
  "curriculumCoverage": {
    "DSE": "core",
    "IB": "related"
  },
  "tier": "non-foundation"
}

tier is optional — omit for foundation topics; non-foundation shows an Extension badge.

Use kebab-case slugs. No content/ files needed for planned chapters.

Publish a live chapter

A live chapter needs a catalog JSON entry and a folder under content/{subject}/{slug}/.

1. Catalog entry

Set "status": "live" in data/{subject}-curriculum.json with description and curriculumCoverage.

2. Chapter folder

Add _index.md, core.html, optional supplement.html, assets/, widgets/*.tsx. Copy content/math/quadratic-equations/.

3. Build

bun run build:chapter math/your-chapter-slug syncs HTML, rebuilds targeted widgets, and updates generated outputs. Full mode is the default.

Chapter graph (map prerequisites)

Prerequisites are required edges in graph.edges. Strand chapters[] order is for the list only — it does not create arrows.

  • from / to are chapter slugs (any strand).
  • The graph must be acyclic (no cycles).
  • Branch: one parent → many children. Merge: many parents → one child (multiple edges).
  • Vertical position uses longest-path layering — a chapter sits below all ancestors.
"graph": {
  "edges": [
    { "from": "quadratic-equations", "to": "sequences-series" },
    { "from": "quadratic-equations", "to": "functions-graphs" },
    { "from": "functions-graphs", "to": "linear-programming" },
    { "from": "sequences-series", "to": "linear-programming" }
  ]
}

Verify at catalog map. Mermaid supports pan and zoom.

Local development

Prerequisites: Zola and Bun.

bun install
bun run dev                                     # start local site quickly
bun run build:chapter math/your-chapter-slug    # targeted full build
bun run build:chapter                           # full build for changed chapters (auto-detect + confirm)
bun run build:site                              # full site rebuild
bun test                                        # tests + curriculum validation
bun run build                                   # production alias of build:site

build:chapter already runs full mode by default, so no --full flag is needed.

Do not commit themes/openfreebooks/static/ or public/.

Catalog subject banner

Optional image at the top of the catalog header for a subject (List and Map). Subjects without banner in data/catalog.json stay plain.

  1. Prepare a 2:1 image (e.g. 2000×1000).
  2. Optimize to WebP in static/catalog/banners/{subject-id}.webp — use ffmpeg with libwebp, or cwebp -resize 1400 0 -q 82 … if ffmpeg lacks WebP support.
  3. Add "banner": "/catalog/banners/{subject-id}.webp" on the subject in data/catalog.json.
  4. Verify at /catalog/?subject=… after bun run build:chapter {subject}/* && bun run dev.

Ready to open a pull request?

Keep PRs focused. Describe subject, chapters, live vs planned, and curricula. Questions welcome on GitHub.

Support

GitHub Sponsors

Supporters who help keep Open Free Books free and open for learners everywhere.

Thank you to all sponsors