Repository navigation
Perfboard Studio v0.14.0
Added
-
A step bar: Circuit, Board, Placement, Wiring, Check, Build — and Next. The window
had every tool and no order: nothing said the circuit comes first, that a board is
chosen before the parts go on it, that routing joins them, that DRC says it can be built,
or that the guide and the 3D view are what it is built from. A row under the toolbar now
shows the six steps, where this board stands on each ("8 parts · 7 nets", "5 x 7 cm",
"8/8 on the board", "3 connections left", "0 errors · 1 warning"), and a Next button that
does whichever is next — a DRC error or an open net first. Pressing a step goes where it
is done. Choosing the board is a step of its own. -
Boards chosen by looking at them. The question of which stock board a circuit goes
on is now a grid of pictures, each board with the circuit actually arranged on it, the
suggested one starred and the too-small ones greyed; and New Board and Board Setup draw
the chosen product — finger strips, corner holes, printed legend — beside the questions,
redrawn as the size changes. The pictures are drawn by the board view itself. -
A welcome that has somewhere to begin. Draw a New Circuit, the shipped examples by
name with what each one is ("11 parts on a 6 x 8 cm board", the drawn-but-not-built one
first), Import a KiCad Netlist, and the six steps named once. -
A wire on the sheet can be dragged from pin to pin, as well as clicked at both ends.
A drag used to take the first pin and do nothing when let go -- the gesture everybody
tries first. The pin under the pointer is ringed before the click, and a pin is a target
of at least eight pixels at any zoom (it was 1.2 mm: five pixels on a fitted sheet). -
Ground and power from a pin's right-click. A pin on nothing offers the sheet's rails
by name, and GND and +5V when there are none — where it used to take the Label tool and
typing the name. -
part.addMany: several parts into the design as one undo step, all or nothing. -
The build guide in Turkish. The guide is what this application is for — the thing a
person follows with an iron in their hand — and it was English in a Turkish window: every
step, every check, the cut list, the parts list and the page they are printed from. It is
now written in the window's language: "D1 1N4007 — I32 → E32, 4 delik ara", "Katot —
bantlı uç — I32 deliğine", "K32 ↔ L32 açık devre olmalı", down to the column headings of
the CSVs and the progress counter on the page. The panel, the exported files and a saved
project's outputs agree,--headless --lang trwrites it too, and an agent asks for it
withlanguageongenerate_guide. English is unchanged, word for word. The
translation lives in the engine (phrasebook.py) because the sentences are built from
the board rather than looked up, and a test builds every board in the repository in both
languages and searches the Turkish for English left in it. Part names are said the same
way in the Parts panel and the guide, from one table. -
Route ▸ Crossings: routing with no wire at all. The engine could always be told what
a solder trace does where it meets something it may not cross, and nothing let anybody
tell it. A short jumper over the crossing stays the default; "one wire for the whole
connection" and "never use wire" are the other two. The last uses solder traces only,
whatever connection is preferred, and names each connection a trace cannot make rather
than laying wire nobody asked for. It is remembered with the other routing choices, and
an agent asks for the same thing withcrossingsonautorouteandreroute. -
File ▸ Open Example. The examples ship with the application and nothing in the
window pointed at them. They open as new, untitled boards — the file lives inside the
application, so saving over it would change the example for everybody — and the empty
board's hint mentions them when there are any. -
Wires laid along the grid. Every wire the router laid was one straight run between
its two ends, so a routed board was a cat's cradle of diagonals crossing each other, and
a straight bare wire could pass 0.2 mm from another net's pad. Route ▸ Lay Wires Along
the Grid (on by default) runs them square to the rows and columns of holes with as few
bends as the board allows, keeps a bare wire off every pin, joint and run of copper, and
keeps wires from lying on top of one another. On the shipped examples, stripped and
routed again: no diagonal wire, nothing unrouted, no short, no DRC error, for about a
fifth more wire. The engine's default stays straight, so every golden route is
unchanged;RouterOptions.wire_pathchooses. The MCP server'sautorouteandreroute
take the same choice aswiresand default to the grid too, so an agent's board comes
out like a person's. -
DRC:
wire-over-joint. A bare wire or a bent lead lying across a pin of another net,
or across the soldered end of an insulated wire, is a short at the bench that neither the
netlist nor LVS can see, because a wire is joined only at its two ends. The router already
refused to lay one; a wire drawn by hand, or a part moved under an existing one, now gets
an error. Six of the fifteen golden fixtures carry one, which the original engine never
checked, so the rule joinsPYTHON_ONLY_RULESand is pinned there.
Changed
-
A netlist is imported into the design, not onto whatever board is open. Its parts
used to land on the board after a question, beside what they connect to — skipping the
choice of board and leaving a first-pass placement nobody would keep. They now arrive in
the design with their values and pin names, the sheet comes forward, and Choose a Board
and Place on the Board take them from there. -
Add a Part offers the catalog first, from the Parts panel's own tree: typing 555
finds the NE555 and gives it its value, its pin names and U as its letter, where it used
to list sixty-one packages with a crystal first and Y1 in the reference box. A value that
names a catalog part in the chosen package brings its pinout too. -
The board's tools are on the toolbar only while the board is in front. With the
sheet in front the bar offered solder-trace and jumper tools, and a Rotate and a Mirror
that acted on the board's selection beside the sheet's own. -
A net is classed by its name until somebody picks a class: GND typed in New Net, a
pin labelled GND, or N3 renamed GND is a ground net and drawn as ground symbols, where it
used to be a signal wired to every part. -
References on the board sit over their part, on a plate, instead of at the corner of
the courtyard across the next row's pads -- and over every part, so a crowded board no
longer prints "X12" as "X1" with the next part across the rest. -
The schematic keeps its lanes out of the text. Every row has room above for its
references and below for its values, so no trunk runs through "NE555" or "10nF"; net
names are placed clear of each other and of the parts' text; every power glyph says which
supply it is; and the panel draws text at the size the layout left room for, re-fitting
the sheet as the panel finds its size until somebody zooms (it used to fit once, while
the panel was still small, and stay there). -
What just happened is said in the window's language. A command describes itself in
English -- that sentence is the undo label, the journal line and what an agent reads -- so
a Turkish window's status bar said "Add J1 PWR to the schematic" and its Edit menu "Geri
Al Place and arrange 8 part(s)". Every sentence the commands, the planners and the
window's own labels produce is now recognised where it is shown and said in Turkish
("Şemaya J1 PWR ekle", "7/7 nette 14 bağlantı yönlendirildi"), a conductor in the guide's
own words. A test runs a session of nearly every command and fails on any sentence that
comes back untranslated. -
Qt's own buttons speak the window's language: OK, Cancel, Close, Yes and No are
Tamam, İptal, Kapat, Evet and Hayır in Turkish. -
The example boards are routed the way Ctrl+R routes, and the README shows the
application as it is.tools/build_examples.pyrouted with the engine's default, which
lays each wire as one straight run because that is what every golden route records — so
the first boards a stranger opened from File ▸ Open Example were the cat's cradle of
diagonal wire the window itself stopped producing when wires were laid along the grid.
All six are rebuilt with the window's settings and the current router: no diagonal wire,
every net closed, no DRC error, LVS clean. Three carry one R5' warning each, a trace laid
beside another net's pin, which the guide turns into a check. The README's pictures and
the assembly animation are regenerated from them, so they show wires along the grid and
solder drawn as solder. -
The potentiometer and the relay look like the parts in the bag in 3D. Neither has a
borrowed model, and the generated bodies were a blue disc with a peg on it and a plain
box. The potentiometer now has its steel cover crimped over the housing, a threaded
bushing and a knurled shaft with a screwdriver slot; the relay a case with rounded
corners standing on its feet. Both carry their value in print, as the real ones do —
across the relay's top, stamped into the potentiometer's cover. -
Solder and wire look like solder and wire in 3D. A run of solder was a round grey
tube with bulges, a wire's end a ball on its pad, an insulated wire a coloured pipe with a
mitre at every corner, and the leads came out of bare rings as if nothing had been
soldered. A run is now a low bright ridge swelling into a dome on each pad; every lead on
the solder side and both ends of every wire sit in a cone of solder, with the trimmed
lead standing proud of it; an insulated wire is stripped at each end over its tinned
core; and wire is bent round its corners and down into its holes. -
Solder traces go straight instead of in staircases. Nothing in the search priced a
bend, so a trace that stepped one hole across and one hole down, over and over, cost
exactly what an L of the same length did — 77 one-hole steps in the solder-first routing
of the examples. In the Solder and Lead-bend styles a bend now costs a hole's worth, and
a hop over an obstacle 16 rather than 10, so straightening does not simply buy jumpers.
Over the examples and the NE555, solder style: bends 273 → 186, trace length 1306 → 1335
holes, jumpers 46 → 49, nothing left unrouted; lead-bend: bends 238 → 142, length 1127 →
1024 holes, jumpers 46 → 41. Lead-bend also puts solder before wire as it always said it
did, where it had left the two to the cost table. Balanced routing, and every golden
route, are unchanged. -
Solder-first routing lays far fewer jumpers. The planner routed ground and power
first, and for a builder committed to solder that rail is a wall: a trace cannot cross a
trace, so every signal beyond it hopped over with a piece of wire. A builder who chose
the Solder or Lead-bend style — or allows no wire at all — is now also given the plans
two other net orders produce, and the one cheapest to build wins. Over the examples and
fixtures, 60 jumpers become 51 (NE555 4 → 1, lpb1-booster 5 → 2), and with no wire
allowed 34 connections left for the builder become 27. No board comes out worse;
Balanced and Wire routing, and auto-place, are exactly as they were. -
Every export asks where it goes. The build guide, the schematic, the 1:1 PDF and
the 3D snapshot wrote fixed names beside the board — or into whatever folder the
application started in, for a board never saved — and replaced what was there without
a word, behind menu items whose "…" promised a question. Each now opens the save
dialog beside the board with the name it used to write, so accepting it does what the
menu always did; its companion files go beside the one chosen, and a board with no
file yet starts where the last export went. -
The findings panel says what is wrong in words. A rule's row read
"component-body-overlap (error)"; it reads "Parts overlap (error)" now — translated —
with the rule's id in the tooltip and still matched by the filter, and LVS's kinds
likewise. A test reads every rule id out ofdrc.pyso a new one cannot appear untitled.
The DRC, LVS and to-route counts on the status bar open the panel that explains them,
and the DRC count no longer carries its run time, which is in its tooltip. -
Routing takes a third less time, and auto-place two fifths less, with every route
and placement exactly what it was. The trace searches' open list is a heap that pops exactly
the node the original's linear scan did (lowest f, then earliest pushed); a document's
physical nets are remembered for the last one asked about; the autorouter asks for the
ratsnest of the one net it is routing instead of the whole board's, after every
connection it lays; and whether a trace may pass a hole is worked out once per route.
The placer no longer scores the pairs of parts nowhere near each other, whose every term
is exactly zero — three million evaluations per placement of a large board. Measured on
one machine against the code before the first of these changes:atmega328-relayautoroute
1.75 → 1.16 s and auto-place 16.4 → 9.4 s,nano-relay0.63 → 0.40 s and 6.1 → 3.8 s. -
The Turkish interface has one word for routing. "Route" and "Trace" were both
"Yol" — a menu and a drawing tool named alike — the Autoroute button read "Oto-yol"
(a motorway), and the rest said "route et" half in English. Routing is now
"yönlendirmek" and a trace a "lehim yolu" throughout, and the Turkish menu bar has a
letter each: three menus shared Alt+Y and two shared Alt+Z.tests/test_i18n.pyholds
both.
Fixed
-
A reopened board no longer refuses its next part. Ids were counted back out of a
loaded document for components, copper, cuts and nets only: a board saved with a part in
its design refused the next Add a Part as a duplicate of "part-1", and every new board --
which opens with its corner holes -- refused its first extra mounting hole. Every kind of
generated id is counted now. -
The build guide panel said where twice and showed neither. Each step read "R1 240 —
J21 → J18, 3 holes apart" beside a Where column saying "J21 → J18, 3 holes apart" again,
and in a dock a few hundred pixels wide what was left of it was "R1…" and a phase called
"1. Lowes…". A step is now one line — the part or the connection first, its holes once —
with phase headings in full, and the panel, its summary and the 3D caption speak the
window's language: "GND · çıplak tel — C14 → B10" under "6. Lehim yüzü". -
The Parts panel named its packages by their ids. Below "Transistors" and "Diodes"
came "axial cylinder", "box film" and "to92", in both languages and in alphabetical order
of the id, and every part under them was named in English in a Turkish window. The
groups are named as the catalog's are — "Axial resistors and diodes", "Film capacitors"
— in the order parts go on a board, and a part's name is shown in the window's language
wherever the window shows one: "Direnç (eksenel, 3 delik açıklık)". The engine's names
do not change (they are in the footprint golden); the panel recognises the engine's
phrasings, and a test fails on a library part named in words it does not recognise.
The filter finds a part by either name. -
--headless --lang tr board.perflooked for a board called "tr". The window's
command line was fixed for exactly this once, and the headless run kept its own copy of
the old rule — every argument not starting with--— so the language's value became
the document. It reads the command line the way the window does now. -
The build guide counted a wire's corners as pads. A wire laid along the grid keeps its
bends in its path, and the step card called each one a pad — "bare wire · 25.4 mm · 4
pads" for a wire soldered at two ends, which reads as two more joints to make on a wire
that would short whatever it lay across there. A wire now has two pads however often it
turns, and its corners are listed as its Path, which is what they are. -
A ground symbol could be drawn inside a power symbol on the schematic. Where a
ground rail from the row above and a power rail from the row below met at one point of a
channel, the lane above went to whichever net's id sorted first — ground, usually — and
the two glyphs, pointing at each other a lane apart and a column across, drew their bars
into each other: stacked lines that read as a battery. It happened on five sheets,
nano-relayamong them. Power takes the upper lane now, so both point away, and a test
holds every glyph on every sheet clear of every other. -
A window a little too narrow for the toolbar lost every word on it. The toolbar
needs 1536 px with its words in English and 1624 in Turkish, and the rule was all the
words or none — so on a 1920 screen at 125 % a Turkish window dropped them all to be 90
px short, and Trace, Spine, Bare and Insulated, which are one drawing differing only in
what runs between the pads, became four identical pictures. The words now go one button
at a time, the pictures everybody reads first (save, undo, delete), the views next to
last and the conductor tools last of all: at 1536 px only six buttons lose theirs, and
at 1280 px the four conductor tools still have their names. -
Ten explanations were English in the Turkish window. The Draw menu's five tools and
the five routing styles explain themselves on hover, and the tables they came from
handed the text over as a variable, which the catalogue's check reads past. They are
translated, and a new test builds the window in both languages and compares every menu
tooltip somebody wrote, however it was built. -
A part dragged onto the board had no shadow where it would land. Dragging from the
Parts panel or the sheet showed only the list's icon, at a fixed size and centred on the
pointer, while the drop puts the part's first pin in the hole under the pointer — so the
picture was neither where the part landed nor its size. The board now draws the part at
its real size and way round, in the holes it will take and red where it cannot go, and
the picture travels beside the pointer instead of over it. -
Pressing Autoroute or Auto-place a second time did nothing. Autoroute on a finished
board said there was nothing to route, so changing the connection style or the crossings
and pressing it again changed nothing; it now plans the board's routing again with the
settings as they are — asking first, because it rips copper up — and says so when that
comes out exactly as it is. Auto-place searched from the same seed every time and found
the same answer; every press now searches from a new one, the seed is still shown with
the result, and an unchanged result stays on the status line instead of timing out. -
Moving a part on the schematic took every wire off the sheet. The first move fixes
the sheet's layout so nothing else jumps, and a fixed sheet draws only the wires
somebody drew — none — so every connection turned into a net label and read as cut,
though the circuit was untouched. The layout's wires now come along as drawn wires in the
same undo step, line for line with their dots, and a moved symbol drags the ends of its
wires with it. A drawn net is named once over its longest run, as the laid-out sheet
names it. -
The schematic panel drew every label in the opposite corner. The drawing says
which end of a label's text is at its point, and the SVG export reads it that way;
the panel handed the same words to a text helper that aligns inside a box centred on
the point, where they mean the reverse. So net names sat left of and below their
point — across the wires the layout had kept clear of them, and off the sheet's left
edge ("XTAL1" read "TAL1") — references hung under their symbols, values stood over
them and pin numbers were on the wrong side of their leads. The panel and the export
now put every label in the same place. -
A net name with no room above its wire went back to where the wire branches. When
no step along a run cleared the band above it, the name returned to the run's left-hand
end — where the branches drop to the pins — with a wire through it. It now tries the
band below the run, taken only with a clearance's worth of nothing under the text as
well (so it cannot read as another run's name, or sit underlined on a rail glyph), and
failing that stays above where the fewest wires cross it. Onnano-relayBASE and
LED_ON come clear; nothing else on the shipped boards moves. -
The HC-49 crystal's footprint was a third of its length. It had the can as
4.65 × 3.5 mm — its thickness along the leads and a height across them — where an
HC-49/U is 11.05 × 4.65 mm on the board, so onatmega328-relaythe crystal stood on
one of U1's pins and DRC said nothing (the 3D view, drawing the real part, showed it).
The footprint is the real size now, recorded as a divergence from the original engine's
golden with a test of its geometry, and the example's crystal moved two holes clear
with its four connections re-routed. -
A 9 mm resistor (
r-axial-6) was drawn with a 6.3 mm body in 3D, while KiCad's 9 mm
model at its own pitch sat unused. It has that model now;r-axial-5keeps the 9 mm one
because KiCad draws nothing shorter at 12.70 mm, and a test holds every axial model's
barrel to its footprint's length, that one exception named. -
An electrolytic's minus stripe was shaded as dull khaki metal in 3D, because the
model converter took its colour for the can's aluminium top. It is print on the sleeve
now, in the colour the 2D view draws it; the minus signs KiCad prints down it keep
theirs. A polarised borrowed part's mark is its biggest printed piece — a diode's band,
a can's stripe — so the rule that fixed the diode's double band covers both. -
Bare metal clipped to a flat white slab in 3D — a crystal can, a TO-220's tab —
seen from the side. The render now ends in an exponential tone curve, exposed so the
board's overall colour does not move; an HC-49 close-up went from 17 861 clipped
pixels to none. -
The window did not fit a laptop screen. The status bar's labels each insisted on
their full width, which made the window's minimum wider than 1280 px; the toolbar with
its words is wider still, so the view switches went behind the overflow arrow; and the
Parts and Nets panels came up about 170 px wide, with no room for a net's name. The
labels may now clip, the toolbar drops its words when they do not fit (every button
keeps its name in its tooltip), and the side panels keep 240 px. -
About thirty messages stayed English in the Turkish interface. They were built as
f-strings, which the catalogue scan never reads — "Cannot place there", "Nothing to
route", the unrouted-connections report, the auto-place confirmation, the export
errors, the About box. They are translated now, the auto-place confirmation says what
was done rather than "router cost 812 (seed 0)", andtests/test_i18n.pyreads every
argument that reaches the status bar or a message box for English not()touches. -
Selecting a net lit its ratsnest and nothing else. On a finished board there is
no ratsnest left, so choosing GND in the Nets panel changed nothing anybody could see.
The net's copper now glows in the ratsnest's highlight colour, on either face, judged by
what the copper actually joins — a wire drawn by hand carries no net, and it lights up
if it lands on the net's pins. -
Exporting the build guide or saving a project froze the window. The 3D picture for
every step was drawn behind a wait cursor, on the belief that it took under a second;
atmega328-relay's 83 steps take about forty, and Windows calls a window that has not
answered for five "Not Responding". A dialog now counts the pictures as they are drawn,
and Skip the Pictures writes the guide without them — never with only some.
Exporting the schematic, which takes seconds, shows a wait cursor instead of nothing,
and the 3D panel redraws after the last edit of a burst rather than after every one
(a third of a second each onatmega328-relay, so a held arrow key lagged behind). -
Pressing Board on the toolbar closed the board. The Board, Schematic and 3D buttons,
and Ctrl+1–4, were the panels' own open/close switches, lit while a panel was open
rather than in front. The board and the sheet start stacked in one tab group, so both
were lit, and pressing Board to get to the board put it away. They now bring their view
forward and never close it; opening and closing a view is View ▸ Panels, where a check
mark says which are open. -
Copper on the far face was hard to follow in 2D. On the component side -- the side
the editor opens on, and so most of the copper on most boards -- a run was drawn only as
thin hatch strokes over a busy grid of pads, and zoomed out it thinned to nothing. A faint
solid band now goes under the hatch, so the run reads as one length of copper while the
hatch still says "on the other side". -
The router could short two nets through a wire's soldered end. An insulated wire is
soldered down at both ends, but it does not block the copper plane, so nothing marked
those holes as taken. Where two insulated hops met on an empty pad, the next net's solder
trace ran straight through it: routingatmega328-relaysolder-first tied +5V to XTAL1 at
L19. LVS reported the short and DRC did not. The router now treats every wire end like a
pin — a trace may not run through one and a bare wire or a bent lead may not lie across
one — and no golden route moves. The random-netlist property test, which only ever asked
the default style (the one that never hops), now runs all four. -
The 3D view cut the board off. The camera fitted a bounding sphere, zoomed in by a
fixed 1.35 and then tilted, in a window it had not been given yet, so every portrait board
lost its near edge off the bottom of the frame and its far edge off the top when flipped
(atmega328-relay's corners landed at y −87…914 in a 950 px picture). It now fits what is
drawn, after the tilt, to nine tenths of the window's own shape: the panel on its first
real resize, the offscreen render and the guide's step images once their window has a
size. -
An LED's flat stood on its anode in 3D. KiCad numbers the cathode pin 1 and puts the
flange's flat on it; this application numbers the anode pin 1. The three LED meshes are
now converted turned end for end (tools/import_kicad_models.py, re-run against KiCad
10), andtests/test_model_leads.pymeasures which side the flat is on. -
Diodes had two cathode bands in 3D: the borrowed mesh's own, and one more printed at
the very end of the barrel. The mesh's band is kept, where the real part has it, and
painted in the colour the 2D view draws it. -
The underside legend labelled the wrong columns in 3D. It was reflected about the
hole span on top of the camera turning the board over, so it was mirrored twice: column A
carried "AH". Each glyph is now reflected about its own centre and stays under the hole
it names — and a one-edge legend stays on the same physical edge as in the 2D view. -
Pin headers had nothing on the solder side in 3D. The borrowed pin is cut at the
board surface like every model, and the part of it that goes through the board was the
one thing a header did not get. -
R did nothing while the schematic panel was open and a part was selected on the
board. The board's Rotate and the sheet's Turn were both shortcuts on R, and Qt answers
two live shortcuts on one key by firing neither. R now belongs to the board window-wide,
and the sheet takes it back while it has the keyboard — R and Shift+R turn its selected
symbols either way. -
A board opened after a blank launch came up as its schematic. The blank launch puts
the sheet in front, the session remembered it, and nothing put the board back. A board
with parts on it now opens on the board; a design with nothing placed opens on the sheet. -
Auto-place said "~-64 mm less connection length" when the estimate had grown. The
winner is chosen on what the board costs to build, not on straight-line length, so the
estimate can rise; it is now worded by its sign. -
Re-route asked with Yes under Enter, and it is the one question that rips up
copper. It goes through the same box as every other destructive question now — Cancel
under Enter, the verb on the button — and its text is translated. -
The empty board's hint gave the Parts panel's key for the Schematic (Ctrl+5, not
Ctrl+2), and a test now holds the hint to the action's real shortcut. -
A header's pin marks had an invisible outline in 2D:
"#00000060"is read by Qt as
#AARRGGBB, a fully transparent blue. A test now refuses an eight-digit colour string
anywhere in the interface. -
The Undo button grew with the command it named — "Undo Autoroute 7 nets (14
connections)" — and pushed every button after it along the toolbar. The button keeps
its one word; the menu and the tooltip still name the command. -
Borrowed parts were shaded in flat facets — an LED's dome, a can's side — because the
meshes carry no normals. They are computed once per mesh when it is read, with a feature
angle that keeps real edges sharp.
Windows - PerfboardStudio_..._Setup.exe. It is unsigned, so SmartScreen will
warn on first run: More info -> Run anyway. A signed build is planned.
Linux - perfboard-studio-...-x86_64.AppImage. chmod +x and run it; it needs
glibc 2.35 or newer. If it will not start, the machine has no FUSE 2: install
libfuse2, or run the file with --appimage-extract-and-run, which unpacks it
instead of mounting it.
macOS - perfboard-studio-...-arm64.dmg, Apple silicon. Drag it to Applications,
then run this before opening it:
xattr -dr com.apple.quarantine /Applications/PerfboardStudio.app
It is signed ad-hoc but not notarized, so Gatekeeper blocks the first launch.
On macOS 15 and later the dialog it raises defaults to Move to Trash, which
deletes the install. Clearing the flag first avoids the dialog entirely. On an
Intel Mac, install from source.
Anywhere with Python 3.12+: pip install -U perfboard-studio, then perfboard-studio.
Same release, no installer and no SmartScreen warning; Qt and VTK are most of a
400 MB download the first time.
Checking your download - SHA256SUMS carries the SHA-256 of all three
files. sha256sum -c SHA256SUMS on Linux, shasum -a 256 -c SHA256SUMS on
macOS, Get-FileHash <file> in PowerShell. Perfboard Studio does this for you when it
fetches an update itself: Help - Check for Updates. It proves the file
arrived intact, not who built it - that second claim needs the code signing
this project has not bought yet.
This is pre-alpha software. Nobody has yet built a real board by following a
generated guide - check every measurement against the part in your hand.