ESP32-S3 Bench Guide
ESP32-S3 N16R8 bench guide: live pinout, lessons, simulators and the bench log.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證製作者的介紹僅有上面的一句話。 更多詳情請閱讀儲存庫 README。 儲存庫 README ↗
正在載入完整 README。
檢視完整 README ↗Free printable math practice for roughly 3rd–5th grade — word problems, logic puzzles, and arithmetic drills, each one page per kid plus a worked answer key.
The site also has step-through animations of the written methods — long division and
multiplication, one pencil mark at a time, with the trap called out at the step where it
actually bites. This repo is the generator behind it all: self-contained HTML, no
dependencies, python3 and a browser.
Two things here are unusual and worth the thirty seconds:
drill_cost.py
computes.--layout plain gives the same problems with blank
space, for when the method is solid and you want it the way a test would ask.One step. Copy the example config and put your own names in it:
cp kids.example.json kids.local.json
$EDITOR kids.local.json
{
"kids": [
{ "id": "kid1", "name": "Amira", "grade": 3 },
{ "id": "kid2", "name": "Idris", "grade": 4 }
]
}
That's it — generate a sheet and the names are on it.
kids.local.json is gitignored. kids.example.json is not. Committed code refers to
children by id (kid1, kid2) and never by name; the name is read at render time and
appears only in the printed Name: field. So you can share, fork, or publish the repo
without shipping your family with it.
If you skip this step nothing breaks — the generator falls back to the example file and prints a loud notice. Sheets will say "Kid One". That's deliberate: a silent fallback would hand you a stack of paper addressed to nobody.
ids are the contract. The drill plans in drill_gen.py are keyed on kid1 and kid2:
PLANS = {
"div": [("kid1", (2, 1), "2-digit ÷ 1-digit, with a remainder", "div_2d_1"),
("kid2", (3, 1), "3-digit ÷ 1-digit, with a remainder", "div_3d_1")],
...
}
Add a kid3 to your config and a matching row there. The digit shapes (2, 1) mean
2-digit dividend ÷ 1-digit divisor; the last field picks the time model from
drill_cost.py.
Being straight about it, because a half-private repo is worse than a known-public one. This repo is public, and it was scrubbed deliberately before it was published:
| ✅ All code | keyed on kid1/kid2 ids, no names |
✅ private/ and kids.local.json | gitignored — the practice plan, results log, and any per-child notes live there |
| ✅ Generated sheets | gitignored; rebuilt from a seed |
✅ Every Name: header field | blank — the child writes it |
| ✅ Git history and commit messages | rewritten with git-filter-repo; no names, no school, no per-child records |
| ℹ️ Story characters | The word problems and logic puzzles are cast with Muslim names — Idris, Hamza, Bilal, Amina, Zayd, Tariq and others. Those are characters, kept on purpose: the puzzle answers reference them by name. Nothing indicates whose repo it is. |
If you fork this for your own kids, kids.local.json is the only file that ever holds a
real name, and it is gitignored from the start.
A full day is three sheets per kid: word problems, logic, and a drill.
# drills — generated, sized to five minutes
python3 drill_gen.py --skill div --seed $(date +%Y%m%d) # or --skill mul
python3 drill_gen.py --skill zeros --stage 1 # kid1 Noetic prep: 2-minute trailing-zero probe (stages 1|2|3|mix)
python3 verify_drills.py # must exit 0
./print-worksheet.sh worksheet-division-drill.html --dry-run
# word problems / logic — pick the day's sheet from PRACTICE-PLAN-2026.md
python3 build_focus.py && python3 verify_focus.py # Noetic-prep focus-track word sheets (one kid per spec; outputs gitignored)
python3 build_fracmul.py && python3 verify_fracmul.py # kid2 fraction packet: 10 multiply + 10 add/subtract, student + key files
./print-worksheet.sh worksheet-sailing-ships.html --date today
--budget 600 makes it a ten-minute sheet instead; the problem counts re-derive
themselves. --seed makes a sheet reproducible — same seed, same problems.
⚠️
print-worksheet.shandprint-drill.shrefuse to print ahead, print a batch, or reprint a day that already exists. That'sday-guard.sh, and it is deliberate. A genuine replacement goes through--override-day-guard, which is loud and logged.
| File | What |
|---|---|
drill_gen.py | generates division/multiplication drills, sized to a time budget |
drill_cost.py | the time model — marks per problem → seconds → problems per sheet |
verify_drills.py | audits the rendered HTML independently. Run before printing |
build_sheets.py | generates the word-problem and logic sheets from specs_*.py |
verify_sheets.py | re-derives every word-problem answer. Must exit 0 |
build_focus.py / specs_focus.py / verify_focus.py | one-kid Noetic-prep focus sheets; student sheet and key are separate files. The verifier finds each answer by brute force and must exit 0 |
build_fracmul.py / specs_fracmul.py / verify_fracmul.py | kid2's 20-problem fraction packet (10 multiply, 10 add/subtract), student and key files. The verifier recomputes every answer with Fraction and must exit 0 |
print-worksheet.sh | render to a clean PDF and print |
print-drill.sh | same, for an external drill PDF |
day-guard.sh | the one-day-at-a-time print guard |
test-day-guard.sh | unit tests for the guard's logic — calls guard_one_day directly |
test-print-path.sh | end-to-end test of the whole print path, via a stub lp. Catches what the unit tests structurally cannot |
animations/ | step-through animations of the written methods |
AGENTS.md | the real documentation — rules, difficulty pin, hard-won lessons |
DRILLS.md | external drill sources (fallback) |
KUMON.md | the Kumon sample packets — what's in them, and how long a page is supposed to take |
kumon_cost.py | prices each Kumon page with the drill_cost.py model, against Kumon's own 15–30 min |
AGENTS.md is the file to read before changing anything. It carries the rules that
have already decayed once and been reinstated — why drills are one day at a time, why the
work has to be shown, and why a doc that says "never" needs its date checked.
A scrubbed subset of this repo is published as a free printable-worksheet site. It is a
separate Cloudflare Pages project (sifxtreme-math) from the blog, on purpose: a bad
math deploy can then never touch sifxtreme.com.
python3 build_site.py # renders site/ from the SHEETS allow-list
python3 verify_public.py # MUST exit 0 — refuses to publish if anything private survived
export CLOUDFLARE_API_TOKEN=$(grep ^CLOUDFLARE_API_TOKEN= ~/code/experiments/cloudflare-cli/.env | cut -d= -f2-)
npx wrangler pages deploy site --project-name sifxtreme-math --branch master
⚠️ If the token looks dead, check with cf, not curl. This site shares its
credential with ../typing/. A cfat_ token is an account token and returns
Invalid API Token from /user/tokens/verify — the user endpoint — however
healthy it is; wrangler misleads identically by failing on /accounts. On
2026-08-10 that cost an hour and an invented expiry story for a token that was alive
and merely lacked Pages permission. ../../cloudflare-cli/cf whoami reports it
correctly. Full write-up: ../typing/AGENTS.md § Deploying.
⚠️ Verify by grepping the live page, never by status code — Pages serves its fallback
with a 200, so an unpublished URL still looks fine:
curl -sL https://math.sifxtreme.com/ | grep -o '<title>[^<]*</title>'
What makes a sheet publishable: the SHEETS allow-list in build_site.py. A new
worksheet is private until someone adds it — the safe default. verify_public.py is the
last line, not the only one, and it reads the terms it hunts from the gitignored
private/forbidden-terms.txt rather than hardcoding them.
Every problem count is currently a prediction. The model is anchored on one real measurement (49 problems of 3-digit subtraction in 13 minutes) and extrapolated from subtraction to division and multiplication.
To make it a measurement instead: time a real sheet, then
import drill_cost
drill_cost.calibrate(observed_sec=41.0, marks=15.0) # → the SEC_PER_MARK it implies
and update SEC_PER_MARK. Don't hand-adjust the problem counts — that breaks the
link between the model and reality, and then the numbers mean nothing.
SPEED.md | the published fluency benchmarks — what Kumon, Khan Academy and CBM each say, and the probe to run |
speed_check.py | scores a timed sheet in digits correct per minute against the CBM grade norms |
PRACTICE-PLAN-2026.md | the day-by-day schedule |
KHAN-MAP.md | where Khan Academy teaches and tests the algebraic-thinking skills (verified 2026-10-25) |