A free, open-source code school. Courses for 50 programming languages — from your first line of code to the deep end — written as Markdown in this repo, rendered by a small static engine, and improvable by anyone with a text editor.
No accounts, no paywalls, no tracking, no build step. Progress lives in your browser's localStorage.
The site is plain HTML/CSS/JS, but it loads course content with fetch, so it needs to be served over HTTP (opening index.html straight from disk won't work):
python -m http.server
Then open http://localhost:8000. Any static file server works the same (npx serve, caddy file-server, ...).
- Push this folder to a GitHub repository.
- Edit
repoUrlinjs/config.jsto point at your repository (it feeds the Source / Contributing links). - In the repo settings, enable Pages → Deploy from a branch, pick your default branch and the
/ (root)folder.
That's the whole pipeline. There is no build step; what's in the repo is what's served. Everything uses relative paths, so the site works from a project subpath (https://you.github.io/your-repo/) as well as a root domain. .nojekyll is included so GitHub serves the files untouched, and 404.html routes stray URLs back to the app.
index.html the single page; all routes render into it (hash routing)
404.html GitHub Pages fallback → redirects to the app
css/styles.css the entire design
js/ the rendering engine
app.js routes + boot
markdown.js Markdown subset → HTML
highlight.js syntax highlighting (per-language token definitions)
blocks.js lesson block types: code, run, output, quiz + registry
runners.js in-browser code runners (JavaScript ships; others pluggable)
views/ home, catalog, course, lesson pages
content/ ALL course material lives here — the engine never changes
index.json the catalog: 50 languages with metadata and status
STYLE.md the writing style guide every lesson follows
<language>/ one folder per language
course.json curriculum: modules → lessons
lessons/<module>/<lesson>.md
_template/ copy this to start a new course
scripts/
validate.mjs checks catalog + courses + lessons against the schema
run-samples.mjs executes every runnable Python/JS sample, compares outputs
logo.py regenerates assets/ from the source logo image
Each language entry:
{
"id": "python",
"name": "Python",
"category": "popular",
"year": 1991,
"status": "course",
"lessons": 39,
"tagline": "Readable, patient, and everywhere from spreadsheets to spacecraft.",
"tags": ["dynamic", "general-purpose", "beginner-friendly"]
}status is course (lessons exist) or outline (curriculum mapped, lessons wanted). lessons mirrors the course.json total — node scripts/validate.mjs --fix keeps it in sync.
{
"id": "python",
"name": "Python",
"status": "course",
"tagline": "...",
"blurb": "A paragraph for the course page.",
"level": "no experience needed",
"runner": null,
"repl": "https://onecompiler.com/python",
"modules": [
{
"id": "first-steps",
"title": "First Steps",
"summary": "One sentence on what this module delivers.",
"lessons": [
{ "id": "hello-world", "title": "Hello, World", "minutes": 8 }
]
}
]
}runner names an in-browser runner from js/runners.js (currently "javascript"), used for that course's run blocks. repl is the fallback: an external site where run blocks link out when no in-browser runner exists.
Markdown with frontmatter and four special fenced blocks:
---
title: Hello, World
---
Plain prose. Standard Markdown: headings, bold, lists, links, tables, blockquotes.
```python
print("a static, syntax-highlighted sample")
```
```python run
print("the run flag adds a Run button (JavaScript) or a REPL link (everything else)")
```
```output
exactly what the program above prints
```
```quiz
{
"question": "One question, one right answer?",
"options": ["Yes", "No", "It depends"],
"answer": 0,
"explain": "Shown after a correct answer."
}
```
::: tip
Callouts: note, tip, warn, and deep ("under the hood").
:::The full authoring contract — voice, structure, code-sample rules — is content/STYLE.md.
- Check the catalog. If your language is one of the 47 outlines, the curriculum already exists — skip to step 4. Otherwise, add an entry to
content/index.json. - Copy the template.
content/_template/→content/<your-language-id>/. - Design the curriculum in
course.json: 6–9 modules, 4–6 lessons each, basics first. Keep it unmistakably your language's curriculum — name its real concepts. - Write lessons into
lessons/<module-id>/<lesson-id>.md, one file per lesson listed in course.json, followingcontent/STYLE.md. You can ship one module at a time; the course page simply links what exists oncestatusflips tocourse. - Validate.
node scripts/validate.mjs --fix(schema + lesson checks, syncs the catalog count) andnode scripts/run-samples.mjs <id>(executes runnable samples if the toolchain is installed locally). - Open a pull request.
No engine changes are ever needed to add or edit a course. If your language would benefit from syntax highlighting, add a token definition in js/highlight.js (defineLanguage); for an in-browser runner, register one in js/runners.js (defineRunner) and set the course's runner field. New lesson block types register in js/blocks.js (defineBlockType).
node scripts/validate.mjs check everything; exit 1 on problems
node scripts/validate.mjs --fix also sync lesson counts in index.json
node scripts/run-samples.mjs run every Python/JS `run` sample, diff outputs
node scripts/run-samples.mjs c limit to one course
python scripts/logo.py regenerate assets/ from the source logo PNG
MIT. The courses are code too — same license, same rules.