English · 中文
Draw a circuit on white graph paper and get the same drawing three ways — a
kirchhoff-ir/1.0 JSON netlist, publication-grade
circuitikz TikZ, and a standalone SVG — with zero LaTeX required to draw or
export. Click Preview to compile a real PDF/PNG through your local TeX Live.
kirchhoff-eye reads circuits from photos; kirchhoff-paper is the human-drawing counterpart. They share one IR and one serialization toolchain — so the editor also opens kirchhoff-eye's
ir.jsonoutput and doubles as its visual repair tool.
The editor renders an instant, self-contained SVG (left). Hit Preview and the same IR is serialized to circuitikz and compiled with LaTeX (right) — pixel-for-pixel the figure you'd put in a paper. Both come from one document; nothing is redrawn by hand.
| In the editor — instant SVG | Preview — circuitikz → PDF | |
|---|---|---|
| → | ![]() |
The TikZ is emitted verbatim by the vendored ir2tikz — commented and sectioned, ready
to paste:
%% ==== [region] input-coupling ====
\coordinate (N_B) at (3,4);
\draw (1,4) to[R, l=$R_1$, a=$10\mathrm{k}\Omega$, name=R1] (3,4);
\draw (3,4) to[C, l=$C_1$, a=$100\mathrm{nF}$, name=C1] (3,2);
\node[ground] at (3,2) {};
%% ==== [region] amplifier ====
\node[npn] (Q1) at (5,4) {};
\draw (5,6) to[R, l_=$R_C$, a^=$2\mathrm{k}\Omega$, name=R2] (5,7.5);
\node[vcc] at (5,7.5) {};- 🧲 Draw like an engineer. Snap-to-grid placement, orthogonal L-shaped wire routing, magnetic junctions, and drag-a-part-onto-the-canvas — the whole 26-component × 2-flavor (American / European) library rendered by real circuitikz.
- 🔌 Real netlist inference. A union-find pass replicates the vendored
irlibexactly — same 1e-3 quantization, wire-adjacency, and power-rail unioning — so nets are named and back-filled the way the machine-vision side would infer them. - 📤 Three outputs, one source.
ir.json(round-trips losslessly), sectioned TikZ, and a self-contained SVG. Editing and TikZ/SVG export need no TeX Live at all. - 🖨️ True preview. Local
pdflatex+pdftoppmcompile the actual figure; the TeX Live path is configurable in Settings (never hardcoded). - ↩️ Editor essentials. Undo/redo, localStorage crash-recovery, live net-highlight on
hover, click-to-locate validation findings, current-direction arrows, and GSAP micro-motion
that respects
prefers-reduced-motion. - 🩹 Repair mode. Open any kirchhoff-eye
ir.jsonto visually inspect and fix it.
git clone https://github.com/Yoki-cmd/kirchhoff-paper.git
cd kirchhoff-paper
npm install && npm --prefix frontend install && pip install -r backend/requirements.txt
npm run dev # frontend → http://127.0.0.1:5600 · backend → 127.0.0.1:8000That's it — open the URL and start drawing. Preview additionally needs TeX Live
(pdflatex + pdftoppm) on your PATH or set in Settings; regenerating the symbol
library additionally needs dvisvgm. Everything else — drawing, validating, TikZ and SVG
export — runs with Node + Python only.
npm test # 235 unit/integration tests (vitest + pytest, incl. vendored sentinels)
npm run symbols # regenerate the circuitikz symbol library (needs LaTeX + dvisvgm)
npm run e2e # Playwright smoke (system Edge)flowchart LR
D["🖉 Draw on graph paper"] --> IR[("kirchhoff-ir/1.0<br/>netlist + geometry")]
IR -->|save| J["ir.json"]
IR -->|"ir2tikz.py"| T["TikZ (circuitikz)"]
IR -->|"export/svg.ts"| S["standalone SVG"]
IR -->|"validate_ir.py"| V["findings"]
T -->|"render.py · pdflatex"| P["PNG preview"]
classDef ir fill:#eaf1f8,stroke:#2f6fb0,color:#22252b;
class IR ir;
The frontend state is the IR document. The Python backend is a thin FastAPI shell that only ever invokes the vendored CLI as subprocesses — so the toolchain stays at zero diff from kirchhoff-eye and the two projects can never drift.
frontend/ Vite + React 18 + TypeScript editor
src/core/ pure logic (transform, geometry, routing, netlist, bbox, symbols) — heavily tested
src/export/ ir.json → standalone SVG
src/state/ zustand store = the IR + undo/redo + autosave
backend/ FastAPI thin shell (probe texlive · run validate / ir2tikz / render)
vendor/kirchhoff/ READ-ONLY vendored toolchain (+ its own test suite as a tripwire)
tools/ gen_symbols.py — build-time circuitikz → SVG symbol renderer
fixtures/ golden circuits shared with kirchhoff-eye
V select |
W wire |
N node (Tab = style) |
A arrow · T text |
R rotate 90° |
M mirror |
F flip polarity |
Del delete |
Ctrl+Z / Ctrl+Y undo/redo |
Space+drag pan |
scroll = zoom | ? this help |
Every drawing is a kirchhoff-ir/1.0 document — 11 required top-level keys spanning the
netlist and geometry, validated by the vendored validate_ir.py. Coordinates live on a
0.5 grid (origin bottom-left, +y up); two-terminal parts carry from/to, multi-terminal
parts carry at + rotate∈{0,90,180,270} + mirror, and an optional top-level arrows
adds current annotations. Because the schema is the contract, a saved file is portable
across kirchhoff-paper, kirchhoff-eye, and the CLI unchanged.
- Screen-space rendering. Symbols are placed with the exact
at + Mᵐⁱʳʳᵒʳ · R(rotate) · offsetpose formula fromirlib, in screen coordinates — so pin hotspots always match what circuitikz draws, and text is never mirrored. - Vendor red-line.
backend/vendor/kirchhoff/is read-only; improvements go upstream to kirchhoff-eye, whose test suite must stay green before re-vendoring (seePROVENANCE.md). - Anti-template UI. Engineering graph-paper aesthetic — two-level grid, a single drafting-blue accent, real depth, and motion that clarifies rather than decorates.
MIT © 2026 Zhanming Liang. The vendored kirchhoff-eye toolchain is the author's
own work, re-distributed here under the same terms.

