# Circuitcaster > Circuitcaster is a touch-first, dot-grid, AI-readable PCB (printed circuit board) > designer. You design footprints, schematics, and board layouts on a phone, > tablet, or computer, then export a machine-readable file that carries everything > a downstream tool — or an AI — needs to take the board all the way to > manufactured hardware. This file exists so that any AI agent can read it and > then help a human set up, drive, and get real boards made with Circuitcaster. > Tagline: "Cast circuits. Anywhere." If you are an AI reading this: you can fully understand and operate Circuitcaster from this document plus the self-describing JSON files the app exports. Every export embeds its own `_ai_briefing` and (for full projects) `_ai_edit_instructions`, so you never need external context. Your job is usually one of: 1. Help a beginner USE the app (explain what to tap, what a footprint is, etc.). 2. DRIVE the running app on the user's behalf via `window.CIRCUITCASTER` (see "Driving the running app" below) — introspect current state, discover every button/input, and dispatch actions programmatically. 3. GENERATE a project the user can import (produce JSON per the schema below). 4. EDIT a project the user exported and hand it back for reimport. 5. Take a completed export and walk the user through the KiCad -> Gerbers -> fab pipeline to get a physical board. ## Driving the running app (window.CIRCUITCASTER) Any modern browser-driving agent (Claude-in-Chrome, ChatGPT Operator/Atlas, Gemini in Chrome, Perplexity Comet) that lands on app.circuitcaster.com has `window.CIRCUITCASTER` available. It is a small, stable, machine-readable API that lets you inspect and drive the entire UI WITHOUT synthesizing touch events or guessing at DOM structure. First call `CIRCUITCASTER.help()` — it returns a briefing that documents every method + the current state. Methods: - `CIRCUITCASTER.getState()` — returns the current design state (level, pitch, board dimensions, component counts, selected pad/wire, which modal is open, workspace project name + library count). This is authoritative; the DOM is decoration around it. - `CIRCUITCASTER.getSchema()` — returns every driveable affordance in the live UI: `{name, kind, desc, visible, disabled, value?, options?}`. Names are stable kebab-case strings (element ids or explicit data-ai-name attributes). Only dispatch affordances where `visible === true` and `disabled === false`. - `CIRCUITCASTER.getActions()` — returns every semantic verb on `CIRCUITCASTER.actions.*` with its argument shape + description. These cover work that lives on the CANVAS rather than in DOM (adding pins, drawing wires between pads, placing components at exact mm coordinates). - `CIRCUITCASTER.dispatch(name, params?)` — invoke a DOM affordance. Buttons: no params. Selects: `{value: "..."}`. Text/number inputs: `{value: "..."}`. Checkboxes/radios: `{checked: true|false}`. Example: to open the parts Library, call `CIRCUITCASTER.dispatch("btn-library")`; to change the pitch to 2.54 mm, call `CIRCUITCASTER.dispatch("pitch-select", {value: "2.54"})`. - `CIRCUITCASTER.actions.*` — semantic verbs. PREFER OVER DISPATCH when a matching action exists — actions are typed, idempotent, and don't toggle. Highlights: - `actions.setLevel("footprint"|"wire"|"board")` — set app mode. (Prefer over `dispatch("btn-level")`, which is a toggle.) - `actions.setPitch(mm)`, `actions.setBoard(w_mm, h_mm)`, `actions.setShape("rect"|"circle")`, `actions.newFootprint()`. - `actions.rotate()` vs `actions.rotatePins("ccw"|"cw")` — IMPORTANT DISTINCTION for Level 1. `rotate()` spins the on-screen preview 90° but pin coordinates DO NOT move (this is a display flip only). `rotatePins()` physically rotates every pin and swaps board W<->H — this is what a user means when they say "rotate the footprint 90° counterclockwise." Always use `rotatePins` for real geometric rotation. - `actions.addPin(ix, iy)` — Level 1 only. Add a pin at dot-grid index [ix, iy]. World position is `ix*pitch, iy*pitch` (mm). - `actions.setBoardOutline({shape?, w_mm?, h_mm?, corner_radius_mm?})` — Level 3 board outline. Partial updates supported. - `actions.addMountingHole(x_mm, y_mm, dia_mm=3.2)`. - `actions.snapCornerHoles(dia_mm=3.2, inset_mm=4.5)` — auto-place 4 corner holes; auto-nudges any that would collide with pads. - `actions.moveComponent(id, x_mm, y_mm)` — id is 'cN' from `getState().wire.componentCount`. In board level moves the board position; in wire level moves the schematic position. - `actions.rotateComponent(id)` — rotates a placed component 90° CW; returns the new `rotation_deg` so the AI can confirm orientation. - `actions.setComponentRotation(id, degrees)` — set a placed component's rotation to an absolute angle (0/90/180/270). Prefer this over calling rotateComponent three times to reach 270°. - `actions.deleteComponent(id)`. - `actions.addWire({from:{cid,n}, to:{cid,n}, layer?='F.Cu'})` — one wire between two pads. Auto-generates a single Manhattan bend. - `CIRCUITCASTER.observe(cb)` — subscribe to state changes; returns an unsubscribe function. `cb` receives the same object as `getState()`. Recommended agent loop: 1. Read `/llms.txt` (this file) once on arrival. 2. Call `CIRCUITCASTER.help()` to get the API briefing + first state snapshot. 3. Call `CIRCUITCASTER.getSchema()` to see which affordances are live right now. Filter to `visible && !disabled` before offering choices to the user. 4. Dispatch actions on the user's behalf. Re-read schema after any dispatch that opens a modal or switches level, because the affordance set changes. 5. When teaching a human, translate schema affordances to natural language — the `desc` field on each entry is written for exactly this. ## Building a footprint from a chip name (datasheet-first, not datasheet-required) When a user names a specific chip ("ATtiny85", "PCM5102A", "SN74HC595") and asks for a footprint, PREFER working from a datasheet. Do not REQUIRE one — never block the user because they don't have one. Suggested flow: 1. Ask which physical package they want. Chips ship in many: ATtiny85 -> DIP-8 (through-hole) OR SOIC-8 OR MSOP-8 OR QFN-20. Same chip, very different footprints. Confirm before placing pins. 2. Politely OFFER to work from a datasheet: "If you have a datasheet URL or PDF page you'd like me to use, share it and I'll take dimensions and pinout from there. Otherwise I'll go by the standard package spec — usually fine for common families (DIP, SOIC, TSSOP, QFN, SIP, JST-XH, screw terminals, headers)." If the user provides one, use it as ground truth and cite the page/table for any dimension or pin name. If not, proceed without asking again. 3. Fall back gracefully when no datasheet is provided. Standard package names carry standard geometry (JEDEC / JEITA / manufacturer standards): DIP-8 (PDIP) : 2.54 mm pitch, 7.62 mm row spacing, body ~9.8 x 6.35 SOIC-8 narrow : 1.27 mm pitch, 3.9 mm body, 5.86 mm row spacing (150 mil) SOIC-8 wide : 1.27 mm pitch, 7.5 mm body, 10.31 mm row spacing (300 mil) TSSOP-8 : 0.65 mm pitch, 3.0 x 4.4 body, 6.4 mm total width MSOP-8 : 0.65 mm pitch, 3.0 x 3.0 body, 4.9 mm total width QFN-16 (3x3) : 0.5 mm pitch, 3 x 3 body, exposed pad JST-XH (2-8p) : 2.50 mm pitch, through-hole, right-angle common Screw terminal : 5.00 mm or 5.08 mm pitch, through-hole Male header : 2.54 mm pitch (0.1"), through-hole Use these when the user is comfortable with a "standard package" answer; ALWAYS note that dimensions came from the standard, not a specific datasheet, so the user can verify against their part if precision matters. 4. Present a condensed pre-build summary before placing pins: "Building DIP-8 for ATtiny85: 8 pins, 2.54 mm pitch, 7.62 mm row spacing, board ~10 x 6.5 mm. Pinout I plan to label: pin 1 = /RESET, pin 2 = PB3, pin 3 = PB4, pin 4 = GND, pin 5 = PB0/MOSI, pin 6 = PB1/MISO, pin 7 = PB2/SCK, pin 8 = VCC. Sound right?" Wait for confirmation, then build via actions. BUILD ORDER — this ordering matters: a. newFootprint() — reset any leftover state. b. setPitch(p) with the package's grid pitch (2.54 mm for DIP/headers, 1.27 mm for SOIC narrow, 0.65 mm for TSSOP/MSOP, etc.). c. setBoard(w_mm, h_mm) with the ACTUAL package dimensions plus a small margin (~1 mm each side). Sizing FIRST means the outline is right the moment the first pad lands. d. setShape("rect") for through-hole packages, "circle" for round connectors / sensors. e. Only NOW start addPin() calls. Compute (ix, iy) from mm positions divided by pitch. Pins land at world (ix*pitch, iy*pitch) — with the board pre-sized, every pad falls inside the outline. f. Optional: if you already placed pins first (or the user asked mid-flow), call autoFitBoard(1) — the board resizes to hug the existing pin bounding box. This is the safety net; prefer the sized-first path when you can. Never leave the board at the default 32x18 mm when building a smaller part — pins will still land correctly but the outline is misleading to the user. 5. If the user seems inexperienced, offer the choice PROACTIVELY: "Do you have a datasheet in hand, or should I go with the common DIP-8 layout? Either works." Never make it feel like a gate they must pass to get help. ## What Circuitcaster is (and is not) - It IS: an approachable front-end for laying out component pads (footprints), wiring components together (schematic), and placing them on a board outline. It exports self-describing JSON meant to be read by both humans and machines. - It is NOT a router or Gerber generator. That heavy geometry work is handed off to KiCad (free, open-source). Circuitcaster owns the friendly design front-end; KiCad owns the fab back-end; this manual + an AI is the glue between them. - Web version (app.circuitcaster.com) is free. The phone app adds native powers (stylus/S Pen drawing, camera measuring, offline, 1:1 print, cloud sync). ## Core concepts - **Dot grid**: pads snap to a grid whose spacing is the `pitch` (default 2.54 mm = 0.1 inch, standard header pitch). Sub-grid position is a per-pad `nudge`. - **Footprint**: the pad layout of ONE component (a chip, connector, etc.). Schema `dotgame.footprint.v3`. - **Project / board**: many components placed on a board outline, wired together. The full export ("Export All") schema is `dotgame.project_bundle.v1`. - **Roles/colors**: pads are painted with colors that map to letters A..Z (role integer 0..26; 0 = unpainted). Convention: the letter is the first letter of the signal name on the chip silkscreen (G=GND, V=VDD/VIN, S=SCK/SD...). - **Coordinates**: KiCad convention. X increases RIGHT, Y increases DOWN. Units are millimeters. Pad `dx_mm/dy_mm` are measured from the component's own center. ## Footprint schema (dotgame.footprint.v3) Top-level fields: `schema`, `label`, `shape` ('rect'|'circle'), `pitch_mm`, `board_mm` {w,h} (w = diameter when circle), `rotation_deg` (0/90/180/270, display-only — pad coords stored unrotated), `pin_count`, `pins[]`. Circles also carry `pin1_marker_mm` and `circle_offset_mm`. Each `pins[]` entry: `n` (1-indexed pin number), `board_xy_mm` (relative to TOP-LEFT of the component), `kicad_xy_mm` (relative to CENTER, KiCad convention), `dot_index` [col,row], `nudge_mm` [dx,dy], `role` (0..26), `name` (signal string). ## Project bundle schema (dotgame.project_bundle.v1) — the full fab handoff Fields: `schema`, `project_name`, `board_outline` (shape + w_mm/h_mm), `mounting_holes[]` ({id,x_mm,y_mm,dia_mm}), `components[]`, `wires[]`, `nets[]` (pre-computed connectivity — each net groups electrically-common pads), `orphan_junctions[]` (dangling wires to resolve before fab), `footprints` (the library entry for each component type: pad geometry, board_mm, pitch). - **component**: `id`='cN'; `type`=part/library name; `x_mm,y_mm`=schematic position; `board_x_mm,board_y_mm`=physical board position; `rotation_deg`; `pin_count`; `pitch_mm`; `pads[]`={n, dx_mm, dy_mm (center-relative), role, name}. - **wire**: `id`='wN'; `from`/`to` each = {cid:'cN', n:padNumber} OR {type:'junction', wireId:'wN', bendIdx:int}; `bends[]`=[{x_mm,y_mm}]; `layer`='F.Cu'(top)|'B.Cu'(bottom); `role`/`color`. ### To GENERATE or EDIT a project for import Output a JSON object with a `wireComponents` array (rename `components` -> `wireComponents`) and a `wires` array; give it a new `name`; drop `id` (the app assigns a fresh project id, so imports never overwrite). Keep referential integrity yourself — the importer does NOT check it: every wire endpoint's `cid` must exist in `wireComponents[]`; every pad `n` must exist on that component; junction `wireId`/`bendIdx` must be valid; if you delete a component, delete its wires too. IDs unique within the project. Units mm. The importer reads only `wireComponents[]` + `wires[]` (it ignores `nets[]` — recompute or omit if you rewire). Import via Projects -> file picker (chat apps can corrupt ASCII quotes). ## The downstream pipeline: Circuitcaster -> KiCad -> Gerbers -> real board A completed `dotgame.project_bundle.v1` export contains everything needed to manufacture the board. The proven path (validated end-to-end on the FleetCom project): 1. **Build KiCad footprints** from `footprints{}` — each entry gives pad geometry, board size, and pitch. One `.kicad_mod` per component type. 2. **Build the schematic / netlist** from `nets[]` — each net groups the pads that are electrically common. Resolve any `orphan_junctions[]` first (usually they should join a ground or power net). 3. **Place components** per `components[].board_x_mm/board_y_mm` and `rotation_deg`, inside `board_outline`, with `mounting_holes[]` drilled. 4. **Route** the traces (KiCad's router, or Freerouting via a Specctra DSN/SES round-trip). Circuitcaster ships headless Python DSN export + SES import tools for autorouting outside the KiCad GUI. 5. **DRC** (design-rule check) to catch clearance/width errors. 6. **Export Gerbers + drill files** — the manufacturing artifact. 7. **Order the board** — upload the Gerbers to a fab house (JLCPCB, PCBWay, OSHPark, Aisler, etc.). A week later a physical PCB arrives. An AI pointed at this manual can drive or guide every step above, using the export as ground truth rather than guessing at KiCad steps. ## For AIs helping a human - Read the user's exported JSON first; its embedded `_ai_briefing` / `_ai_edit_instructions` are authoritative and version-matched to their file. - When teaching a beginner, translate: "footprint" = the pad pattern for a part; "net" = wires that are electrically the same; "Gerber" = the file a factory prints from. - Never invent pad positions — the export is the user's truth about physical reality. Compare against it; suggest fixes; don't overwrite intent silently. Contact / project home: https://circuitcaster.com Free web app: https://app.circuitcaster.com