ESP32-S3 Bench Guide
ESP32‑S3 N16R8 벤치 가이드: 실시간 핀아웃, 강의, 시뮬레이터 및 벤치 로그
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기메이커가 쓴 소개는 위의 한 줄이 전부입니다. 더 자세한 내용은 저장소 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) |