v3.0.0

<bmx-pcb-viewer>

A viewer for printed circuit boards from their fabrication files, in the page, nothing uploaded: the Gerber layers (RS-274X with X2 attributes) and Excellon drill files a board house is sent, loose or in the ZIP the CAD tool made.

13 properties · 7 events · 11 methods · 4 parts

Example

Try it with your own files in confidence: they are opened by your browser, on your device. Nothing is uploaded, no copy reaches us or anyone else, and nothing is kept once you close this tab.

A fictional two-layer sensor board, its fabrication files written by the viewer's own sample: Gerber X2 copper, solder mask, silkscreen and paste for both sides, the profile, and plated and non-plated drill files. See it as made from the top and the bottom, or as layers; click a pad or a track to light up its net and name its part and pin; find a part (U1, J2) or a net (SDA) on the Parts tab; measure between pads; pin notes to the board; read the drill table; save the view as SVG, PNG or PDF. Change the solder mask to red, blue or black and the finish to tin or bare copper.

Show markup
<bmx-pcb-viewer id="ex-pcb" style="--bmx-pcb-viewer-height: 36rem"></bmx-pcb-viewer>
<p class="note">A fictional two-layer sensor board, its fabrication files written by the viewer's own sample: Gerber X2 copper, solder mask, silkscreen and paste for both sides, the profile, and plated and non-plated drill files. See it as made from the top and the bottom, or as layers; click a pad or a track to light up its net and name its part and pin; find a part (U1, J2) or a net (SDA) on the Parts tab; measure between pads; pin notes to the board; read the drill table; save the view as SVG, PNG or PDF. Change the solder mask to red, blue or black and the finish to tin or bare copper.</p>

<div class="row" style="gap: 0.75rem; flex-wrap: wrap; align-items: center; margin-block: 0.5rem 1.5rem">
  <label>Open your own board (Gerber and drill files, or a ZIP) <input type="file" id="ex-pcb-file" multiple accept=".zip,.gbr,.ger,.gtl,.gbl,.gts,.gbs,.gto,.gbo,.gtp,.gbp,.gko,.gm1,.drl,.xln,.txt" /></label>
  <button type="button" id="ex-pcb-sample">Show the sample again</button>
  <label>Solder mask
    <select id="ex-pcb-mask">
      <option value="green">Green</option>
      <option value="red">Red</option>
      <option value="blue">Blue</option>
      <option value="black">Black</option>
      <option value="purple">Purple</option>
    </select>
  </label>
</div>
<p class="note" id="ex-pcb-out" role="status"></p>

<script type="module">
  await customElements.whenDefined('bmx-pcb-viewer');
  const viewer = document.getElementById('ex-pcb');
  const out = document.getElementById('ex-pcb-out');
  const mm = v => `${Math.round(v * 100) / 100} mm`;
  viewer.addEventListener('bmxLoad', e => {
    const { name, stats, layers } = e.detail;
    out.textContent = `${name}: ${layers.length} files, ${mm(stats.width)} × ${mm(stats.height)}, ${stats.copperLayers} copper layers, ${stats.holes} holes, ${stats.components} parts, ${stats.nets} nets.`;
  });
  viewer.addEventListener('bmxSelect', e => {
    const s = e.detail;
    out.textContent = s ? [s.component && (s.pin ? `${s.component} pin ${s.pin}${s.pinName ? ` (${s.pinName})` : ''}` : s.component), s.net && `net ${s.net}`].filter(Boolean).join(', ') || 'Nothing named there.' : '';
  });
  viewer.addEventListener('bmxMeasure', e => (out.textContent = `Measured ${mm(e.detail.distance)}.`));
  viewer.addEventListener('bmxSave', e => (out.textContent = `Saved ${e.detail.name} (${Math.round(e.detail.data.size / 1024)} KB).`));
  viewer.addEventListener('bmxError', e => (out.textContent = e.detail.message));
  document.getElementById('ex-pcb-file').addEventListener('change', e => {
    if (e.target.files.length) viewer.open(Array.from(e.target.files));
  });
  document.getElementById('ex-pcb-sample').addEventListener('click', () => viewer.loadSample());
  document.getElementById('ex-pcb-mask').addEventListener('change', e => (viewer.maskColor = e.target.value));
  await viewer.loadSample();
</script>

WHAT IT DOES

  • Reads every Gerber feature boards use - apertures and macros, arcs, regions, clear polarity, step and repeat - and Excellon holes, slots and routes; knows each file's layer from its X2 attributes or the names the common CAD tools give their files.
  • Shows the made board from the top or the bottom - the solder mask's colour, copper under it, plated pads, laminate in the openings, the silkscreen, holes through - or the layers stacked in colours, each shown or hidden, coloured as wanted.
  • Nets and components from X2 attributes: click a pad or track to light up its net and name its part and pin; find a part or net by name and zoom to it.
  • Measures between points (snapping to pad centres) in millimetres, mils or inches; notes pinned to the board, kept as JSON.
  • The drill table, the board's size, copper layers, smallest hole and narrowest track.
  • Saves the view as SVG (vector, exact), PNG or PDF at a chosen resolution.

Properties

PropertyAttributeTypeDefaultDescription
compactBelow compact-below number 760 Below this width (pixels) the side panel goes under the board.
finish finish 'enig' | 'hasl' | 'copper' 'enig' The plated finish on exposed copper: enig (gold), hasl (tin) or copper.
label label string — The element's accessible name.
markups markups BmxPcbMarkup[] | string [] Notes on the board (or their JSON). Mutable: edits replace it.
maskColor mask-color string 'green' The solder mask's colour: a name (green, red, blue, black, white, purple, yellow, matte) or a CSS colour.
noFiles no-files boolean false Hide the Open button (the page gives the files with open).
readOnly read-only boolean false No notes added, changed or removed.
silkColor silk-color string 'white' The silkscreen's colour: white, black, yellow, or a CSS colour.
src src string — A URL of a ZIP of fabrication files, or of one Gerber file, to open.
strings strings Partial<BmxPcbViewerStrings> | string — Replacements for any of the wording (an object, or its JSON).
tool tool BmxPcbViewerTool 'pan' What a click does: pick and pan, measure, or add a note.
units units BmxPcbUnits 'mm' The units lengths are shown in.
view view BmxPcbView 'top' The made board from the top or the bottom, or the layers stacked in colours.

Events

EventDetailDescription
bmxError { message: string; name?: string | undefined; } Fired when files cannot be read.
bmxLoad BmxPcbViewerInfo Fired when a board has been read.
bmxMarkupChange { markups: BmxPcbMarkup[]; } Fired when notes are added, changed or removed.
bmxMeasure BmxPcbMeasure Fired when a measurement is made.
bmxSave BmxPcbSaveDetail Fired before a picture of the board is downloaded. Cancelable: cancel to keep the file yourself.
bmxSelect BmxPcbSelection | null Fired when something on the board is picked (a pad, a track) or the pick is cleared (null).
bmxViewChange { view: BmxPcbView; } Fired when the view changes (top, bottom, layers).

Methods

MethodSignatureDescription
download download(kind?: "svg" | "png" | "pdf") => Promise<void> Download the view as SVG, PNG or PDF (unless bmxSave is cancelled).
exportPdf exportPdf(dpi?: number, page?: "fit" | "a4" | "letter") => Promise<Blob> The view as a PDF, drawn at a resolution and printed at the board's true size ('fit' page, or A4 or Letter).
exportPng exportPng(dpi?: number) => Promise<Blob> The view as a PNG at a resolution in dots per inch (largest side 12,000 pixels at most).
exportSvg exportSvg() => Promise<string> The view as SVG: exact and vector, at the board's real size.
fit fit() => Promise<void> Fit the board in the view.
getBoard getBoard() => Promise<BmxPcbViewerInfo | null> What is open: its layers, figures and what was not used.
loadSample loadSample() => Promise<BmxPcbViewerInfo | null> Open the built-in sample board (a small two-layer sensor board with nets and parts).
open open(files: FileList | readonly (Blob | BmxPcbInputFile)[]) => Promise<BmxPcbViewerInfo | null> Open fabrication files: Gerber and drill files, ZIPs of them, or { name, data } records.
select select(target: { net?: string; component?: string; } | null) => Promise<void> Pick a net or a component (null clears).
setLayerVisible setLayerVisible(id: string, visible: boolean) => Promise<void> Show or hide a layer (layer view).
zoomTo zoomTo(target: { component?: string; net?: string; box?: readonly [number, number, number, number]; }) => Promise<boolean> Zoom to a component or a net (by name), or to a box in millimetres.

CSS shadow parts

PartDescription
panel The side panel.
stage The board.
status The status line under the board.
toolbar The toolbar.

CSS custom properties

PropertyDescription
--bmx-pcb-viewer-height The viewer's height.
--bmx-pcb-viewer-panel-width The side panel's width.
--bmx-pcb-viewer-radius The frame's corner radius.
--bmx-pcb-viewer-stage Behind the board, in the top and bottom views.
--bmx-pcb-viewer-stage-layers Behind the layers, in the layer view.