ESP32-S3 Bench Guide
ESP32-S3 N16R8 bench guide: live pinout, lessons, simulators and the bench log.
翻译准备中
尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证Here you can learn programming.
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
Learn programming languages from Zero to Senior, with interactive lessons, exercises and projects.
See ROADMAP.md for the full plan, stack and development phases.
Requires Node.js 24 (see .nvmrc).
Open http://localhost:3000.
Sign-in uses Better Auth with GitHub and Google, and data lives in
Neon Postgres via Drizzle ORM. Until DATABASE_URL and
BETTER_AUTH_SECRET are set, the site works normally and the sign-in page says
sign-in isn't switched on yet.查看完整 README ↗Learn programming languages from Zero to Senior, with interactive lessons, exercises and projects.
See ROADMAP.md for the full plan, stack and development phases.
Next.js 16 (App Router) · React 19 · TypeScript · Tailwind CSS v4 · shadcn/ui · Better Auth · Drizzle · Neon Postgres
Requires Node.js 24 (see .nvmrc).
nvm use
npm install
npm run dev
Open http://localhost:3000.
Sign-in uses Better Auth with GitHub and Google, and data lives in
Neon Postgres via Drizzle ORM. Until DATABASE_URL and
BETTER_AUTH_SECRET are set, the site works normally and the sign-in page says
sign-in isn't switched on yet.
.env.example to .env.local and fill it in (see the comments in the file).npm run db:migrateBETTER_AUTH_URL set to the live domain and
production OAuth callback URLs (https://<domain>/api/auth/callback/github and /google).XP rules live in src/lib/gamification.ts (lesson XP comes from each lesson's frontmatter;
exercises +10, quizzes answered right first time +5). The server validates every award
against the content and the database's unique index means each activity pays out once.
Schema changes: edit src/db/schema.ts, then npm run db:generate and npm run db:migrate.
Courses live in content/courses/<language>/:
content/courses/javascript/
course.yml # intro + 4 levels → modules (slug, title, description, project)
basics/ # one folder per module slug
01-hello-world.mdx # lessons, ordered by the number prefix
02-variables.mdx
Each lesson needs frontmatter:
---
title: Hello, World!
description: Write and run your very first line of JavaScript.
duration: 5 # minutes
xp: 10
---
Lessons can use these components without importing them:
| Component | Use |
|---|---|
<Callout type="note|tip|warning|danger" title="…"> | Highlighted box |
<CodeExample output="…"> + a code block | Code with the output it prints |
<Quiz question="…" options={[…]} answer={1} explanation="…" /> | Multiple-choice question (answer is 0-based) |
<Exercise title="…" starter={…} tests={[…]} expectedOutput={…}> with <Hint> and <Solution> | Practice task with an in-browser editor, Run and Check |
<TryIt html={…} code={…} /> | Live HTML + JavaScript demo the learner can edit |
<TryIt language="python" code={…} /> | Editable code to run, e.g. Python that draws a chart |
<TryIt language="react" code={…} /> | Live React component (renders into <div id="root">) |
<TryIt language="tsx" code={…} /> | The same in TypeScript, type-checked first |
Code blocks support titles and highlighted lines: ```js title="app.js" {2}.
Interactive exercises run in a Web Worker in the learner's browser. Checks are either
expectedOutput (exact printed lines) or tests, JavaScript expressions run after the
learner's code in the same scope, e.g. { name: "adds", check: "add(2, 3) === 5" };
__output holds the printed lines. Every exercise needs a <Solution> code block:
npm test verifies each solution passes and each starter doesn't.
Python exercises add language="python" and write their checks in Python
(e.g. "add(2, 3) == 5"); they run on Pyodide (Python 3.14),
loaded in the browser from jsDelivr and in tests from the pyodide package.
Packages the code imports (pandas, FastAPI, SQLAlchemy, pytest, matplotlib…) are
installed on first use. The browser has no threads, so the runner gives asyncio.run
a simple event loop and runs FastAPI's TestClient on it; plt.show() prints the chart
as an image. The code is saved as lesson.py, so pytest.main([__file__]) runs its
tests, and checks can call _panda_pytest() (counts of passed/failed tests) or
_panda_pytest(patch={"add": buggy}) to make sure the learner's tests catch a bug.
requests and httpx (sync and async) answer the practice API below from the browser
too, Beautiful Soup can scrape its HTML shop (/shop, /shop/<id>, /robots.txt), and
checks can read _panda_requests.
SQL exercises add language="sql" (```sql fences). They run on PostgreSQL 18 compiled to
WebAssembly (PGlite), served from public/vendor like the TypeScript
compiler. Every run starts from a fresh copy of the sample database in
src/lib/runner/sql-seed.ts (a shop, a company and a film catalogue), runs the statements
one by one and prints what psql would: aligned tables, command tags (INSERT 0 3), and
errors with the line and a caret. Checks are JavaScript (they may await) and see rows and
columns of the last result, results, query(sql), lastQuery and rerun(setupSql),
which changes the data and runs the learner's last query again, so hard-coded answers fail;
each check runs in a transaction that's rolled back afterwards (src/lib/runner/execute-sql.ts).
JavaScript can fetch the built-in practice API at https://api.pandadev.test
(/movies, /weather?city=, /recipes, /users, /posts, /todos with full CRUD,
/status/404, /delay/1500, /flaky, /offline; see src/lib/runner/fake-api.ts). It answers
after a fixed 100 ms with the same data every run, and never touches the network; checks
can read __requests (method, URL, headers and body of each request). Code can also
import { describe, it, expect, vi } from "vitest" (tests run after the code, like
vitest run, and print a report; checks read __vitest or call
await __retest([["a + b", "a - b"]]) to make sure the learner's tests catch a bug), and
import express from "express" / import request from "supertest" for an
Express-compatible server that tests call without a network (with res.cookie(),
cookie-parser, and request.agent(app), which keeps cookies like a browser).
import { WebSocketServer } from "ws" starts a WebSocket server on an in-memory network
for that run, and the global WebSocket (or the ws client) connects to it, e.g.
new WebSocket("ws://localhost:8080"); messages arrive asynchronously, one task each,
like a real connection (src/lib/runner/ws-shim.ts).
React exercises use language="react": JSX runs in the live preview with React 19
(bundled from node_modules by scripts/build-vendor.mjs, development build so learners
see React's warnings), on <div id="root"></div> unless html says otherwise. The same bundle brings the
WebSocket network, so one page can run a ws server and a React client together. Checks
can await __click("button"), await __type("input", "Mei") and await __settle() to
wait for renders and requests. To check a loading state without racing the response,
hold the practice API's answers: (__hold(), __type("input", "p"), await __release(await __waitFor(() => /* loading is shown */))).
TypeScript exercises add language="typescript". Code is type-checked first (strict) with
the real TypeScript compiler, which scripts/build-vendor.mjs copies from node_modules
into public/vendor (so the site serves it, not a CDN); code with type errors doesn't run,
so a starter with deliberate type errors makes a good "fix the types" task. What the code
may use depends on where it runs (src/lib/runner/typecheck.ts):
vitest, express,
supertest, cookie-parser, ws, http) with types shaped like the real packages'
(src/lib/runner/module-types.ts; Express infers route parameters from the path).html={…}, TypeScript is checked against the DOM library and runs in the preview.language="tsx" is React in TypeScript: checked with React's own types
(@types/react, vendored by scripts/build-vendor.mjs) and run like language="react".Checks run after the types are stripped, so they can't see types; to test type-level work,
let the starter fail type-checking, e.g. with // @ts-expect-error lines that must be
errors ("Unused '@ts-expect-error' directive" fails a too-loose type). npm test fails if
any TypeScript example or solution has a type error. To show an error in a lesson, use a
plain code block with a // ❌ Error: … comment.
DOM exercises add html={…}: the code runs against that page in a sandboxed iframe
with a live preview, and each check is evaluated in the page afterwards, in order, so
checks can click (document.querySelector("#add").click()) and then inspect the page.
<TryIt html={…} code={…} /> (closing /> on its own line) is an editable demo with
the same preview and no checks; npm test runs each one in jsdom to make sure it works.
Previews have an in-memory localStorage (the sandboxed page can't use the real one). The
site keeps its contents between runs, so pressing Run again behaves like reloading a page;
Reset clears it, and checks always start with empty storage.
Practice problems live in content/practice/<language>/NN-slug.mdx and appear at
/practice/<language>/<slug>: frontmatter title, description, difficulty (easy, medium,
hard: 10, 20 or 30 XP), topic (see src/lib/practice-meta.ts) and optionally a refresher
lesson, then the statement and exactly one <Exercise>. Translations sit next to them as
NN-slug.ru.mdx, like lessons.
Signed-in learners can save lessons and problems for later (the bookmark in the page
header, listed at /saved), continue where they left off (lesson and problem pages
record visits in page_visit; the navbar, dashboard and home page link to the last page
opened, or the one after it once it's finished; signed-out visitors get the same from
localStorage), and do a daily review at /review: quiz questions from finished lessons
come back on a spaced-repetition schedule (src/lib/review-schedule.ts, cards in
review_card), with XP once a day. Velite extracts each lesson's quizzes for it.
Code typed in exercise editors and the playground is kept in localStorage, and for
signed-in learners also in saved_code (saved a moment after typing stops), so it follows
them to other devices. Each copy carries the time of its last edit, and an editor opens with
whichever is newer (src/lib/code-sync.ts); a reset is saved too.
New accounts land on /welcome after their first sign-in (Better Auth's newUserCallbackURL):
a language, a starting level (0–2) and a daily goal (30, 50 or 100 XP), stored in
learner_profile. The dashboard uses the goal, "continue" starts them at that level's first
lesson, and the profile page links back to change them.
Every day has a problem of the day per language (src/lib/daily.ts: the same for
everyone, cycling through all problems before repeating); solving it that day pays a 20 XP
bonus once a day and builds a daily-problem streak. Streak freezes are earned for every 7
days in a row (up to 2, in streak_freeze) and cover missed days automatically when the
learner's data is next loaded.
Search (⌘K / Ctrl+K, /, or the navbar button) finds lessons, their sections and practice
problems by title, headings, description and the words in their inline code. The index is
built at build time, one static file per locale (/search/en.json, from
src/app/search/[file]/route.ts), and searched in the browser by src/lib/search.ts.
Each level ends with a capstone project. In course.yml a level's capstone is either a
title, or { slug, title, description } with its lessons ("parts") in
content/courses/<language>/<slug>/, listed after the level's modules.
The lesson URL is /learn/<language>/<slug> (the file name without its number).
npm run content validates everything: unknown modules, missing number prefixes and
duplicate slugs fail the build with a clear message. New languages must also be added to
src/lib/languages.ts.
The site is bilingual with next-intl: English at the plain URLs
(/learn/python/variables), Russian under /ru (/ru/learn/python/variables). Visitors
switch with the EN | RU toggle in the navbar; we don't redirect based on browser language.
src/app/[locale]/…. src/proxy.ts maps URLs to locales; links use
Link from @/i18n/navigation, which adds /ru automatically.messages/<locale>/<area>.json (areas listed in
src/i18n/namespaces.ts). Keys are type-checked against English, and npm test fails if
the Russian files are missing a key or a {placeholder}. Russian plurals use ICU
({count, plural, one {# урок} few {# урока} many {# уроков} other {# урока}}).NN-slug.ru.mdx, and course
outlines as course.ru.yml. A translation shares the lesson's slug, permalink and XP, so
progress is the same in every language. The build fails if a translation's exercise/quiz
counts, XP or duration differ from the English lesson, and npm test runs every
translated example and exercise just like the English ones. Lessons without a
translation fall back to English with a note.The site is hosted on Vercel and connected to this GitHub repo:
every push to main deploys to production, and other branches get preview deployments.
Vercel runs npm run build on Node 24 (Velite, then Next.js) and doesn't run the tests
itself: GitHub Actions (.github/workflows/ci.yml) checks formatting, lint, types and
tests, and solves every exercise in Chrome, on every push and pull request. main is
protected, so code only reaches it through a pull request whose checks all pass.
Production environment variables (Vercel → Project → Settings → Environment Variables):
| Variable | Value |
|---|---|
DATABASE_URL | Neon connection string |
BETTER_AUTH_SECRET | Its own random secret (openssl rand -base64 32), not the local one |
BETTER_AUTH_URL | The production URL, e.g. https://pandadev.vercel.app |
GITHUB_CLIENT_ID / GITHUB_CLIENT_SECRET | A separate GitHub OAuth app whose callback is <url>/api/auth/callback/github |
NEXT_PUBLIC_SENTRY_DSN | Optional: turns on Sentry error reports (browser and server) |
SENTRY_AUTH_TOKEN, SENTRY_ORG, SENTRY_PROJECT | Optional: upload source maps so Sentry shows real code lines |
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET | Optional, same idea with callback <url>/api/auth/callback/google |
Without the database or auth variables the site still works, just without sign-in and saved progress.
In production a service worker (public/sw.js) keeps Python, PostgreSQL, the TypeScript
compiler, React and the site's scripts after their first download, so the editor starts
instantly on later visits, and keeps visited lessons and practice problems for offline use. Printed values match Node's
console.log, including line breaking and promises (Promise { <pending> }).
| Command | What it does |
|---|---|
npm run dev | Start the dev server (and Velite in watch mode, in its own process) |
npm run build | Production build |
npm run start | Serve the production build |
npm run lint | ESLint |
npm run typecheck | TypeScript type check |
npm run format | Format all files with Prettier |
npm run format:check | Check formatting |
npm run test:e2e | Solve every exercise in Chrome against a running site (npm start) |
npm run content | Build and validate course content |
npm run db:generate | Create a migration from schema changes |
npm run db:migrate | Apply migrations to the database |
npm run db:studio | Browse the database in Drizzle Studio |