Four interactive, self-contained learning platforms plus a five-course cloud-native path, all running entirely in the browser. 71 streams, 628 lessons and 742 hands-on exercises: an in-editor coding exercise on every lesson, a belt progression, spaced-repetition review, a difficulty-filtered practice hub, a domain glossary with click-to-explain terms, tournaments, and end-to-end capstone projects.
| Course | Streams | Lessons | Exercises | Quiz questions | Content checks |
|---|---|---|---|---|---|
| Dev Dojo | 29 | 211 | 378 | 450 | 1,911 |
| Identity Dojo | 14 | 153 | 163 | 340 | 777 |
| JS Dojo | 16 | 66 | 109 | 198 | 407 |
| ML Dojo | 12 | 115 | 113 | 363 | in its own repository |
It began as a Java course (JavaDojo, which is why this repository was once named for it). Dev Dojo now spans the full stack: the Java language and JVM, computer science & algorithms, web/HTTP, front-end (React), APIs, databases & SQL, concurrency, security & cryptography, DevOps, architecture, and a senior ("dan") track.
Identity & access has its own course. It grew past 130 lessons (40% of Dev Dojo), which unbalanced a course meant to cover software engineering broadly. It is now Identity Dojo: 14 streams covering the identity lifecycle, OAuth 2.0/2.1 and OIDC, SAML, WebAuthn/FIDO2 internals, Active Directory and Kerberos, zero trust, and a Running Identity stream on incident response, migration and operations. Same engine, separate build.
JavaScript has its own course too. JS Dojo is 16 streams of the language and its runtime, and its exercises are graded by really running your code in a sandboxed Web Worker.
Machine learning starts at Python itself. ML Dojo is written for
someone who has never written a line of Python: Python, NumPy arrays and vectors, mathematical
notation, linear algebra, calculus and gradients, logarithms. A probability and statistics stream then
runs from counting through distributions, the Gaussian, Bayes, maximum likelihood, expectation
maximization, Lagrange multipliers and the bias-variance decomposition. Then the models: regression,
the classifier zoo, clustering, neural networks from the perceptron to the transformer, and
reinforcement learning from the multi-armed bandit through Q-learning and policy gradients to the
algorithm that fine-tunes language models. Every lesson opens in plain English and ends at textbook
rigor. Python runs in the browser through Pyodide. 12 streams, 111 lessons, 109 exercises, 351 quiz
questions, and a glossary of 203 terms across 8 domains. It lives in
its own repository and ships here as a tracked build snapshot at
ml-dojo/dist/index.html.
▶ Live: https://roniam.dev/ is the portfolio home, and https://roniam.dev/courses/ lists every
course. Dev Dojo ·
Identity Dojo ·
JS Dojo ·
ML Dojo. Each is a single, self-contained page: SQL exercises run
against real sample data in your browser with no server, JS Dojo's exercises execute in a sandboxed
Web Worker, and ML Dojo runs Python through Pyodide. The pages are served from GitHub Pages, whose
origin is rcbart.github.io/dojo/.
(First time: in Settings → Pages, set Source to "GitHub Actions". The workflow unit-tests the shared
engine, then verifies and builds the courses on every push, and fails the deploy if any check fails.
Four dojos and five crash courses ship from it; ML Dojo is copied in from its tracked build snapshot,
since it is built in its own repository.)
- Guided onboarding: a 🚀 Getting started page (how to set up your environment and how grading really works) and a 🗺️ Learning path (a recommended white→black-belt route).
- Every lesson ends with an exercise in the built-in editor. How grading works: most exercises, all the Java ones included, are checked by regex against the shape of your answer; they verify you wrote the right construct, not that your code runs correctly. Real execution is available where the environment allows it: SQL runs against sample datasets in the built-in engine and JavaScript in a sandboxed Web Worker, which covers 185 exercises graded on actual results. Java compiles and runs for real only if you start the optional local runner. Every exercise ships a Run locally panel with exact commands, which is the ground truth.
- Run it for real: every exercise has a 🖥️ Run locally panel with exact commands for your own dev environment, plus a 🔬 Dive deeper panel that states honestly how it was graded.
- 🔁 Review: spaced repetition builds a review deck from your completed exercises and schedules them on expanding intervals; the sidebar shows what's due.
- 🎯 Practice: every exercise is rated easy/medium/hard and filterable, giving a difficulty ramp across the whole catalog.
- 🧠 Quick check: multiple-choice questions with instant feedback: not just "wrong", but which answer was right, why it is right, and why the option you picked is not. Options are shuffled per lesson visit in all four dojos, so the answer position can never be memorized. The bank is 1,271 hand-authored questions: 397 in Dev Dojo, 331 in Identity Dojo, 192 in JS Dojo, 351 in ML Dojo. Every one carries a written explanation of why the right answer is right, plus a per-option rebuttal saying why the option you picked is wrong. Dev Dojo adds 41 more auto-generated from the exercise specs. Extending the hand-authored bank to the remaining lessons is an open item.
- 📖 Glossary: 11 domains / 360 terms shared by Dev, Identity and JS Dojo, collapsible and searchable, doubling as the in-lesson click-to-explain source. ML Dojo carries its own: 8 domains, 203 terms.
- Belts & capstones: per-domain percentage belts (white → black), dan sub-tracks for advanced
topics, and a graded multi-step capstone. Streams
flagged
tournament:trueorproject:trueare practice and don't count toward belts.
Three decoupled layers: content is pure data, a vanilla-JS runtime renders it, and a build step fuses everything into one offline file. An optional Node/SQLite backend adds accounts and progress.
flowchart TD
subgraph Content["content/streams/*.js (pure data)"]
M[manifest.json order] --> S["STREAMS.push · lessons · exercises · regex tests"]
end
subgraph Runtime["engine/ (shared runtime, vanilla JS, zero deps)"]
A["app.js · nav · editor · graders (SQL/JS/Java) · Review · Practice · quizzes · glossary"]
E["sqlengine.js · in-browser SQL engine + sample datasets"]
C["styles.css · shell.html · boot.js"]
end
subgraph Course["src/ (per course)"]
G["gradejava.js · quizzes.js · quizzes_hand.js"]
end
V["scripts/verify.js · CI gate: parses modules, runs every test vs its solution"]
B["build.js · concatenate + inline"]
D["dist/index.html · one self-contained offline file"]
Site["site/ · Node + node:sqlite · scrypt auth · CSP · rate limiting"]
GH["GitHub Actions → GitHub Pages"]
Content --> B
Runtime --> B
Course --> B
Content --> V
V --> B
B --> D
D --> Site
B --> GH
Runtime --> ID["identity-dojo/ · same shape, own content + build"]
Runtime --> JS["js-dojo/ · same shape, own content + build"]
ID --> GH
JS --> GH
ML["ml-dojo/dist/index.html · tracked snapshot, built in its own repo"] --> GH
The engine is unit-tested. node --test engine/test/engine.test.js runs 35 tests against the shared
runtime's pure logic: regex grading and its failure modes, the Web Worker sandbox preamble, quiz option
shuffling, difficulty rating, and HTML escaping. They run in CI before any course is built, because a bug
in the engine breaks every course at once. Two of them exist because a real bug shipped: every hand-authored
quiz once had its answer at option A, and two exercise regexes did not match their own reference
solutions. Writing them found a third: esc() threw on undefined, which would blank a panel rather
than render nothing.
How grading works (honestly). The headline number to be careful with is the content checks
badge: scripts/verify.js runs 1,911 assertions for Dev Dojo, and 3,095 across the three
engine-based dojos, proving every exercise's reference solution matches its own regex checks and that
ids are unique. ML Dojo has its own workflow, which executes all 62 runnable Python reference solutions against the assertions the learner is graded on. A separate gate,
scripts/verify-exec.js, goes further for the exercises that are executed: it loads each reference
solution and calls it with that exercise's own cases, 1,089 of them across 194 exercises, so a solution
that does not actually produce the expected result fails the build. That is a content integrity
gate, not a test suite for a running product; it says the material is internally consistent, not
that a learner's code is correct.
Grading itself splits three ways:
| Path | Share | What it actually verifies |
|---|---|---|
| Regex structural checks | 454 of 702 (65%) | That your answer contains the expected constructs. Not correctness. Most Java, shell, YAML and prose exercises land here. |
| Real execution, in-browser | 248 of 702 (35%) | 185 JavaScript exercises run in a sandboxed Web Worker and are compared on real return values. 63 Python exercises run in Pyodide and are checked by assertions against the actual interpreter state. SQL runs against sample data in engine/sqlengine.js. |
| Real execution, opt-in | a subset of the Java exercises | Compiles and runs via the local runner (site/ + JD_LOCAL_RUNNER=1) with a generated DojoTest harness, off by default. |
So a green check on most exercises means "this looks right", not "this works". Every exercise has a Run locally panel with exact commands, and that is the ground truth. Raising the share of real execution is the most valuable open improvement to the platform.
The home page: belt progression per domain, and the "how to learn & retain" guide.
A SQL lesson: the in-editor exercise, "What your code must do", and the Compile & Run panel. SQL is
graded by running it against sample data and comparing result sets.
The domain-grouped glossary. Every term here is also click-to-explain inside any lesson.
engine/ the SHARED RUNTIME, used by every engine-based course in this repo
app.js state, nav, lessons, editor, Review (SRS), Practice, quizzes
glossary.js keyword table, click-to-explain and the glossary (loads before app.js)
grade.js all five grading paths
feedback.js lesson ratings and written comments
sqlengine.js dependency-free in-browser SQL engine + sample datasets
boot.js startup wiring
shell.html page shell (placeholders: @@STYLES@@, @@SCRIPT@@)
styles.css all styling
src/ Dev Dojo's own content-derived maps (NOT the engine)
gradejava.js auto-generated executable-grading specs (by lesson id)
quizzes.js auto-generated quick-check bank (by lesson id)
quizzes_hand.js hand-authored quizzes, where they exist
content/streams/ one module per stream, the course content itself
manifest.json stream order
LESSON_TEMPLATE.md the shape every new lesson follows: skeleton, checklist, gates
scripts/verify.js content integrity gate: parses every module, runs each exercise's
regex tests against its own solution, checks id uniqueness
scripts/verify-exec.js execution gate: runs every run-spec exercise's reference
solution against its own cases, as the browser worker does
scripts/verify-java.js compiles every self-contained Java reference solution
scripts/verify-depth.js depth gate: every lesson against half its course median
scripts/verify-cloudnative.js cloud-native gate for the five crash courses: pages exist,
quizzes well-formed, Next-chains match the built order
build.js engine/ + src/ + content/ -> dist/index.html (+ devdojo.html)
identity-dojo/ Identity Dojo: same shape, consumes ../engine
js-dojo/ JS Dojo: same shape, consumes ../engine
ml-dojo/dist/ ML Dojo's built page, a tracked snapshot from its own repository
site/ optional Node server: accounts, progress sync (SQLite via node:sqlite)
Why engine/ is separate. src/ used to be both "Dev Dojo's source" and "the shared runtime",
which meant a second course could only be added by forking 1,600 lines of app.js. Splitting the
engine out makes the seam explicit: a course is content plus a build file, and lifting one into its own
repository is a copy rather than a fork. ML Dojo is the proof: it left, and the engine did not notice.
Identity content lives in identity-dojo/ and JavaScript content in
js-dojo/, each with its own manifest and build. They reuse this runtime, so
there is one engine to maintain; only content, domain grouping and the page shell differ.
node scripts/verify.js # validate all content (target: 0 failures)
node build.js # produce dist/index.html (+ devdojo.html copy)The build output is a single, dependency-free HTML file; open devdojo.html directly in a browser,
or host dist/index.html on any static host. Generated files are gitignored; only source is
versioned. In CI, 18 gates have to pass before anything deploys: the engine unit tests, content
verification for each dojo, the execution gate, the Java compile gate, lesson depth, the cloud-native
check, color contrast, a run check on every built page, two quiz-balance gates, the home-page stats
check, a prose check, sitemap resolution, internal link resolution including fragments, a check that
the authlint snapshot still matches its own source repository, and a check that the revision claim on
the home page is backed by the posts.
PORT=3000 node site/server.js # then open http://localhost:3000Requires Node 22.5+ (built-in SQLite). Behind HTTPS, set JD_SECURE_COOKIES=1; behind a trusted
reverse proxy, set JD_TRUST_PROXY=1. The user database lives in site/data/ and is gitignored.
Each stream module calls STREAMS.push({ icon, title, blurb, lessons:[...] }). A lesson has body
(HTML), optional docs links, and one ex or several exs. An exercise carries prompt,
starter, solution, regex tests ({ d, re, flags?, not? }), behavior (shown as "What your
code must do"), and hints. Non-Java exercises set lang ('sql', 'shell', 'js', 'jsx',
'text'). Identity modules add iam:true and a sec:'...' sub-category label.
Content lives inside JS template literals. Escaping rules that keep the build clean: escape backticks
and ${; in HTML body code samples use </>/&; keep single-quoted hints free of
apostrophes and \u sequences. Always run node scripts/verify.js after editing.
Five companion courses on their own lighter pipeline (markdown → web/build.py → one interactive
HTML file each), all live on the same site and gated in CI by scripts/verify-cloudnative.js
(80 modules, 374 quiz questions, every answer explained, right and wrong options alike):
- Cloud-Native Fundamentals, the map before the machines: the path of a request, load balancers, API gateways, CDNs, DNS in depth, TLS, queues & caches. Pure concepts, nothing to install.
- Docker ·
Kubernetes ·
Envoy ·
Istio: hands-on on your own machine; each starts
with a step-by-step local setup guide, and Envoy ships runnable lab configs in
envoy-crash-course/labs/. oauth-trainer/: a small Maven CLI for generating and signing JWKs
DEVDOJO_ROADMAP.md, per-domain belt design and curriculum planIAM_TOPICS.md, the identity & access topic mapLAUNCH_GUIDE.md, hosting → backend → AI judge → sandboxed runnerBACKEND_PLAN.md, architecture for publishing Dev Dojo as a productMLDOJO_PLAN.md, ml-dojo architecture and curriculum