A tiny flashcard + multiple-choice app for learning to code by doing and repetition. Starting with bash.
Pick whichever's least friction for you. All four paths serve the same files.
# 1. Docker (recommended — no python needed; one command)
make up # → http://localhost:8080
make down # stop
# 2. Python http.server (no Docker needed)
make serve # → http://localhost:8000 (Ctrl+C to stop)
# 3. Just open the file
xdg-open index.html # localStorage works but some browsers complain
# 4. Self-contained image (no bind mounts; for shipping to a server)
make rebuild # builds from Dockerfile then runsOverride ports: make up PORT=9090, make serve PORT=9000.
make up bind-mounts the source directory into the container, so edits to
index.html / app.js / shell.js / data/*.js show up on a browser refresh
with no rebuild. make rebuild produces a portable image that includes the
files (uses docker-compose.build.yml + the Dockerfile).
- Flashcards — prompt → flip → rate yourself (knew it / got it wrong).
- Multiple choice — pick the right command from 4 options.
- Exercises — type real bash into a simulated terminal; we check the resulting filesystem / output. Supports
pwd,cd,ls,mkdir,touch,rm,cp,mv,cat,echo,head,tail,wc,grep,sort,uniq, plus pipes (|), redirects (>/>>), and chained commands (&&). - Weighted practice — items you get wrong resurface more often.
- Tag filter — narrow to e.g. just
pipesorpermissions. - Focus weak cards — only practice ones you've been getting wrong.
- Progress is saved per topic in
localStorage.
| Mode | Key | Action |
|---|---|---|
| Flashcards | Space | Reveal answer |
| Flashcards | 1 | Got it wrong |
| Flashcards | 2 | Knew it |
| Flashcards | S | Skip |
| Multi choice | 1–4 | Choose answer |
| Multi choice | Enter | Next card |
| Exercises | Enter | Run command (or advance once solved) |
index.html Markup + control bar
style.css Styling (dark + light)
app.js State, rendering, persistence, keyboard
shell.js In-browser bash simulator (window.Shell)
data/bash.js Bash flashcards (window.BASH_CARDS)
data/bash-exercises.js Bash exercises (window.BASH_EXERCISES)
Dockerfile Self-contained nginx image
docker-compose.yml Dev compose: bind-mounts the source for live edits
docker-compose.build.yml Prod-ish compose: builds from Dockerfile
Makefile `make help` for run shortcuts
- Create
data/<topic>.jsand assignwindow.<TOPIC>_CARDS = [...]using the same card shape asdata/bash.js. - Register it in
index.htmlwith another<script src="data/<topic>.js">line and add a topic chip in the header. - Add a key in
TOPICSinapp.js.
{
id: "unique-stable-id", // used for progress tracking
prompt: "What does X do?",
answer: "the canonical command",
accept: ["alt 1", "alt 2"], // optional, for a future typing mode
explain: "short why/how note", // optional, shown after answering
choices: ["distractor 1", ...], // optional, else auto-sampled for MC
tags: ["topic", "subtopic"],
level: 1 // 1 = beginner, 3 = advanced
}{
id: "ex-mkdir",
prompt: "Create a new directory called `projects`.",
hint: "...", // optional
answer: "mkdir projects", // shown via Show answer
context: "...", // optional, rendered above the terminal
initial: { fs, cwd?, env? }, // starting state, deep-cloned per attempt
expect: { // all must pass; check after every Enter
noError: true,
cwd: "/home/user/projects",
stdoutTrimEquals: "...",
stdoutContains: ["foo", "bar"],
exists: "/home/user/projects",
isDir: "/path", isFile: "/path",
missing: "/path/old.txt",
fileContent: { path: "/file.txt", equals: "...", contains: "..." },
},
tags: ["files"],
}Use the dir({...}) and file("...") helpers in data/bash-exercises.js to build the initial filesystem.
- More topics: git, python, sql.