Skip to content

Commit f81ffb1

Browse files
feat: port to TypeScript/Vite and add plotting surface
Migrate the engine, UI, and tests from vanilla ES modules under js/ to strict TypeScript under src/, bundled by Vite and tested with vitest. Removes the old js/ tree, css/app.css, and the scripts/serve.js static server; adds tsconfig, vite config, lockfile, and a GitHub Pages deploy workflow. Adds a Plot surface: scatter(xs, ys, "title") / line(xs, ys, "title") push a plot spec rendered as SVG on a Plot tab alongside the Memory canvas, so the object graph and the chart read the same data. Fixes: - plot title used the repr form (displayValue) instead of the print form, so line(..., "trend") titled the chart 'trend'; use printArg - Tab completion suggested sorted() and list(range(...)), which the engine does not implement and would raise NameError Docs: - rewrite README and DESIGN for the TS/Vite layout, supported subset, meta-commands, and the Plot surface - align the ADR 001 title and engine header comments to the learn-python product name Co-Authored-By: Claude Code <noreply@anthropic.com>
1 parent 3a0219f commit f81ffb1

40 files changed

Lines changed: 6631 additions & 2161 deletions

‎.claude/launch.json‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"version": "0.0.1",
3+
"configurations": [
4+
{
5+
"name": "learn-python",
6+
"runtimeExecutable": "npm",
7+
"runtimeArgs": ["run", "dev"],
8+
"port": 5173
9+
}
10+
]
11+
}

‎.github/workflows/deploy-pages.yml‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
name: Deploy to GitHub Pages
2+
3+
on:
4+
push:
5+
branches: [main]
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: read
10+
pages: write
11+
id-token: write
12+
13+
concurrency:
14+
group: pages
15+
cancel-in-progress: false
16+
17+
jobs:
18+
build:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
- name: Setup Node
24+
uses: actions/setup-node@v4
25+
with:
26+
node-version: 22
27+
cache: npm
28+
- name: Install dependencies
29+
run: npm ci
30+
- name: Test
31+
run: npm test
32+
- name: Build
33+
run: npm run build
34+
- name: Upload Pages artifact
35+
uses: actions/upload-pages-artifact@v3
36+
with:
37+
path: dist
38+
39+
deploy:
40+
needs: build
41+
runs-on: ubuntu-latest
42+
environment:
43+
name: github-pages
44+
url: ${{ steps.deployment.outputs.page_url }}
45+
steps:
46+
- name: Deploy to GitHub Pages
47+
id: deployment
48+
uses: actions/deploy-pages@v4

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
node_modules/
2+
dist/
23
output/
34
.playwright-cli/
45
.DS_Store

‎DESIGN.md‎

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -25,23 +25,24 @@ Supported subset (deliberately small, pedagogically sharp):
2525
- `list`, `dict`, `tuple`, `set`, indexing, slicing, `.append` / `.pop` / `.update`
2626
- Function `def` / call / `return`, local frames, nested calls
2727
- `print`, `type`, `id`, `len`, `is`, `==`, arithmetic, comparisons
28-
- Meta: `help`, `levels`, `level`, `goal`, `hint`, `undo`, `reset`, `hint`, `golf`
28+
- Plotting: `scatter(xs, ys, "title")` / `line(xs, ys, "title")` → SVG board
29+
- Meta: `help`, `levels`, `level`, `goal`, `hint`, `solution`, `undo`, `reset`, `golf`, `script`
2930

30-
Out of scope v0: classes/OOP, imports, exceptions (except parse/runtime errors shown cleanly), comprehensions beyond simple cases, I/O, async.
31+
Out of scope v0: classes/OOP, imports, exceptions (except parse/runtime errors shown cleanly), comprehensions beyond simple cases, I/O, async, `range`/`sorted`/`min`/`max`/`abs`.
3132

3233
## Architecture
3334

3435
```
35-
js/engine/ simulated Python runtime (heap, frames, parser, evaluator)
36-
js/viz/ SVG canvas: stack frames → heap objects → reference edges
37-
js/levels/ level pack + memoryCompare (goal checker) + golf
38-
js/shell/ command line, history, undo stack, dialogs
39-
index.html app shell
40-
css/app.css design tokens + layout
41-
tests/ engine + compare unit tests (node --test)
36+
src/engine/ simulated Python runtime (tokenizer, parser, evaluator, memory,
37+
session) + goal checks (checks.ts) — the TreeCompare analogue
38+
src/levels/ 6-series / 24-level catalog + per-level goals, par, solutions
39+
src/ui/ app shell, memory canvas, plot board, REPL, dialog, script editor
40+
src/style.css design tokens + layout
41+
index.html app shell entry
42+
tests/ engine + compare + level-solution unit tests (vitest)
4243
```
4344

44-
Mirrors LGB's separation: `git engine` / `visuals` / `levels` / `command line`.
45+
Mirrors LGB's separation: `engine` / `visuals` / `levels` / `command line`.
4546

4647
### Memory snapshot (the "tree" of this game)
4748

@@ -91,12 +92,12 @@ Scale: 11 / 12 / 14 / 16 / 20 / 28 / 40. Line length in the brief ≤ 62ch.
9192

9293
```
9394
┌──────────────────────────────────────────────────────────┐
94-
│ learn-python sandbox · levels · undo · reset golf 3 │
95+
│ learn-python levels · lesson · hint · solution · undo │
9596
├───────────────────────────────┬──────────────────────────┤
96-
│ │ LEVEL BRIEF (paper) │
97-
│ MEMORY CANVAS │ title · goal · hint │
98-
│ [stack frames] → [heap] │ target mini-canvas │
99-
│ │ par / your score │
97+
│ [Memory] [Plot] │ LEARNING GUIDE (paper) │
98+
│ CANVAS │ title · brief · hint │
99+
│ [stack frames] → [heap] │ par / your score │
100+
│ (or SVG scatter / line) │ next-step hint │
100101
├───────────────────────────────┴──────────────────────────┤
101102
│ >>> statement | meta | multi-line … │
102103
└──────────────────────────────────────────────────────────┘
@@ -110,6 +111,7 @@ Scale: 11 / 12 / 14 / 16 / 20 / 28 / 40. Line length in the brief ≤ 62ch.
110111

111112
1. **Reference draw** — assignment draws an amber edge from name → object with stroke-dash animation.
112113
2. **Alias pulse** — when a shared mutable object changes, every inbound edge pulses once together.
114+
3. **Data-to-chart** — `scatter`/`line` reads the same heap lists the Memory canvas shows and draws them as SVG on the Plot tab, so the object graph and the chart agree.
113115

114116
### Motion
115117

@@ -126,12 +128,13 @@ Scale: 11 / 12 / 14 / 16 / 20 / 28 / 40. Line length in the brief ≤ 62ch.
126128
| goal tree compare | goal snapshot / predicate compare |
127129
| command golf | statement golf |
128130
| `undo` / `reset` | `undo` / `reset` |
129-
| goal dialog | paper brief + target mini-canvas |
130-
| import / build level (later)| level JSON (v0: static pack) |
131+
| goal dialog | paper brief + learning guide panel|
132+
| (no analogue) | Plot tab: data → SVG chart |
133+
| import / build level (later)| level TS catalog (v0: static) |
131134

132135
## Engineering standards
133136

134137
- Files, code, comments, Markdown: English.
135-
- Python-sim engine in TypeScript-free ES modules with full JSDoc (`Args`, `Returns`, `Throws`).
136-
- Unit tests for parser, evaluator, memory compare — `node --test`.
138+
- Engine and UI in **TypeScript** (strict), bundled by **Vite**.
139+
- Unit tests for parser, evaluator, memory compare, and level solutions — **vitest** (`npm test`).
137140
- No AI footprint in repo content.

‎README.md‎

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,62 +4,92 @@ Interactive Python **memory model** visualizer, sandbox, and challenge levels.
44

55
**Live:** https://alisadeghiaghili.github.io/learn-python/
66

7-
Architectural sibling of [learnGitBranching](https://github.com/pcottle/learnGitBranching): a fully client-side simulator with a live canvas, command shell, goal-checked levels, and statement golf. Where LGB makes git's commit DAG visible, learn-python makes Python's stack/heap object graph visible.
7+
Architectural sibling of [learnGitBranching](https://github.com/pcottle/learnGitBranching): a fully client-side simulator with a live canvas, command shell, goal-checked levels, and statement golf. Where LGB makes git's commit DAG visible, learn-python makes Python's stack/heap object graph visible — and lets you watch it become a chart.
88

99
## Run
1010

1111
Open https://alisadeghiaghili.github.io/learn-python/ in a browser.
1212

13-
Locally, open `index.html` via a static server (ES modules need HTTP):
13+
Locally, use the Vite dev server (TypeScript ES modules need a bundler):
1414

1515
```bash
16-
node scripts/serve.js
16+
npm install
17+
npm run dev
1718
# → http://127.0.0.1:5173
1819
```
1920

2021
## Test
2122

2223
```bash
23-
npm test
24-
# node --test tests/engine.test.js tests/levels.test.js
24+
npm test # vitest run
25+
npm run build # type-check (tsc --noEmit) + production build to dist/
2526
```
2627

28+
## Layout
29+
30+
Two live surfaces sit side by side:
31+
32+
- **Memory** — stack frames on the left, heap objects on the right, amber reference edges between them. This is the core instrument.
33+
- **Plot** — `scatter(xs, ys)` and `line(xs, ys, "title")` push a plot spec that renders as SVG on this tab. The memory model and the chart read the same data, which is the pedagogical point: a plot is just a list of `(x, y)` pairs.
34+
35+
Plus a **console** REPL at the bottom (statement or meta-command) and a **learning guide** panel on the right with the level brief, par, and next hint.
36+
2737
## Sandbox
2838

2939
Type Python-subset statements. Meta-commands:
3040

3141
| Command | Effect |
3242
|---------|--------|
3343
| `help` | subset + meta overview |
34-
| `levels` | list challenge packs |
35-
| `level <id>` | load a level |
36-
| `goal` | show the brief |
44+
| `levels` | list the 24 levels / 6 series |
45+
| `level <id>` | load a level (e.g. `level first-name`) |
46+
| `lesson` | open the current level's lesson text |
47+
| `goal` / `guide` | focus the right-hand guide panel |
3748
| `hint` | level hint |
49+
| `solution` | reveal the solution |
3850
| `golf` | statements used vs par |
3951
| `undo` | undo last statement |
4052
| `reset` | reset level / sandbox |
4153
| `sandbox` | free-play mode |
54+
| `script` | toggle the multi-line script editor |
55+
| `clear` | clear the console |
56+
57+
## Supported Python (v0)
4258

43-
Supported Python (v0): names, assignment, `list` / `dict` / `tuple`, indexing, slicing, `.append` / `.pop` / `.copy` / `.update` / `.get`, functions with `return`, `print`, arithmetic, `is` / `==`, `type` / `len` / `id` / `str` / `int` / `bool` / `list` / `dict`.
59+
A deliberately small, pedagogically sharp subset — not CPython:
4460

45-
Not in v0: classes, imports, exceptions, comprehensions, I/O, async, full CPython semantics.
61+
- **Literals & types:** `int`, `float`, `str`, `bool`, `None`; `list`, `dict`, `tuple`, `set`
62+
- **Names:** assignment, rebinding, augmented assign, indexing, slicing
63+
- **Methods:** `.append` `.insert` `.extend` `.pop` `.remove` `.copy` `.get` `.update` `.keys` `.clear`
64+
- **Functions:** `def` / call / `return`, local frames, nested calls
65+
- **Builtins:** `print` `len` `type` `id` `str` `int` `bool` `list` `dict` `set`
66+
- **Plotting:** `scatter(xs, ys, "title")` `line(xs, ys, "title")`
67+
- **Operators:** arithmetic, comparisons, `is`, `==`
68+
69+
Not in v0: classes, imports, exceptions (beyond clean parse/runtime errors), comprehensions, I/O, async, `range`/`sorted`/`min`/`max`/`abs`, full CPython semantics.
4670

4771
## Architecture
4872

4973
```
50-
js/engine/ simulated runtime (tokenizer, parser, evaluator, memory)
51-
js/viz/ SVG stack frames → heap objects → reference edges
52-
js/levels/ level pack + goal compare (TreeCompare analogue)
53-
js/shell/ REPL, undo stack, level flow
54-
css/ design tokens
55-
tests/ node:test unit + level-solution tests
74+
src/engine/ simulated runtime (tokenizer, parser, evaluator, memory, session)
75+
+ goal checks (checks.ts) — the "TreeCompare" analogue
76+
src/levels/ 6-series / 24-level catalog + per-level goals, par, solutions
77+
src/ui/ app shell, memory canvas, plot board, REPL, dialog, script editor
78+
src/style.css design tokens + layout
79+
tests/ vitest unit + level-solution tests
5680
```
5781

82+
Mirrors LGB's separation: `engine` / `visuals` / `levels` / `command line`.
83+
5884
The engine is intentionally a **teaching subset**, not CPython. Every state transition is controlled so the visualizer can show what a real interpreter hides.
5985

6086
## Levels
6187

62-
Four packs — Bindings, Aliasing, Containers, Frames. Each level has a brief (lab-note card), optional hint, a goal predicate/snapshot, and a statement-par for golf.
88+
Six series — Names & Bindings, Aliasing & Copy, Containers in Memory, Mutation & Methods, Functions & Frames, Plotting & Capstone. Each of the 24 levels has a brief, optional hint, a goal (predicate or target snapshot), a statement-par for golf, and a worked solution.
89+
90+
## Tech
91+
92+
TypeScript, Vite, Vitest. No backend, no runtime dependency — the "interpreter" is a hand-written subset whose entire memory graph is inspectable in the browser.
6393

6494
## License
6595

0 commit comments

Comments
 (0)