This file provides guidance to Codex (Codex.ai/code) when working with code in this repository.
Build & Development:
bun run build- Build package using tsup (ESM format with TypeScript declarations)bun run format- Format code using Biomebun test- Run tests using Bun's built-in test runnerbun test <file-pattern>- Run specific testsbunx tsc --noEmit- Typecheck the project
@tscircuit/core is a React-based circuit design system that converts React components into Circuit JSON, which renders as PCB layouts, schematic diagrams, and 3D models.
- Normal Components: Electronic components (resistors, capacitors, chips, etc.) in
lib/components/normal-components/ - Primitive Components: Low-level elements (traces, holes, ports, silkscreen, etc.) in
lib/components/primitive-components/ - Base Components: Abstract classes
RenderableandNormalComponentinlib/components/base-components/
The system uses a 42-phase rendering pipeline:
- React subtree rendering
- Source component creation
- Schematic layout and rendering
- PCB layout and routing
- 3D CAD model generation
Components implement specific phase methods like doInitialSourceRender(), doInitialSchematicComponentRender(), doInitialPcbComponentRender().
lib/fiber/- React reconciler integration for JSX-to-class-instance conversionlib/utils/autorouting/- PCB trace routing algorithmslib/utils/schematic/- Schematic layout utilitieslib/utils/edit-events/- Manual editing systemlib/sel/- CSS-like selector system for component querying
Uses Bun's native test runner with extensive snapshot testing:
const { circuit } = getTestFixture()
circuit.add(
<board>
<resistor name="R1" />
</board>
)
circuit.render()
expect(circuit).toMatchPcbSnapshot(import.meta.path)Test Structure:
- Tests in
tests/organized by component type - Generates
.snap.svgfiles for visual regression testing - Supports both PCB and schematic view snapshots
- Special categories: examples, features, repros, subcircuits
BUN_UPDATE_SNAPSHOTS=1 bun test path/to/file.test.tsto update snapshots- Only one test per file, otherwise split into multiple enumerated files e.g.
fn1.test.ts,fn2.test.ts, etc. - Almost all tests should have a visual snapshot with clear text (e.g pinLabels) or such that looking at JUST the svg is enough to understand what is being tested or the expected output
- Don't add trivial
expector assertions, the visual snapshots methods e.g.toMatchSchematicSnapshot,toMatchPcbSnapshotetc. are the most important part of the test
Creating New Components:
- Define props using @tscircuit/props package
- Extend
NormalComponentorPrimitiveComponent - Implement required render phase methods
- Add to component catalogue in
lib/fiber/catalogue.ts - Write comprehensive tests with snapshot comparisons
Selector System:
circuit.selectAll(".R1 > .pin1") // Find pin1 of resistor R1
circuit.selectOne("resistor") // Find first resistorBreaking up class files:
- If a class INSTANCE FUNCTION is too long, create a file
ClassName_fnName.tsand call the function from the class file -
- Do not use this pattern for non-instance methods
- React + custom React Reconciler
- TypeScript (strict mode, ESNext target)
- Zod for prop validation
- circuit-json ecosystem for data interchange
- Biome for formatting/linting
- External services: @tscircuit/footprinter, @tscircuit/capacity-autorouter
- Enum / discriminant values use underscores, not hyphens. Any string-literal
union or enum-like value (e.g. snapshot modes, circuit-json
typefields, warning names) must besnake_case: useschematic_stacked, notschematic-stacked. This keeps values consistent with the circuit-json ecosystem (schematic_component,source_property_ignored_warning, etc.).
- Use the most concrete domain term available. Avoid vague names such as
component,item,reference, orindexwhen the value has a more precise role. - Do not introduce transport, protocol, or serialization vocabulary into the internal domain model. Translate domain identifiers into boundary-specific fields only at the serialization or adapter boundary.
- Do not use raw
Map<string, ...>types for domain identifiers. Use an existing named or branded key type, such asMap<SourceTraceId, ...>, and name mapping variables to make both key and value meanings clear. - Do not widen domain identifiers or keys to
stringin parameters, return types, collections, or intermediate values. Use or export the canonical named or branded type, such asSourceTraceIdorSubcircuitConnectivityMapKey. - Prefer inferred local types when the initializer already has the correct
domain type. Avoid redundant primitive annotations such as
: stringor: number; they can erase more specific types. - Prefer canonical exported domain types over reconstructing equivalent types
with
Omit,NonNullable, indexed access, or ad hoc aliases. If an external dependency does not export the identifier type, define one named boundary alias from its canonical interface instead of repeating inline derivations. - Reuse an existing domain interface when a function needs part of its behavior.
Use
Pick<ExistingInterface, "method">for a deliberately narrow dependency instead of creating a duplicate structural interface. - Name loop variables, parameters, collections, and intermediate values after
their precise domain role and representation, such as
srjConnections. When nearby values share a type, distinguish their roles in their names, such aspositiveSubcircuitConnectivityMapKeyandnegativeSubcircuitConnectivityMapKey. - Name helpers after their full domain operation, including a representation
qualifier such as
Srjwhen it identifies the boundary being handled. Do not useRequiredto signal throwing; when throwing must be explicit in the name, use anOrThrowsuffix. - Do not add runtime type guards after a trusted typed API. Parse or refine once at an untrusted boundary; redundant internal guards add noise and hide broken type contracts.
- ESM output with TypeScript declarations
- Path mapping for
lib/*imports - Biome enforces kebab-case file naming, space indentation, double quotes for JSX
- Do not assign/change to _parsedProps or props
- Do not add a ton of instance methods to classes, especially large classes like NormalComponent