altiumts is a TypeScript-first parser and serializer for Altium document
formats.
The current experimental release supports source-preserving ASCII .PcbDoc,
.SchDoc, .PrjPcb, and .OutJob files plus read-only binary PCB and
schematic compound-file variants. It models syntax, semantic records,
references, connectivity, CFB storages, and streams as classes. Unknown
content remains available in the source tree, and untouched binary documents
retain their exact original bytes.
The support matrix is deliberately operation-specific: binary documents can be inspected and round-tripped untouched, but modified binary serialization is refused. See Compatibility for tested versions and explicit exclusions.
The repository includes a browser-local project viewer for opening a project
folder, a ZIP archive, a public GitHub repository or folder URL, or individual
.PrjPcb, .SchDoc, and .PcbDoc files. It renders schematic sheets,
complete PCBs, and individual PCB layers as SVGs. Local project contents stay
in the browser and are never uploaded; GitHub projects are downloaded directly
from GitHub and parsed locally.
Open the hosted Altium File Viewer by tscircuit
This is an open-source community tool by tscircuit. It is not affiliated with or endorsed by Altium.
bun run site:devRun bun run site:typecheck and bun run site:build to verify a production
build. If a design cannot be processed, the viewer prepares a GitHub bug report
containing filenames and parser errors, without including design contents.
bun add altiumtsimport { readFile, writeFile } from "node:fs/promises"
import {
AltiumTrackRecord,
parseAltiumPcbDoc,
} from "altiumts"
const source = await readFile("board.PcbDoc", "utf8")
const board = parseAltiumPcbDoc(source)
const tracks = board.records.filter(
(record): record is AltiumTrackRecord =>
record instanceof AltiumTrackRecord,
)
for (const track of tracks) {
if (track.get("LAYER") === "TOP") {
track.set("WIDTH", "8mil")
}
}
await writeFile("board-modified.PcbDoc", board.getString())Create native binary Altium documents from ASCII models:
import {
parseAltiumPcbDoc,
serializeAltiumPcbDocToBinary,
serializeAltiumSchDocToBinary,
} from "altiumts"
const pcb = parseAltiumPcbDoc(asciiPcbSource)
const pcbBytes = serializeAltiumPcbDocToBinary(pcb)
const schematicBytes = serializeAltiumSchDocToBinary(asciiSchematicSource)The native PCB serializer preserves the source board contour coordinates and
winding while encoding board, net, component, pad, track, via, and text
streams. It throws AltiumSerializationError for record kinds, primitive
fields, layers, shapes, or values that it cannot encode without loss.
The generic parseAltiumAscii function returns document lines without
requiring a Board root record. parseAltiumAsciiStream() accepts an async
iterable of decoded chunks. Every node supports getChildren(), walk(),
visit(), source locations, stable parsed IDs, parent/document references,
dirty state, structural hashes, and JSON debug output.
Use the byte-oriented entrypoint when the container or encoding is not known:
import { readFile } from "node:fs/promises"
import {
AltiumBinaryPcbDoc,
AltiumSchDoc,
parseAltiumFile,
} from "altiumts"
const bytes = new Uint8Array(await readFile("design.PcbDoc"))
const { detection, document } = parseAltiumFile(bytes)
console.log(detection.container, detection.documentKind, detection.encoding)
if (document instanceof AltiumBinaryPcbDoc) {
console.log(document.components.length, document.nets.length)
console.log(
document.pads.length,
document.tracks.length,
document.arcs.length,
document.vias.length,
document.regions.length,
document.texts.length,
)
}
if (document instanceof AltiumSchDoc) {
console.log(document.sourceFormat, document.records.length)
}Binary .PcbDoc parsing currently inventories every CFB storage family,
decodes common property streams, and creates semantic records for board
metadata, components, nets, classes, rules, polygons, pads, tracks, arcs, vias,
fills, regions with contour holes, bodies, models, and wide-string-backed
text. Extended pad records include top/middle/bottom and full-stack
layer geometry, custom corner radii, hole shapes and offsets, slot dimensions,
and plating state. Board geometry retains the source contour vertices and arc
metadata while exposing approximated points, bounds, winding, board cutouts,
layer-stack regions, and polygon cutouts. Binary .SchDoc parsing decodes framed property records,
%UTF8% fields, typed common record IDs, owner indexes, hierarchy links, and
schematic connectivity.
altiumts inspect board.PcbDoc --json
altiumts tree sheet.SchDoc
altiumts streams board.PcbDoc
altiumts records board.PcbDoc --json
altiumts validate board.PcbDoc --json
altiumts roundtrip board.PcbDoc
altiumts diff before.PcbDoc after.PcbDoc
altiumts extract board.PcbDoc extracted-streamsextract sanitizes stream names and rejects paths outside the requested
directory. Hex dumps and allocations are bounded.
The SVG serialization module can render a complete PCB, one PCB layer, or an ASCII/binary schematic sheet:
import { readFile, writeFile } from "node:fs/promises"
import {
parseAltiumPcbDoc,
serializeAltiumPcbLayerToSvg,
serializeAltiumPcbToSvg,
} from "altiumts"
const board = parseAltiumPcbDoc(await readFile("board.PcbDoc", "utf8"))
await writeFile("board.svg", serializeAltiumPcbToSvg(board))
await writeFile(
"board-top.svg",
serializeAltiumPcbLayerToSvg(board, "TOP"),
)
await writeFile(
"board-top-detail.svg",
serializeAltiumPcbLayerToSvg(board, "TOP", {
// Lower-left origin and dimensions in normalized Altium board units.
viewBox: { x: 4200, y: 2500, width: 1200, height: 900 },
}),
)serializeAltiumSheetToSvg() accepts AltiumSchDoc, AltiumPcbDoc, or the
lines returned by parseAltiumAscii(). The PCB serializers accept either
ASCII or binary PCB documents. PCB rendering currently prioritizes outlines,
tracks, arcs, pads, vias, regions, polygons, fills, and text. The renderer is
intentionally source-model based and also renders shape-based component-body
outlines, so visual snapshot differences expose parser or geometry regressions
directly. A PCB viewBox crops in board coordinates, uses no implicit margin,
and omits primitives that cannot intersect the crop; this keeps focused visual
tests small and makes dense features easier to inspect. Component
designator/comment text follows the parent component's NAMEON and COMMENTON
visibility flags; pass { showHidden: true } when debugging hidden source
text.
Binary schematic rendering includes embedded images, Altium font-table sizes, ordinary graphic lines, text frames, No-ERC markers, and paper-bound clipping. Embedded Windows bitmaps are decoded with bounded allocation and emitted as portable PNG data URLs, keeping the generated SVG self-contained.
Board cutouts are combined with the board outline using even-odd SVG fill.
Polygon cutouts erase poured-region color before independent fills, tracks,
pads, and vias are painted. Pass { showBoardCutouts: false } to inspect the
uncut board substrate during debugging.
Single-layer PCB renders select the corresponding pad-stack geometry. Round, rectangular, rounded-rectangle, octagonal, and obround pads are rendered directly, along with round, square, and slotted holes.
parseAltiumPcbDoc(source, options?)parses and validates an ASCII.PcbDoc.parseAltiumSchDoc(source, options?)parses ASCII or binary.SchDocinput.- Binary PCB documents expose typed
modelsandembeddedModelscollections.getEmbeddedModelForComponentBody()resolves duplicate model IDs using the body's stored 3D rotation, andgetDecompressedBytes()extracts the corresponding zlib-compressed STEP payload with a configurable output-size limit. - PCB documents resolve component and net indexes through
getComponentForRecord(),getNetForRecord(),getRecordsOwnedByComponent(), andgetRecordsOnNet(). The SVG serializer acceptscomponentIndicesandnetIndicesfor focused debugging renders. - PCB documents expose lazy
indexandconnectivitymodels, layer-stack metadata (including V8/V9 sub-stacks, layer pairs, and controlled-impedance profiles),boardGeometry, board-grid settings, typed rule constraints, polygon/rule references, unique-ID lookup, and component bounds. Individual board and region records exposeoutline/geometryhelpers without changing their source fields. Rule helpers cover routing width/layers/vias, differential-pair gaps, impedance, matched-length tolerance, thermal relief, masks, holes, heights, silk clearances, and test-point dimensions. - Schematic documents expose typed components, pins, wires, labels, ports,
power ports, sheets, ownership indexes, sheet links, and
netGraph. parseAltiumPrjPcb()andparseAltiumOutJob()provide source-preserving project/job parsing. Project references resolve Windows paths consistently on any host.validateAltiumDocument()returns machine-readable structural diagnostics.serializeAltiumDocument()validates by default and refuses unsafe modified binary output. PCB validation checks primitive layer references against standard, legacy, and document stack-specific names while preserving unknown names for inspection.cloneAltiumNode(),transformAltiumTree(), andsearchAltiumRecords()support copy-on-write tooling and generic AST work.altiumCompatibilityManifestandsupportsAltiumOperation()let callers query support without relying on prose.parseAltiumBinaryPcbDoc(bytes, options?)parses a binary.PcbDoc.parseAltiumCompoundFile(bytes, options?)exposes a bounded, read-only OLE/CFB tree.detectAltiumFile(bytes)andparseAltiumFile(bytes, options?)provide extension-independent format detection and dispatch.parseAltiumAscii(source, options?)parses any Altium ASCII record stream.AltiumPcbDoc#getString()serializes a complete board.AltiumRecord#get(),getAll(),set(), anddelete()provide ergonomic field access while the ordereditemsarray preserves duplicate and unknown fields.sanitizeAltiumFieldText()replaces record delimiters and control characters before arbitrary text is assigned to an ASCII field.- Known PCB primitives are represented by dedicated record classes:
AltiumArcRecord,AltiumBoardRecord,AltiumComponentRecord,AltiumNetRecord,AltiumPadRecord,AltiumPolygonRecord,AltiumRegionRecord,AltiumTextRecord,AltiumTrackRecord, andAltiumViaRecord. - Unrecognized record kinds become
AltiumUnknownRecordinstances and malformed lines becomeAltiumRawLineinstances, so permissive parsing does not discard data. serializeAltiumPcbToSvg(),serializeAltiumPcbLayerToSvg(), andserializeAltiumSheetToSvg()provide visual inspection and regression-test output.
Pass { mode: "strict" } to reject malformed text, "compatible" for the
normal source-preserving behavior, or "recovery" to make recovery decisions
visible through onDiagnostic. Unknown record kinds remain preserved in every
mode for forward compatibility. Limits are available for files, lines, fields,
binary records, CFB chains, directories, decompressed models, and writes.
import { parseAltiumPrjPcb } from "altiumts"
const project = parseAltiumPrjPcb(projectText)
console.log(project.documents)
console.log(project.variants)
console.log(project.resolveDocumentPaths("/workspace/hardware"))
project.addDocument("sheets/power.SchDoc", { uniqueId: "POWER-SHEET" })
project.addVariant("Production", { description: "Shipping configuration" })
console.log(project.getDocumentGraph("/workspace/hardware").nodes)Targeted PCB edits can be applied transactionally and exported as an undoable change set:
import {
reassignPcbRecordLayer,
renamePcbNet,
runPcbEditTransaction,
} from "altiumts"
const result = runPcbEditTransaction(board, (draft) => {
renamePcbNet(draft, 1, "USB_D+")
const track = draft.getRecordsByKind("Track")[0]
if (track) reassignPcbRecordLayer(draft, track, "BOTTOM")
})
console.log(result.validation, result.changeSet)Download the pinned SimpleFOC Mini, SimpleFOC Shield, Hyperpolyglot, Elk Pi, Novena, and TI TMDS62LEVM Altium PCB/schematic references:
bun run download-references
bun run inventory-references
bun run inventory-schema
bun run benchmarkThe TI fixture is extracted from the official nested SPRCAL9 Rev. B archive. Its 60.5 MB PCB and all 57 binary schematic sheets exercise large multilayer-board parsing, strict validation, board contours, polygon cutouts, embedded schematic images, exact untouched round trips, and PCB/schematic SVG rendering in CI.
Then run the complete suite:
bun test
bun run test:update-svg
bun run typecheck
bun run format:check
bun run build
bun run verify:browser
bun run verify:packageThe imported reference files are not committed to this repository. Their
generated .snap.svg visual baselines are committed and compared with
bun-match-svg.
Binary writing, semantic .SchLib/.PcbLib/.IntLib parsing, a complete
Altium rule evaluator, Circuit JSON conversion, and licensed Altium reopen
tests are not implemented. Library headers are detected so callers receive an
explicit unsupported-feature error instead of accidental document parsing.
Unverified fields, trailing bytes, streams, embedded blobs, and unknown records
are retained for inspection and exact untouched round trips. Project-level
variant fitted-state overlays and fully populated generated title blocks are
not yet reconstructed when an individual .SchDoc is rendered in isolation.
See CHECKLIST.md for the implementation roadmap and docs/format-references.md for research sources. The checklist intentionally keeps fixture-, license-, and reverse-engineering- dependent work open.
The packed npm artifact is limited to 1 MB compressed and 5 MB unpacked. The minified browser-compatible core bundle is limited to 1.5 MB; both budgets are enforced by repository scripts and CI.