ESP32-S3 Bench Guide
ESP32-S3 N16R8 bench guide: live pinout, lessons, simulators and the bench log.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
GPU-powered interactive science simulations, running in the browser on WebGPU.
Built with Next.js 16 (App Router, Turbopack), React 19, Tailwind 4 and vgpu.
The catalog in src/lib/subjects.ts lists many more planned simulations (marked "Coming Soon").
See docs/ROADMAP.md for the improvement plan.
You need a browser with WebGPU (recent Chrome, Edge or Safari). Without it, simulation pages show an
explanatory message instead of a blank canvas.檢視完整 README ↗GPU-powered interactive science simulations, running in the browser on WebGPU. Built with Next.js 16 (App Router, Turbopack), React 19, Tailwind 4 and vgpu.
| Simulation | Subject | GPU technique |
|---|---|---|
| Wave Interference & Diffraction | Physics | Fragment shader; Huygens–Fresnel slits as phasor sums |
| N-Body Orbital Mechanics | Physics | Tiled all-pairs gravity compute shader (up to 16 384 bodies), leapfrog integrator, instanced rendering |
| Double Pendulum Chaos | Physics | One RK4 compute kernel for every view: a 32-bit GPU crowd of up to 10 000 pendulums against a 64-bit CPU pair, and a flip-time fractal of up to 1024² pendulums (one per pixel) |
| Axons & Nerves | Biology | Hodgkin–Huxley cables, one GPU invocation per fibre solving its tridiagonal system implicitly (Thomas algorithm); a nerve of up to 1 000 fibres and its compound action potential |
| Hodgkin–Huxley Neuron | Biology | Compute shader integrates the ODEs; fragment shader plots the traces |
| Cellular Automata | Computer Science | Ping-pong compute shader over grids up to 2048²; a reduction shader counts and fingerprints every generation; pan/zoom renderer |
| How AI Learns | Computer Science | A neural network trained on the GPU: forward, backpropagation, gradient and momentum-SGD kernels over the whole mini-batch (deterministic, no atomics); a live decision map and every neuron's own map; real handwritten digits (MNIST) with a draw pad |
The catalog in src/lib/subjects.ts lists many more planned simulations (marked "Coming Soon").
See docs/ROADMAP.md for the improvement plan.
pnpm install
pnpm dev # http://localhost:3000
You need a browser with WebGPU (recent Chrome, Edge or Safari). Without it, simulation pages show an explanatory message instead of a blank canvas.
This repo uses a newer Next.js than most training data covers — see
AGENTS.mdand readnode_modules/next/dist/docs/before changing framework-level code.
| Command | What it does |
|---|---|
pnpm lint | ESLint |
pnpm typecheck | next typegen (route types) + tsc --noEmit |
pnpm test | Vitest: pure logic and headless-GPU tests of every shader |
pnpm check:wgsl | Validates every .wgsl file against a real WebGPU device (next build does not) |
pnpm build | Production build (all simulation routes are statically generated) |
pnpm smoke | Browser smoke test of a running server (BASE_URL=http://localhost:3000) |
pnpm e2e | Full browser suite (86 scenarios: every sim, URL state, measurement tools, challenges, shortcuts, no-WebGPU, phone) against BASE_URL. Works on pnpm start, pnpm dev with E2E_DEV=1 (React strict mode; skips size budgets) and a static export. E2E_GREP=<regex> runs only the scenarios whose name matches |
pnpm smoke:local | Builds, serves on a spare port, runs the smoke test, stops the server |
pnpm export | Fully static offline build in out/ — serve with any static file server, no Node or internet |
pnpm verify | lint → typecheck → test → check:wgsl → build |
pnpm install enables .githooks/pre-push, which runs pnpm verify before every push so a broken build
never reaches GitHub (GitHub Actions may be unavailable). Bypass in an emergency with git push --no-verify.
pnpm test and pnpm check:wgsl need a WebGPU adapter. On a machine without one (containers, CI):
npx vgpu install-software-renderer # one-off: downloads a CPU Vulkan renderer
REQUIRE_GPU=1 pnpm test # REQUIRE_GPU makes a missing adapter a failure instead of a skip
src/
app/
page.tsx landing page, grouped by subject
[subject]/[sim]/page.tsx the single simulation route (generateStaticParams, 404 for the rest)
components/ SimLayout, ParameterSlider, SimCard, GpuStatusOverlay
lib/
subjects.ts simulation catalog (single source of truth)
gpu/runtime.ts WebGPU lifecycle: init, surface, clock, safe teardown
gpu/useGpuSim.ts React hook wrapping the runtime
simulations/
loaders.tsx sim id -> lazily loaded, client-only component
<subject>/<sim>/
sim.ts creates the GPU resources and the frame loop; returns a handle
controls.tsx React UI built on SimLayout + useGpuSim
*.wgsl shaders, loaded through vgpu's bundler loader
usePersistedParams(simId, schema, defaults) keeps settings in the URL (and, as a fallback,
localStorage). Schemas in lib/urlState.ts clamp/validate everything, so a bad link can't break a sim.SimLayout: copy link, save image, reset to defaults, keyboard shortcuts (Space, ., R, ?) and an
optional Challenges tab. On phones the sidebar is a bottom drawer (peek / half / full) with Play always in reach.summary to SimLayout (one sentence on what the canvas shows, announced through a
throttled polite live region), use usePlaying(sim, autoplay) so a sim starts paused under reduced motion,
and keep every simulation page clean in the axe audit (pnpm e2e checks desktop and phone).lib/gestures.ts turns two-finger input into pan and pinch-zoom steps; canvases with a view (Cellular
Automata, N-body) apply them, and keep one finger for their own tool.lib/challenges.ts format (predict → set up → goal check → explanation), rendered by
ChallengesPanel. See challenges.ts next to each simulation. Each has a test that its setup does not already
solve it, that the intended answer does, and that obvious shortcuts do not.wave.ts, hh.ts, life.ts) used for graphs,
readouts and tests, and a GPU test proving the two agree. MiniChart is a small SVG chart for readouts like the
firing-rate curve and the population graph.gravity.wgsl sums softened gravity over all pairs in 64-body tiles of workgroup memory, integrate.wgsl
does leapfrog (or Euler, for the numerics lesson). engine.ts is the GPU physics without drawing, shared by the sim
and the GPU tests; renderer.ts copies positions into vertex buffers (vertex shaders may not read storage buffers
on compatibility-mode devices) and draws instanced discs and fading trails. Energies, orbital elements and measured
periods come from small read-backs, sampled every ≤ 16 steps so fast planets are never aliased. The orbit lab's
units are AU, years and solar masses (G = 4π²), so Earth's period is exactly 1 year.pendulum.ts is the 64-bit twin (equations of motion, RK4/Euler, energy, flips, the energy
boundary, normal modes, the spread and its growth rate λ); turns states into readouts, shared by the sim
and the challenge tests. The Pendulum view and the measured Butterfly pair are integrated on the CPU in 64-bit (two
pendulums cost nothing, and 32-bit floats cannot even store a 10⁻⁹ rad nudge near 2 rad), and only drawn by the GPU;
the Butterfly crowd ( keeps its 32-bit starts distinct) and the Fractal run on the GPU.
The fractal is seeded on the GPU (), coloured by straight from the flip-time buffer, and
the cursor readout copies out a single pixel instead of reading the map back.A compact editorial layout (about one screen on a desktop, 1.35 on a phone): numbered plates for the working
simulations (one row that scrolls sideways with snap: four at a time on a desktop, a swipe on a phone) and a typographic index of the planned ones. Design tokens (colours, type scale, motion) live in
src/app/globals.css; components in src/components/home/. The plan and measurements are in
docs/HOMEPAGE-PLAN.md.
pnpm posters builds, serves, drives
each simulation from fixed settings, reads only the canvas pixels, and writes public/plates/<id>.webp plus the
social-preview image src/app/opengraph-image.jpg. Re-run it after changing how a simulation looks.simulations/previews.ts, loaded only then). Rules, in components/home/intent.ts: one live plate at a time;
never on touch, with prefers-reduced-motion or without WebGPU; stops when scrolled out of view or the tab is
hidden; a GPU failure leaves the poster. The home page uses no GPU until the visitor shows intent.pnpm e2e): ≤ 1.15 screens tall on desktop, ≤ 1.4 on a phone, no horizontal overflow,
JavaScript ≤ 470 KB (the React + Next runtime is ~457 KB of that), HTML ≤ 14 KB gzipped, zero axe violations.Simulations run through a paced render loop (ctx.loop): it skips ticks while the GPU is still busy, so a slow
device never builds a backlog (Pause/sliders stay responsive), and a governor (lib/gpu/pacing.ts) lowers the
canvas resolution — down to 35% — when frames cost too much, raising it again only when the predicted cost fits.
A badge shows when resolution is reduced. To pin full resolution (projector, screenshots), run
localStorage.setItem("edusim:quality", "full") in the browser console.
src/simulations/<subject>/<id>/ with *.wgsl, sim.ts (a SimFactory that returns a handle with
dispose()), and controls.tsx (default export; use useGpuSim(factory) and SimLayout).implemented: true for it in src/lib/subjects.ts, with a tagline and posterAlt.src/simulations/loaders.tsx and add its home-page preview to src/simulations/previews.ts.pnpm posters to generate its plate poster (add its capture settings to scripts/make-posters.mjs).src/lib/subjects.test.ts fails if the catalog and the loaders disagree. Put pure logic in its own module
(see hh.ts, rules.ts) so it can be unit-tested, and add a headless-GPU test for any new shader in
src/simulations/gpu-shaders.test.ts.
launchSim / useGpuSim. Teardown must be synchronous and
safe at any point, which is what makes React strict mode (double mount) leak-free.frameDelta(ctx.clock)), never a fixed per-frame increment, so speed does not
depend on the display refresh rate.set(): the first call for a struct must include every member; later calls may send a subset.meta; pnpm check:wgsl will tell you.measure.tscrowdAnglespendulum.wgslseed.wgslfractal.wgslcable.ts is the 64-bit twin: HH membranes (shared with the neuron sim) joined into
compartments, a bare axon in equal compartments or a myelinated one as nodes of Ranvier and internodes (myelin
thickness ∝ diameter, nodes ~1 µm: Rushton's similarity, so speed ∝ diameter). Each step relaxes the gates, then
solves the voltages implicitly along the fibre (conductances linearised, Thomas algorithm): an explicit step would
need Δt < 0.004 ms for the squid axon. cable.wgsl runs one fibre per invocation for many steps per dispatch and
writes the kymograph, two electrode traces and each fibre's extracellular signal into one output buffer (four
storage buffers in all, within compatibility-mode limits); cap.wgsl sums the signals into the compound action
potential. Tested: HH 1952's 18.8 m/s (within 2 %), √d for bare and ∝ d for myelinated fibres, annihilation,
refractoriness, TTX/lidocaine and demyelination block, heat block.net.ts is the 64-bit twin (layout, activations, cross-entropy, backpropagation checked against
centred finite differences, momentum SGD with L2, seeded initialisation, the datasets and the batch order, the step
probe). mlp.wgsl trains one mini-batch step as a fixed sequence of dispatches (a forward pass per hidden layer, the
output layer with its softmax or sigmoid, a backward pass per hidden layer, one gradient and one update over every
parameter); every sum runs in a fixed order, so 20 GPU steps match 20 twin steps on the same batches. eval.wgsl
evaluates thousands of samples at once in private memory, also along the last step (w + (s − 1)·(−η·v), which is the
step probe); boundary.wgsl computes the decision map and each hidden neuron's map into a buffer that
playground.wgsl draws; the weights reach links.wgsl as a vertex buffer copied layer by layer. The digits are a
10 000 + 2 000 subset of MNIST (Yann LeCun, Corinna Cortes, Christopher Burges; CC BY-SA 3.0), built by
scripts/build-digits.mjs into public/data/mnist-12k.dat (gzip, 1.9 MB) and stored on the GPU four pixels per word.count.wgsl reduces the grid to a live-cell count and an order-independent
fingerprint every generation (into a 1024-slot ring buffer); sim.ts reads it back at most every 100 ms and
tracker.ts classifies the history (extinct / still life / oscillator with period / moving pattern). It only runs
when a host passes onStats, so the home-page preview pays nothing. A shared link reproduces the rules, grid,
speed, colours and the starting pattern (a library pattern, random soup or empty grid) — not hand-drawn cells.