FFalCAD docs

The .falcad project format — version 1

Status: draft, implemented by @falcad/format 0.1. Normative JSON Schemas are generated into ../schema from the zod definitions in ../src; those definitions are the single source of truth.

Goals

Layout

A project is a directory with one entry file:

blinky/
  blinky.falcad                     ← manifest (entry file)
  falcad.lock                       ← pinned engines/toolchains/libraries
  schematics/main.sch.json          ← falcad.schematic
  pcb/main.pcb.json                 ← falcad.board
  simulation/main.sim.json          ← falcad.simulation
  assembly/robot.asm.json           ← falcad.assembly (3D system assembly)
  firmware/src/blinky.ino           ← plain source
  rtl/counter.v                     ← plain source (HDL)
  scripts/led_bar.py                ← plain source (circuit script)
  libraries/project.library.json    ← falcad.library
  results/                          ← generated output, Git-ignored

Only the file names inside the manifest are significant. The folder names above are conventions.

A packed project (.falcadpack) is optional and a ZIP archive of the same files with exactly one top-level .falcad entry. Packing is deterministic: entries are sorted and timestamps are fixed. Unpacking enforces an entry-count limit, a size limit per file and in total, and the path rules below.

Manifest (*.falcad)

Field Type Notes
format "falcad"
formatVersion 1
id UUID v4 Project identity.
name, description string
displayUnits mm | mil | in Display preference only; storage is nm.
generator string? Last writer, diagnostics only.
documents[] entry { id, kind, name, path, … }. kind is one of schematic, board, simulation, assembly, firmware (+language, target), hdl (+language, role), script (+language, target, params, top), notes, asset.
libraries[] { name, path } Project-local component libraries.
toolchains[] { id, version } Exact toolchain pins for reproducible builds.

A structured document’s id must equal its manifest entry’s id.

Script documents (circuits-as-code)

A script entry is a plain source file that generates a schematic:

Field Type Notes
language python javascript
target UUID v4? The schematic document the script generates and updates. Absent until the first run creates it.
params `{ [name]: string number
top string? HDL scripts: top module (default: the only module no other module instantiates).

Running a script produces a Circuit Description (parts, nets, no-connect pins; schema falcad.circuit, published by @falcad/script as circuit.schema.json). A reconciler turns it into an ordinary transaction on the target schematic. Generated components carry the reserved properties falcad.key (the stable part key from the script), falcad.links (ids of the stub wires, labels, power symbols and no-connect markers generated for each pin) and, on generated power symbols, falcad.owner; re-running a script reuses those entities, so component ids, board links and hand-made placement survive. Loaders never execute scripts: running one is always an explicit user action.

Paths

Paths are relative to the manifest’s directory and use /. These are rejected: empty segments, ., .., a leading /, \, : (so no drive letters), control characters, * ? " < > |, Windows device names (con, nul, com1, …), and segments ending in a dot or a space. On disk the loader also resolves symlinks and refuses anything that resolves outside the project root.

Lockfile (falcad.lock)

{ format: "falcad.lock", version: 1, entries: [{ kind, id, version, sha256?, source? }] }, where kind is one of engine, toolchain, library, model or extension. Tools write it and Git reviews it. It is how a project rebuilds with exactly the toolchain it was built with, instead of whatever happens to be installed.

Common conventions

Schematic (falcad.schematic v1)

Top-level entity collections: sheets, components, wires, junctions, labels, noConnects, notes, ercSuppressions. Every entity except sheets and suppressions carries sheetId.

Board (falcad.board v1)

Simulation (falcad.simulation v1)

Optional analysis fields. They were added in format 1 without a version change; older readers that reject unknown keys reject documents that use them.

Assembly (falcad.assembly v1)

A project-level 3D scene: boards of the project and mechanical bodies placed in space, and the external wiring between them.

Footprints on boards may carry model3d {path, format, unit, scale, offset, rotation}: a user model (GLB / glTF / STL / OBJ asset document) that replaces the parametric body in 3D. Binary models are stored as base64 text in an asset document whose mediaType ends in ;base64 (for example model/gltf-binary;base64).

Library (falcad.library v1)

Symbols have pins with electrical types, which ERC uses. Their graphics are polyline, rect, circle, arc or text. defaultValue is the value of a newly placed component. The optional value states what the value means (added in format 1, see below). An optional sim mapping names a solver primitive and its terminal order:

The primitive list (SimPrimitiveSchema) is additive. It covers passive parts, sources, diodes / LEDs, BJTs, MOSFETs, JFETs, controlled sources, op-amps, comparators, the 555, regulators, magnetics, switches, relays, instruments, microcontrollers (mcu_avr, arduino_uno), logic gates and ICs, and power (power symbols, see below).

Value metadata (SymbolDef.value)

Added in format 1 without a version change. Readers that reject unknown keys reject libraries that use it.

kind Fields Meaning
quantity quantity, min?, max?, exclusiveMin?, allowNegative?, allowInfinite?, label? A physical value such as a resistance or a voltage. Bounds are in SI base units.
netName label? The name of the net (power symbols). Not empty, no whitespace or control characters.
enum options, custom?, label? One of the options. An option is a string or {value, label?, description?, params?}. With params it is a model preset: when the value selects it (case-insensitive), its params apply over the symbol’s parameter defaults. A value that matches no option keeps the preset of defaultValue. custom: true allows any other text (custom part names).
text label? Free text (part numbers, labels).

Without value, power symbols read as netName and other symbols as text. label names the value in editors (for example “Amplitude”). Without it editors use the quantity’s name. The default value stays in defaultValue (one source), and it must be valid for the value metadata.

Simulation parameters (SymbolDef.sim.params)

Each entry is {name, label, kind, description?, default?, advanced?, when?} plus fields for its kind:

kind Fields Stored text
quantity quantity and the same bounds as quantity values Engineering notation, unit-checked (see Quantities).
enum options One option value.
boolean true or false (editors also accept on / off, yes / no, 1 / 0).
text Any text.
table columns (quantities) Rows of one value per column, separated by whitespace, commas or semicolons, for example PWL points 0 0, 1m 5.

default is the text used when a component does not set the parameter. Without it the parameter is unset (the engine’s own fallback or none). Every default must be valid for its own metadata, and parameter names must be unique. advanced parameters are collapsed in editors. when: {param, values} shows a parameter only while another parameter has one of the values (pulse timing while waveform is pulse).

Power symbols: a non-ground power symbol has primitive power and a voltage quantity parameter. Its default follows the net name where the name states a voltage (+5V → 5, +3V3 → 3.3). VCC has no default. With a voltage, the symbol is an ideal supply between its net and ground in simulation, one per net. A net that another element already drives (a source, a regulator output) gets no second source. Power symbols that disagree on one net’s voltage are an error. Ground is the 0 V reference and has no voltage parameter.

Quantities

The quantity table (QUANTITIES in src/quantity.ts) is the single definition of each quantity’s SI unit, accepted spellings and display:

Quantity Unit Also accepted Negative by default
resistance Ω ohm, ohms, R (10R, 4R7, R47) no
capacitance F no
inductance H no
voltage V volt, volts yes
current A amp, amps yes
frequency Hz no
time s sec no
power W no
temperature °C ℃, degC, C (no prefixes) yes
conductance S mho, ℧ yes
transconductance A/V² A/V2, A/V^2 no
per_voltage V⁻¹ 1/V, /V, V^-1 no
slew_rate V/s V/ms, V/us, V/µs, V/ns no
energy eV no
length m no
ratio (none) % (50% = 0.5), no prefixes no
dimensionless (none) yes

Parsing (parseQuantity) accepts plain and signed numbers (5, -10, +3.3, 1e-3, the typographic minus), prefixes (f p n u µ m k M meg G T, M is mega and m milli), infix notation (4k7), the field’s unit with or without a space (5V, 5 V), unit letters in any case when unambiguous (5v, 100nf), and inf / ∞ only where allowInfinite is set. Everything else is rejected with a reason: not a number, an unknown unit (with the valid leading value as a suggestion, '5vdc' → 5 V), a unit of another quantity ('10mA' is a current), negative, below the minimum or above the maximum.

Stored text. A value keeps the designer’s notation (4k7, 2k2, 100nF, 5 V, trimmed) whenever the lenient legacy parser parseSiValue reads it as the same value, so every FalCAD reader agrees on it. Anything else (5v, −10 with a typographic minus, 100nf, 50%, 0.5V/us) is stored in canonical form: compact engineering notation without the unit, ASCII, 12 significant digits, with meg for mega and u for micro so SPICE reads it the same way (5, -10, 100n, 0.5, 500k). Display text adds the unit and typographic signs (4.7 kΩ, −10 V, 2.2 µF).

Footprints have pads (smd/tht/npth; circle/rect/roundrect/oval), silkscreen, a courtyard and an optional parametric body for 3D preview.

Canonical JSON

Keys are ordered with identity keys first (format, formatVersion, schema, version, id, kind, name) and the rest in code-point order. The output uses two-space indentation and LF line endings with a trailing newline. undefined is omitted, -0 is written as 0, and non-finite numbers are an error. Array order is meaningful and preserved.

Collaboration model

schema/collections.json is generated from the same definitions. For each structured kind it lists the entity collections, the reference fields and the editable document properties. Collaboration transactions (see falcad-engine’s collab protocol) address entities as (collection, id). Both the TypeScript client and the C# server enforce them from this one description.

Compatibility promise