Changelog

Newest first.

1.16.0

  • The published site is the tool now. It runs ngspice. Every circuit on the page is simulated in your browser — the four SKY130 amplifiers included, against the foundry's own transistor models — and nothing is sent anywhere: there is no API behind the page and there never was. What used to be a shopfront that redrew schematics and asked you to install something is a circuit simulator you can open a link to.
  • The design decision that made it worth doing is that there is no second implementation. A JavaScript rewrite of the netlist builders and the measurement code would have been a tenth of the download, and would have started disagreeing with the server the first week either was edited. Instead CPython runs in the page next to ngspice, and it runs Faradaem's own spice package unmodified — the same builders, the same parsers, the same measurements, the same verdicts. The package is standard library only, which was a rule kept for years for other reasons, and it turned out to be the thing that made this a week's work rather than a rewrite.
  • The awkward part was that Python expects to call a simulator and have the answer before the next line, and WebAssembly ngspice answers through a promise. Blocking on it needs SharedArrayBuffer, cross-origin isolation and a second worker to be blocked from; making the pipeline asynchronous forks it in two. spice/detached.py does neither: it runs the pipeline twice. The first pass has a simulator that refuses every deck and reports the one it was asked for; the browser runs that deck; the second pass replays the results through the ordinary code path. Building a netlist is a pure function of its parameters, so the second pass asks for exactly the deck the first did. Planning simulates nothing and is counted as nothing, so a plan and its finish cost one simulation between them rather than two.
  • Underneath it, the two places that started an ngspice process became one. runner.py had the same fifty lines twice, once for decks that print and once for decks that write files, and every difference between them was an opportunity. There is now one function that runs a deck, one place a simulation is counted, one place a budget stops one, and a seam where a different simulator can be installed — which is what the browser does, and what a desktop build will.
  • Nothing is taken on trust and nothing comes from a CDN. The runtime is 34 MB of somebody else's build — Pyodide and an MIT-licensed WebAssembly ngspice — fetched by tools/runtime.py, pinned by SHA-256, unpacked with the tar the operating system already ships, and never committed. Only the files the page loads are kept. It is fetched on the first measurement, not on page load, because someone who came to read about the tool should not pay for a simulator they did not ask to run. The SKY130 models are the model card from the release before this one, cut at build time from the same pinned PDK: two megabytes for four amplifiers, out of the two gigabytes it was cut from.
  • The claim is not "a simulator runs in a tab", which is a demo. The claim is that the published page measures what the local tool measures, and it is proved: every circuit is run through the file the browser actually loads, under node, and compared with the server. The simulator's own output is byte-identical — ngspice 45.2 in WebAssembly and ngspice 47 native write the same characters for all ten decks — and the shipped model card is byte-identical to the one this machine cuts. What Faradaem makes of those bytes agrees to within about five units in the last place of a double, because decibels and degrees pass through log10 and atan2 and two C maths libraries round the last bit differently. That is stated as it is rather than rounded up to "identical", and the bound is checked so a change that made it worse would be caught.
  • A discrete circuit measures in about eight milliseconds and a SKY130 amplifier in about two hundred, on a page you did not install. The five-transistor OTA returns an open-loop gain of 36.99553751811478 dB in the browser and 36.99553751811478 dB on the server.
  • The amplifiers lay out there too. Open the Layout tab on the published page and it places the devices in a row at the minimum diffusion spacing, splits the matched pairs into fingers around a shared centroid with dummies at the ends, guards each group, routes the nets on two metals, checks the drawn geometry against thirty-six process rules, compares the drawing against the netlist that was simulated, hangs the drawn interconnect back on the circuit to measure what it cost in margin, and hands you a GDS. The five-transistor OTA comes out at 97.5 square microns, clean on all 36 rules, all eight nets matching, 54 kB of geometry, in about a second once the runtime is up.
  • That needed one thing the two passes could not do: a layout is two simulations, the circuit as drawn and the same circuit with its own wiring loading it, and the second deck depends on geometry computed after the first. So plan and finish became a loop. The caller plans, runs whatever deck it is handed, and plans again until the operation stops asking; each pass replays what came before and re-runs the pure parts from the start, which costs microseconds and is what keeps the replay exact rather than a second implementation of the sequencing. One deck or five is the same to it.
  • The layout code needed no changes at all, because Magic's technology file ships with the page. Every dimension the floorplan places, every rule the checker checks and every GDS layer number is read out of that file at run time, so shipping the file rather than a digest of it means layout.py, drc.py and gds.py run in a browser without knowing they are in one. It is 168 kB, thirty of them over the wire. The foundry's own sign-off deck stays local and its button is not in the published page: that one is a Ruby runset inside a gigabyte of Qt, and KLayout's extraction is reported as not run rather than as a pass.
  • And the strategist came back to the published page. It is the thing the project is for and the one part that could not follow the rest into the browser, for a reason that has nothing to do with WebAssembly: talking to a language model needs an API key, and a key in a page is a key anybody can read in the network tab and spend. So the key sits on the site's own server, in one endpoint that will not hand it out, and the loop around that endpoint runs in the tab — because that is where the tools now are. The model asks for a measurement; your browser takes it with its own ngspice; the answer goes back for the next turn. It can choose a topology, seed a sizing, simulate it, measure its step and its rejection, lay it out and explain what it found, and every number in that is measured in front of you.
  • Everything that costs money is decided by the server. A caller sends the conversation and nothing else: the model, the token ceiling, the system prompt and the tool list are all chosen where the key is, because a client that could name its own model could name an expensive one. Two of the eight tools are withheld and the model is told why — the corner suite needs five process corners and the page carries one, and the optimiser would hold a tab for minutes — so it says those need the local app instead of spending a turn discovering it. The endpoint is off unless it is switched on deliberately: deploying the code is not consent to spend money, and a merge cannot turn somebody's key into a public endpoint by itself.
  • What that does not solve is written into the module rather than left for someone to find out. The caps bound the cost of one call and not the number of calls; serverless invocations do not share memory, so the rate limit in there is per instance and is a speed bump rather than a gate; and the protection that actually works is a spend limit on the API account, which is set where the key was issued. Anyone deploying this is making a financial decision, and it should be made with that in view.
  • And Faradaem became an application. python desktop.py picks a port nobody is using, starts the server in its own process, and opens the tool in a window with its own taskbar button and no address bar; python install.py --shortcut puts it in the Start menu, pointing at the interpreter that has no console behind it, with an icon assembled from the same drawing the pages use. Launching it twice opens a second window onto the first one rather than a second server, because two would mean two ledgers writing at once. There is no framework in any of this and no new dependency: Electron would be the same window and a hundred and fifty megabytes of second browser.
  • The one part that could not be done the obvious way was knowing when the window closes. Waiting on the process that opened it looks right and is wrong: a browser hands the window to whatever is already running and exits, measured here at twenty milliseconds. So the page says it is still there, every five seconds, and the app stops when the saying stops. It is a smaller mechanism than the alternatives and it measures the thing that actually matters, which is whether anyone is looking. Deliberately no goodbye on the way out, because pagehide fires when a reader clicks through to the manual as surely as when they close the window.
  • That heartbeat found the third instance of one bug in as many releases. Its script was added to six pages and to neither the published build's asset list nor the server's route table, so it answered 404 and the app shut itself down while its window was open. Nothing broke loudly; a page with a script tag and no route behind it renders perfectly and is simply missing a feature. Every page's script tags are now checked against what each deployment actually serves, which is the check that would have found this one, the layout panel's two, and the null write two releases before that.
  • Two bugs, one class, found by driving the built page. panel-layout.js bound the sign-off button that the published build does not ship, threw during start-up, and took the whole page with it: a blank form, no circuit tabs, from one null. Then it called fetch straight out for /api/layout, reached a host with no API, and got the 404 page back to parse as JSON. Both were fine for as long as that panel only ever ran locally. The invariants that were supposed to catch them read app.js and nothing else, which is a rule about one file rather than a rule; they now read every script the published page loads, and the panels are handed the null-safe helpers and the one API door instead of being trusted to remember. And a figure caption that had said "nothing here has been design rule checked" since before there was a rule checker now says what is actually checked, because it was sitting directly under a verdict reporting thirty-six rules clean.
  • Then the rule was moved one step earlier than the bug it was written for. Checking only the scripts the published build ships leaves every local-only script one line of build_static.py away from repeating panel-layout.js's second bug, and catches it the release after the promotion rather than before: twenty-five bare calls were waiting across six files, thirteen of them in the datasheet panel alone. All of them go through the door now. The two pages that are not the tool — the notebook and the printable datasheet — do not load app.js, so there is no door there to borrow; each declares its own, reading the same mode stamped on <html> and refusing rather than answering, because a ledger and a stored datasheet are files on the machine that measured them and a published copy of those pages would have nothing to read. The check globs static/ instead of reading a list, because a list is a thing to forget to add to and the file it was forgotten for is exactly the one nobody checked. It reads the shape of the call, so it did not catch the one that passed its path in as an argument; that one was found by reading the file, which is what a shape check exists to make unnecessary and does not entirely.
  • The page got its controls back, and the policy got tighter about what it admits rather than looser. Run, the netlist view and the Bode plot were deleted from the published build two releases ago because they could not work; they work, so they ship. The Content-Security-Policy gained wasm-unsafe-eval, which permits compiling WebAssembly and nothing else — eval and new Function stay refused, and a test spells the two apart so the narrow keyword cannot quietly become the broad one. Enforcing it found a real bug: the Bode trace's draw-in animation wrote a style attribute, which the policy correctly refuses. It uses an SVG attribute the format already has instead, which is simpler than what it replaced.
  • What is still local is stated per circuit rather than per deployment, and read from the catalogue rather than guessed in JavaScript: the page knows which circuits it can measure because the build wrote it down. The strategist, the layout, the foundry deck and the notebook remain local, and the manual marks them — but "Running a simulation" is no longer marked, because the published page runs one. Three mode-marker pairs went away entirely: the footer used to say "this published demo does not run simulations", and the sentence that replaced it is the one the local build already had.
  • And the wiring is extracted now, off the polygons, rather than estimated from a length. What was there was not so much wrong as a different quantity: a net's interconnect was its total run in microns, times metal1's area constant, at metal1's minimum width, hung on that net as one capacitor to ground. Three things about that were untrue of the drawing it described. The stubs are drawn a via pad wide and were priced at a metal1 width, so nearly half their area was missing. The tracks are metal2 and were priced as metal1, which is a different constant on a different plane. And every net's capacitance went to ground, so a metal1 stub crossing another net's metal2 track — which happens fifty-nine times in the five-transistor OTA — contributed nothing at all, in either direction.
  • spice/extract.py reads the rectangles instead. Area, perimeter and overlap come off the drawn geometry at the constants the technology file states for the plane each piece of metal is actually on; shielding and coupling are one calculation rather than two that have to be kept agreeing, because a conductor is charged against the substrate only over the area where nothing nearer is in the way, and the part that is in the way is charged against whatever is in it. So a wire over the n-well couples to the well's net instead of to ground, and a supply wire over a well tied to that supply stores nothing at all, which is correct and which no length could have expressed. The extraction reaches the transistors' own poly and diffusion as things that lie underneath, and never as things to charge: the SKY130 models already carry those, computed from the same W and L that drew the polygons, and extracting them again would count them twice and count them worse.
  • Resistance goes in the deck as well, which meant the deck had to be rewired. Every drawn pin gets a node of its own and is joined back to its net through the metal that actually connects it: up through the contact, along the stub, through the via, onto the track, and along the track past every other pin. The node that keeps the net's own name is the one at the electrical middle of the track, so the load capacitor and the bias source, which are not on the die and which nothing in the drawing places, attach in the middle of the wire rather than at an end. The rewrite refuses rather than guesses: a pin the deck has on a different net than the layout drew it on stops the whole thing, because rewiring on top of a disagreement would bury it.
  • Three proofs, because a new number that nothing checks is a new number to be wrong about. Collapsing every added resistor has to give back the deck it started from, element for element and token for token, which is exact and needs no simulator: if the rewrite ever changed the topology, no amount of agreement in the measured values would show it. The resistance agrees with KLayout's own square-counting extractor over the same rectangles to two parts in a million, both sides now asking one function which stubs count and where the current enters and leaves, so what is left to disagree about is the measuring. And run over the drawn compensation capacitor, which was built by sizing two plates so that area times the overlap constant is the value asked for, the extractor recovers 2.0000023 pF from geometry it knows nothing about, to a part in a billion.
  • That third proof was also a bug. The extractor had found the capacitor, and the deck already had it as an ideal element, so the drawn one was being counted twice: two picofarads of compensation became four. Drawn passives are declared now and the term the deck already holds is dropped, while the terms it does not — the bottom plate over the substrate, and 55 fF of fringe between the plate edges — are kept. The nulling resistor had the matching problem from the other end: a strip of poly and a resistor are the same drawing, and the net extractor walked straight through it and reported its two nets as one. It is declared too, and lvs.extract grew the ability to be told that a rectangle is a device rather than a wire.
  • What it costs, measured: the OTA's interconnect goes from 31.9 fF estimated to 22.6 fF extracted, of which 8.0 fF is coupling between nets rather than load to ground, plus 452 Ω of metal. The folded cascode goes from 461.7 fF to 271.9 fF and 1884 Ω. The two-stage stays about the same in total, 631.5 to 640.6 fF, and moves underneath: 103 fF of it turns out to be coupling, and 57 fF of that is between the compensation capacitor's own two plates, which is in parallel with the compensation and helps. The lumped model had no way to say that, so it read the drawn network as costing three and a half degrees of phase margin where the extraction measures eight tenths of one.
  • And one measurement the model it replaces could not make even in principle. A capacitor to ground carries no direct current, so hanging one on every net changed the power the folded cascode draws by exactly 0.000%, every time, whatever the wiring was. Metal has resistance, and the folded cascode's supply is 852 microns of it across nineteen nodes, 99 Ω end to end and 42 Ω between its furthest two pins: the extracted circuit draws 0.098% less and its output sits 23 microvolts lower. That is an operating point moving because of the layout, which is the thing post-layout simulation is for and the thing the old number could not report.
  • And it went live, which found three more things. The published site is built here and uploaded rather than built by the host, because cutting the model card needs a two gigabyte PDK that a build image has not got: a host-built site measures six circuits instead of ten and has no Layout tab, and it would not fail, it would quietly publish less. An uploaded directory is its own deployment root, so the build now writes the host's configuration into the output rather than leaving the headers to be remembered; a Content-Security-Policy that ships only when somebody pastes it is not a policy. Checking the result on a preview deployment before promoting it found that the vendored runtime's year of immutable caching had never once applied: every matching header rule is used and the last one wins, and the general rule for /static/ was written after it, so 34 MB revalidated every hour. And the repository's requirements.txt turned out to be UTF-16, which pip cannot read at all — harmless while nothing installed from it, and about to stop being harmless.
  • What is not extracted is on the page next to what is. Coupling between two wires side by side on one plane is measured and reported and is deliberately not turned into a capacitance: the technology file states it as a value and a distance, and does not say what the distance is for, and Magic has no Windows build to check an interpretation against. The facing length, the gap and the constants that would price it are all reported, so the size of the omission is visible rather than described — fifty-four pairs sharing edges on the folded cascode. Ground's own resistance is drawn, reported, and not simulated, because SPICE's node 0 is the reference by definition and splitting it would mean deciding which piece of the substrate is the real zero. And the whole thing is priced at the PDK's own wiring corners as well, which costs no simulation at all, because extraction is arithmetic over geometry that has already been worked out.

1.15.0

  • A SKY130 simulation takes half a second instead of sixteen. Almost all of that sixteen was never the circuit: asking the kit for its typical corner loads models for every device SkyWater makes, five flavours of low voltage transistor, the 5 V and 20 V families, ESD devices, bipolars, varactors, flash cells, RF variants, a shelf of diodes and every metal capacitor, and Faradaem instantiates exactly two of them. The rest were parsed, binned and built for nothing, on every run. spice/modelcard.py now writes a card that carries the two, by resolving each corner's include tree inline and leaving out every file that names a device the tool does not draw. That is the whole rule, and it is mechanical rather than a hand-picked list, so a kit that renames a file is caught rather than quietly half-copied.
  • What it buys is not a nicer number in a log. Measured on the five-transistor OTA: the eleven-condition robustness suite went from 176 seconds to 5.7, which is 16.0 seconds a simulation down to 0.52. Everything built on top of a simulation scales the same way, because the saving was never in the circuit. The test suite itself fell from twenty-seven minutes to under five, and that is after adding three and a half minutes of comparison against the full library to it. Work that was technically possible and practically not worth starting is now something you can watch happen.
  • The card is derived data and is treated as such. It lives beside the ledger under ~/.faradaem, never in the project and never in the kit; it records every file it was cut from, with size and timestamp, and is rebuilt when any of them moves, the same staleness rule Python uses for a compiled module; it is written a file at a time with its stamp last, so an interrupted build reads as stale rather than as a card half a release old. The installer writes one as its final step, so a new machine is fast from its first run, and any run that finds none writes one for itself. If it cannot be built at all, the foundry's own library is used, which is slower and correct, and the doctor says so.
  • Trimming a model library is exactly the kind of shortcut that is fine until it is not, so the equivalence is proved rather than asserted. Both devices are swept across seven geometries and the full gate and drain bias plane at every corner the tool runs, and the four SKY130 circuits are measured end to end, against the card and against the foundry's library, and the numbers must match as written text rather than within a tolerance: two thousand five hundred and forty-eight numbers per corner, and every one identical. The mismatch section is compared under a fixed seed, and a second test confirms a different seed gives different numbers, so that comparison cannot pass by being accidentally deterministic. Set FARADAEM_FULL_PDK=1 to read the foundry's library on every run, which is the thing to do whenever a result is in doubt.
  • The device set is closed and a test keeps it that way. A topology that reached for a third device would build a netlist the card cannot simulate, so every model name written anywhere in the package is read and required to be one the card carries: adding a device turns the suite red rather than a run. The corners are named once now, in the module that has to write a section for each of them, and a corner is retargeted by the shape of the library line rather than by the library's filename, because the card and the kit sit at different paths and a robustness run has to work against either.

1.14.1

  • The published page says what the strategist is for. The release before it had deleted the panel outright, on the correct reasoning that a control which cannot work should not be painted and then taken away, and the wrong conclusion that the shopfront should therefore go quiet about the part of the tool most worth seeing. A reader arriving at the demo saw a circuit simulator and no sign that anything asks for a design. The panel is still absent, because it still cannot run there, and in its place is a description of what it does when it can.

1.14.0

  • Setting up a new machine became one command. python install.py fetches the two things Faradaem needs and is not, the console build of ngspice and the SKY130 process design kit, verifies every archive against a pinned checksum, and unpacks them into ~/.faradaem/tools, which the resolvers now look in. Nothing goes on PATH, nothing needs an environment variable, and nothing is installed with pip: the archives are unpacked by the tar the operating system already ships, which on Windows reads both 7-Zip and zstd without help. The old route was an afternoon and five chances to be subtly wrong, and the failures arrived one at a time, each after a simulation that would not run.
  • The kit shrank from 2.2 GB to 21 MB, because Faradaem is an analog tool: it needs the technology files and the primitive devices, and none of the standard cells, IO pads or SRAM macros that the gigabytes are. Trimming it that far had one trap worth recording, since it is invisible until a transistor appears: the technology archive alone loads happily and then stops on the first device, because the corner files include the models by relative path out of their own directory. The installer now resolves those includes before it will accept a tree, so a release that moves them fails during the install, with something useful to say, rather than during someone's first simulation.
  • Nothing unverified is ever kept. Every archive is pinned by SHA-256, because a binary that is about to be executed is not taken on trust; a short read is reported as the server cutting off rather than as a substituted file; and a bad mirror costs a retry rather than the install, which the pin makes safe. --list prints every URL, size and checksum and fetches nothing, for anyone who would rather read before trusting. Builds you already have still win: FARADAEM_NGSPICE and PDK_ROOT outrank anything the installer wrote, and the installed copy in turn outranks whatever is on PATH, because it is the one Faradaem pinned. Where no official prebuilt binary exists, the step says "unavailable" and names your package manager instead of failing.
  • The pieces around it were told about it. The doctor's fixes are now one command rather than a paragraph of setup, and it is the doctor that reports the result, since it stays the single opinion on what a machine has. The ledger, the simulator and the kit share one home, so provenance can say which release measured a number: an installer-built kit has none of ciel's version directories, so the installer writes the release down where the ledger reads it. The container stopped needing a mounted volume and builds the kit in with the same script. The server now says at startup what is missing, because it serves its pages perfectly well without a simulator, so an unset-up machine looked fine right up until someone pressed Run. And the published site's note names the command, instead of linking to a repository and leaving the afternoon as an exercise.
  • The published site stopped pretending to be the tool. It used to work out that it had no simulator by asking for one: it fetched /api/circuits, got the host's 404, and only then took its own controls away, in front of the reader. So the demo painted "Ask for a design", a Notebook link and a Run button, then removed them; it made a request that could only fail, once per load; and what it removed was only hidden, so every server-only control was still in the document, still focusable, still read aloud. The deployment is now decided before the page is written. spice/deployment.py renders each page for its mode, deleting the other mode's markup outright, and stamps the mode on <html> where the first line of script reads it. Nothing flashes, nothing focusable lies, and the published build makes no /api request at all, which is enforced by shape rather than by promise: every server call goes through one function that refuses in the static deployment, so "no requests from the demo" is a property a test reads off the file instead of a claim about sixteen call sites.
  • /notebook was linked from the header and the footer of every page and was never built, so it answered with the host's own unbranded 404. It is a page now, and in the published deployment it says the true thing: the notebook is a reading of the ledger on the machine that did the work, this demo has never run anything, and here is how to run it. A branded 404 replaced the host's for every other missing path, in both deployments, and it carries noindex. Alongside it: robots.txt, a sitemap.xml listing all five routes, a canonical URL and an og:url on every page, and share images made absolute, which is the difference between a link preview and a blank one.
  • Importing a design stopped trusting the file. The old path checked two things about the envelope and then moved the page: it switched circuits, overwrote every input it recognised, cleared the result and started a simulation, discovering only somewhere in there that a value was the string "oops", or a hundred times the legal maximum, or missing. A rejected file left the reader holding a circuit they had not chosen, half filled with a stranger's numbers, under a message claiming it was being measured, on a site that cannot measure. Validation is now one pure function in its own file, handed the catalogue and asked before anything moves: size, JSON, a plain object, a supported schema, no unknown fields, a known circuit, every declared parameter present, none extra, each a finite number inside its declared range, a real ISO date. Imported measurements are read and dropped with a note saying so, because a number on this page comes from the simulator in front of you. A rejected file changes nothing at all and says exactly what was wrong, in a live region that takes focus. Being pure, it is exercised by eighty-six cases under node rather than asserted about.
  • The page remembers. Editing six values, reloading, and finding the defaults back was a small cruelty a browser has had the means to avoid since 2009; the last valid sizing per circuit now survives a refresh, namespaced and versioned, alongside the circuit in the URL hash. Valid is the load-bearing word: half-typed text is not a design, so clearing a field to retype it leaves the last good numbers standing rather than saving an empty one. Corrupt or foreign stored data is ignored rather than coerced, every access is wrapped so a private window or blocked site data means "no memory" and never a broken page, and a Reset to defaults button clears one circuit without asking a question nobody needed.
  • The circuit strip became a real tab strip. Arrow keys used to move focus and select nothing, so a reader arrowing along ten circuits heard silence until they guessed that Enter was needed; selection now follows focus, Home and End reach the ends, both ends wrap, and Enter and Space still work for anyone who expects them. Tab reaches the strip once instead of ten times. Each tab declares the panel it controls and the panel names the selected tab, which nothing did before. Driving it by keyboard is also what found the bug underneath: select() wrote to a label that only exists in the local build, so on the published site pressing End threw, the URL stopped tracking the circuit, focus was lost, and every further arrow key did nothing. One null write killed the tab strip, and the shape that allowed it is now refused by a test.
  • The numbers on the pages are counted from the code that owns them. The fast rule checker knows thirty-six rules; the home page said thirty-two, the README said thirty-two in one place and thirty-five in another, and the manual said thirty-six. Three of the four were wrong and nothing could notice, because each was typed by hand into a different file. Counts now come from spice/siteinfo.py and the pages carry tokens, so a page cannot disagree with the code it describes. The same pass fixed a claim that was simply false: "10 circuits, 3 of them SKY130 amplifiers", when four circuits are built on SKY130 and three of those are the topologies the strategist chooses between. Both numbers are real and they are different numbers, so the page states them separately, and the strategist's own prompt stopped miscounting them too.
  • The manual keeps every section on the published site and marks the sixteen that need a simulator, because a manual that hid them would lie by omission about what the tool is. Its keyboard section was rewritten to match what the code does rather than what it used to do. And one repository URL is written once and substituted everywhere: the hero, the notice, the footer, the About page, the notebook's empty state and every install link, with a check that fetches it unauthenticated, because a "Run it locally" call to action that 404s is worse than none.
  • Accessibility and layout, from reading the rendered markup rather than the source. Two form controls had no accessible name; a heading level was skipped; thirty-six release entries sat under one h1 with no heading between them; there was no way past the header for a keyboard, so every page cost six presses to leave; every plot was an unlabelled shape; and reduced motion reset animation durations but not the delays holding the hero invisible. All fixed, and held by a hundred and twenty-one checks over both deployments. On a phone the schematic was ordered above the controls, which pushed the first input to 1726 pixels and the sentence explaining what the demo can do to 1493, so a visitor scrolled past a drawing to reach both: the same mistake the hero made at this breakpoint two releases ago, and the same fix. Content-Security-Policy, Permissions-Policy and an anti-framing rule joined the headers the host already sent, and the pages were checked to actually live under that policy rather than needing it relaxed.

1.13.0

  • The studies arrived: five standing experiments that put analog folklore to measurement, run by study.py, every simulation counted at the subprocess and written to the ledger. Analog design is full of beliefs held because someone experienced said so; each study takes one and replaces the authority with evidence.
  • The capability atlas charts what a circuit family can actually be made to do. A grid is laid over two spec axes, the shipped design search runs at every cell under a budget, and each cell reports "met", carrying the sizing that proves it, or "not found within budget", which is all the evidence ever supports; the atlas never says impossible. The first chart, the two-pole amp over phase margin and crossover, met 20 of 25 cells in 231 simulations and correctly failed to find the five that ask a two-pole loop for more than 90 degrees. Charts store beside the ledger, like the datasheets.
  • Signoff became an attack. The adversary is given a simulation budget and told to break the design: five process corners, then the supply and temperature extremes on the worst one, then a local walk of both knobs toward thinner margin, then mismatch draws. Three verdicts only: "broken", with the condition named; "survived", always carrying its simulation count, because a number is the claim a checkmark never makes; and "unmeasurable", when a condition inside the operating envelope will not simulate, which is a finding and not a pass. The first live attack on the OTA's reference sizing survived 21 adversarial simulations and named the thin ice: gain margin rounds to +0.0% at the fast corner, 1.62 V, 125 C, a condition none of the eleven standard PVT rows sits on.
  • Forensics runs the simulator backwards. Given a sizing and a set of observed numbers, it searches process, supply, temperature and mismatch for the condition that reproduces them, names the space it searched, and reports "unexplained" with the nearest miss when nothing in it fits. It proves itself on blind trials whose answer it is never told: in the first live trials on the SKY130 OTA it recovered both drawn conditions exactly, one in 5 simulations and one in 13, at zero residual. Building it taught the module its own first lesson: a mismatched typical die reads as a mildly skewed corner unless the die is searched jointly with the environment, so it is.
  • The learning curve prices experience. Warm starts are harvested from the ledger by re-scoring stored measurements against the new targets, at zero simulations, and the curve solves every spec twice, cold from the geometric centre and warm from accumulated experience, under the same counted budget. On twelve two-pole specs the cold arm paid 102 simulations and the warm arm paid 20, one simulation per spec from the second spec on. Read honestly, that says this spec family is narrow as much as it says experience transfers; both readings are in the numbers, which is the point of having them.
  • The arena opens the four-way comparison's rules to any method that can be written as one function. A contestant gets the spec, the bounds, the seed rule and the simulator, never the registry sizing; its budget is enforced where the subprocess runs; and it is scored on the design it declares, re-simulated by the referee. The shipped optimizer enters under the same rules as anything else.
  • Ask for a design joined the page it lives on. The first sizing the strategist touches switches the schematic to the topology under design, so you watch the right circuit from the first seconds instead of whatever was on the bench before. While the search iterates, one status line updates in place with the simulation count and the worst margin, where before a forty-evaluation search was minutes of silence; those per-evaluation heartbeats also stopped flooding the event log, which could freeze the conversation past eighty entries. And when the strategist ends its turn, the last sizing that met every target lands in the form, the schematic redraws, and the bench measures it again, the contract the design panel has kept since 1.12.2. A turn that never met the spec loads nothing, and every card keeps its own load button. The strategist was also told about the page it works inside: asked to see the schematic, it now finishes the design or points at a load button instead of explaining that it has no drawing tool, and a complete request starts the flow instead of a menu of ways it could begin.
  • The bias landed on the schematic. After a SKY130 circuit measures, one more simulation reads every device's Id, gm, Vgs, Vds, Vdsat and saturation headroom at the bench's own operating point, and hovering a transistor shows its numbers beside it, the way engineers pencil them onto printed schematics. Values the model does not expose read "not exposed", never zero, and an edited sizing clears the annotations because they described the old one.
  • The workbench grew the conveniences engineers keep spreadsheets for. Hold a measured design as A and every later measurement renders the delta table, knob by knob and number by number, with A's frequency response as a faint trace under the live curve. A History row walks back through every sizing measured this session and restores any of them. Export design writes circuit, sizing, measurements and provenance as one JSON file, and Import selects the circuit, loads the sizing, and measures it again on the local simulator, never trusting the sender's numbers. Every value field reads 10k, 2.2u, 5meg and 4.7 pF, with the echo beside the label showing what the entry was read as. The printable datasheet opens with the verdict sentence and the schematic drawn from the stored sizing, so it reads as a design review. And long jobs report back: time estimates from the run's own pace, stop buttons everywhere including the autopsy, and a browser notification when a job finishes in a background tab.
  • The home page leads with its evidence. The four claims under the headline became a hairline grid of readouts, the number at the numeral step with what it counts under it, each one a link to the page that proves it; the drawing is framed as the file it is, with its name and what is in it along the top. And the copy now leads at every width: under 900 pixels the figure used to be ordered above the headline, so a visitor on a laptop or a phone landed on a picture of silicon with no words telling them what the tool was.
  • Sixty-three audit agents walked every page, panel, poll loop and error path, fifty-five confirmed findings were fixed, and then every button, tab and simulation was driven live in the browser, which caught and fixed twenty more, mostly one family: a slow response landing on a page that had moved on, and being trusted anyway. Measurements, bias annotations, layouts, deck verdicts and feasibility sentences now all carry the circuit and sizing they were started with, and are dropped when the page has changed underneath them. A keystroke no longer kills a suite ten minutes into its corners; the suite finishes and its state line says which sizing it measured. The bugs with teeth: a simulation answered onto the wrong circuit if you switched tabs mid-run; a failed run left the bench claiming work forever; the design search overwrote your sizing after a Stop or a missed spec, while the manual promised a button that never appeared; abandoned searches and characterizations kept burning simulations server-side after a circuit switch; and five polling loops rendered undefined forever when a job vanished. The quieter ones: stopped runs now say stopped instead of finished, the notebook survives a failed "show more", the datasheet prints its sizing with units and its area honestly, stale manual claims about rule counts and tab coverage were corrected against the code, every page prints in paper colours, the error panel's dismiss became a real button, and the Notebook joined every footer.
  • Adversarial review ran over all of it before it shipped, three times: over the studies, over the page audit's fixes, and over the new conveniences, with every confirmed finding fixed, more than a hundred across the three sweeps. The theme of what the first sweep caught was claims outrunning evidence at the interruption boundaries: a cancelled attack now says "aborted" instead of "survived", a truncated explanation says "inconclusive" instead of "nothing in the space fits", a chart cell stopped mid-search says "not run" instead of "not found", and a search that spent its whole budget reads "budget exhausted" instead of "completed". The referee also stopped being fragile: a declared design that will not simulate is now that contestant's failure rather than the contest's, a declaration outside the box is refused because the search space is part of the rules, the toolbox no longer quietly backfills missing tunables from the registry sizing it promises to withhold, frozen-parameter overwrites are recorded as the rules always claimed, and the ledger now tells the learning curve's cold arm from its warm one.

1.12.3

  • The folded cascode is redrawn on a planned grid. The first drawing failed a stricter audit in ways a label check could never see: every bottom-row source stopped eighteen pixels short of the ground rail, the M12 and M5 gate wires ran straight through the bodies of M11 and M14, the diode tie clipped the edge of the bias source's circle, and three parallel runs tangled around the fold nodes. Now every wire ends exactly on a device terminal, the gate buses ride clear channels and drop onto each gate from outside its symbol, and the few unavoidable crossings sit alone, well away from every junction dot.
  • The same disease was latent in the OTA and the two-stage op-amp: their bias buses ran along the gate row, which is through every transistor body between the gates they tie. Both now route at the diode-tie level, in the clear, with one honest crossing where the op-amp's bus passes the tail.
  • The geometry audit grew from checking labels to checking the circuit drawing itself. Every symbol primitive now tags its group with what it is and where its terminals sit, so the browser-side scanner can prove mechanically, for all ten schematics with measured values rendered: no wire ends in space, no wire transits a symbol body, no terminal is left unconnected, no crossing sits close enough to a dot to read as a junction, no two symbols overlap, and nothing leaves the frame. It caught a wire through the input pair in the first version of this very fix, which is the point of having it.
  • The three amplifiers draw their bias current source with a shared primitive instead of three hand-inlined circles, because a symbol the audit cannot see is a symbol it cannot defend.

1.12.2

  • Every schematic label was checked by machine, not by eye: a scanner in the browser intersects every label's box against every wire, symbol stroke and other label, on all ten circuits, with the measured values rendered. The folded cascode had eight labels sitting on wires -- both cascode references, both marked nodes, an input, a width and two device names -- and every one was moved against the drawer's own coordinates until the scan reads zero. Its phase margin tag now hangs below the output run instead of drawing its leader over the drain wire, and the load value no longer clips at the frame's edge.
  • Marker labels on the frequency plots track collisions per row across three rows, because two alternating rows printed the first and third of three close markers on top of each other -- exactly what the RLC band-pass did with its centre and both -3 dB marks.
  • A four-way audit of every page fixed what it found. The layout pane no longer claims the tool cannot do what its own buttons then do. The manual stopped contradicting the product: four SKY130 circuits, six analysis tabs, a layout that is routed, extracted and signed off, a contents that follows the document, and Ctrl+Enter where the keyboard is documented. The datasheet tab refreshes its store and pins when it opens, not only when the window resizes.
  • The search finishes its own story. Generate or optimize, feasible or not, the winning sizing lands on the page, the schematic redraws as the generated circuit, the confirming run measures it, and a table says exactly what moved: each knob, was, now, percent, with the unchanged ones named. The status line says whether the spec held instead of just "Finished".
  • Light mode holds up under a contrast meter: the light accent darkened to read on white, control borders firmed, and the layout plot's seven fills became theme tokens with light values instead of dark-palette constants that ignored the toggle.
  • Phones get one column again: the pane widths introduced at 1.12.1 were set on ids, which silently outranked the mobile reset. The reset now speaks at the same strength.
  • Around the edges: the shell settled at 1400 pixels; the notebook link is in every page's navigation rather than two; the netlist gained a copy button; corner and Monte Carlo tables speak the readout's language with units instead of raw keys; every simulator-spending button prices itself, in one unit; target complaints use the goal's own name; the tables' scrollbars quieted; and the mentor's heading says what it does.

1.12.1

  • The page uses its width. The shell grew from 1240 to 1520 pixels, and the panes that are all tables -- the datasheet, the design search -- take the whole row instead of being pinched into a form's column. The panes that carry a figure keep two columns, wider on the panel side.
  • Light mode. The toggle sits in the navigation on every page, the choice is remembered by the browser, and dark remains the default and the identity. Every colour on the site comes off the token scales, so the schematics, the plots and the verdict tables follow the theme on their own; the printable datasheet was already paper and ignores the toggle on purpose.
  • PVT corners and Monte Carlo run at the same time. The two suites answer different questions and share nothing but the circuit, so each now has its own progress, its own table and its own stop, and starting one no longer locks the other.
  • Buttons hold their labels. The characterize button said a paragraph and wore it badly; it now says "Write the datasheet (about 16 simulations)" and the paragraph lives in prose above it. Buttons that receive long text wrap instead of striking through their own borders.
  • Marker labels on the frequency plots get three rows with per-row collision tracking. Two alternating rows printed the first and third of three close markers on top of each other, which is exactly what the RLC band-pass did with its centre and two -3 dB marks.
  • The design panel says what it is for: it sizes the circuit for you, from a physics seed or from the values on the page, one real simulation per step, apply with one click.

1.12.0

  • The datasheet writes itself. One button runs the whole bench for the sizing on the page -- gain, margins, the step, rejection and range, all eleven corners, the layout with its four verdicts -- and renders the document engineers assemble by hand, headed by the commit, the simulator version and the PDK the numbers came out of. The extremes column says worst observed, never min or max, because eleven deterministic corners are a sample and not a guarantee, and the note beneath says exactly how many measured. Edit a value afterwards and a banner says the document no longer describes the circuit on the bench; the check is exact. Every characterization is stored beside the ledger, and a print view renders it black on white for the PDF a reviewer actually receives.
  • Pinned numbers, the regression test analog circuits never had. Pin a good result and the server freezes the sizing and its measurements together; a later check re-simulates the frozen sizing, so drift can only mean the stack moved underneath -- a model update, a simulator upgrade, an edited deck -- never that you turned a knob. The history draws as a row of marks with the first break outlined, and it never stitches across a re-pin, because a trend across two different pins would be an invention.
  • Compare two runs side by side: every number both carry, the delta, corner by corner when both have corners. A bench-only side says so instead of showing blanks, and two runs measured by different stacks earn a warning, because two stacks are two experiments.
  • The design panel answers three questions by measurement. Check feasibility: one simulation, every margin, the binding goal named, "at this sizing" and meaning it. Explain the margins: every tunable stepped five percent each way, two simulations per knob, the table sorted by what moves the binding goal, labelled as the local slopes they are. Sweep the bias: eight points along the declared knob, plotted power against crossover and captioned as a one-knob slice, not a Pareto front, with points that failed to bias drawn as facts rather than dropped.
  • The corner autopsy. After any corner suite, one click re-runs the eleven conditions with the operating point captured and tabulates every transistor's saturation headroom at every corner, sign-aware for PMOS, negative in red, the tightest device named even when everything holds. vds and vdsat come from the foundry's model card through ngspice at each corner's real bias; a value the model does not expose says so, and is never shown as zero.
  • The tapeout packet refuses to assemble. It builds: one click renders the geometry, runs the foundry's own deck over those shapes, runs layout-versus-schematic at the same sizing, and only if both pass does a zip exist -- the GDS with named ports, the verified netlist with its dummies, the sign-off report, and a README carrying the SHA-256 that binds the verdicts to exactly this drawing. A clean report from Tuesday can no longer ship beside Wednesday's GDS.
  • The notebook. Every run this machine makes is already recorded as it happens; the new page renders that ledger as the lab notebook engineers mean to keep and do not -- every run, its circuits, its simulation count as observed at the subprocess boundary, its verdicts, damaged lines shown rather than hidden, exportable as Markdown. The stored datasheets live there too.
  • python doctor.py checks every dependency at once -- ngspice, the PDK, the technology data, both halves of KLayout, the writable directories, the optional keys -- through the same resolution functions the tool itself uses, and prints the exact fix for anything missing. Optional pieces report absent, not failed, because absent and broken are different facts.
  • Around all of it: one background job per circuit at a time, refused with the name of the job in the way; simulation counts reported as observed, never estimated; the analysis tabs answer to the arrow keys like the circuit chips always have.

1.11.0

  • The layout is matched. Every pair the circuits rely on being identical -- the input pair, the mirror load, and for the folded cascode both cascode pairs and the folding sources -- is now drawn common centroid: each device split into two fingers and interleaved A B B A, with a dummy at each end of the array so the outermost real finger sees a neighbour rather than open field. The property this buys is exact and is tested exactly: compute both centroids and require them equal, which they are to within a part in ten to the fifteenth. A differential pair drawn side by side samples the process gradient at two different points and shows the difference at the output as an offset the schematic never predicted; that is the failure this removes.
  • Splitting a device into fingers is not a drawing trick, it is genuinely N devices in parallel, and the comparison against the netlist is told so rather than told to overlook it: both the extracted and the schematic netlists are combined the same way, by KLayout's own combine_devices. All three amplifiers still match. The dummies are declared in the comparison netlist too, because the layout has them, and every one of them is tied off -- an unconnected gate is a reliability problem and an extractor reads it as a transistor wired to nothing.
  • Each group has a guard ring: a tapped ring round the devices, tied to the rail its bodies sit at. Drawing it moved the groups 1.56 microns apart, because a substrate ring and a well ring meeting in the middle is a short from the substrate to the well. The foundry's deck adjudicated the corners four times over -- overlapping contacts merging into a bar, then their spacing, then the interconnect over them, then two vias a via's width apart -- and the ring that came out the far side is contacted along its length and bare where it turns, which is what a drawn guard ring looks like.
  • The loop closes on the drawn circuit. When the wiring breaks a target the schematic met, the search runs again with the parasitics in the deck and the result is drawn again, re-extracting the wiring each round because the wiring is a consequence of the sizing. Asked for 73 degrees of phase margin, the schematic gives 74.6 and the drawn circuit 71.3; one round of sizing against its own 519 femtofarads returns 89.2 as drawn. The tool has been able to say what the interconnect costs since the wires were first drawn, and until now nothing acted on it.
  • Simulations are counted where they happen. The plan's headline metric for comparing design methods is how many each spends, and it was being counted at the caller: a session that ran the corner suite spent eleven ngspice runs and was charged none, while the plain optimizer was charged exactly. Counting moved to the two places a netlist becomes a subprocess, with a budget enforced at the same place, so the number is measured rather than asserted.
  • Two live bugs in the strategist, found while building an experiment to measure it. list_circuits returned the whole catalogue, 19,080 characters, into a 2,000 character budget, and the clip cut it mid-token: every design session has been running with the model unable to see any of the three amplifiers, their parameters or their ranges. And advise called run_tool with two arguments, so the per-evaluation callback was always dead inside a session. Both fixed, and a clipped tool result is now always valid JSON that says what it left out.
  • A ledger: every attempt, measurement, decision and drawn layout, one JSON object per line, with the commit, the ngspice version, the PDK hash and the corner stamped at the head of each run. A run whose provenance is unknown is not evidence. It records and never judges, and it lives outside the project folder because an append-heavy log inside a syncing folder is a bad idea twice over.
  • The drawn cell names its ports. The GDS now carries a text label for every routed net, on the metal that carries it -- without them the file was a correct picture no other tool could connect to, because nothing in it said which piece of metal was the output.
  • The tool's own fast LVS now compares what is drawn. The drawing physically holds fingers and dummies; the KLayout engine learned that when matching landed, but the fast comparator was still handed the five-device schematic and told to find it in a sixteen-device drawing, so it reported a mismatch on every matched circuit. It is now declared the netlist of the drawing -- a finger carries its parent's nets, a dummy sits entirely on its body rail -- which is not a relaxation of the check but the check.
  • The page shows where you are without being asked. The hero is the folded cascode exactly as the tool drew it, rendered from the same rectangles the foundry's deck signed off. A bench strip under Measurement collects the four verdicts -- simulated, fast rules, foundry deck, LVS -- as they land, in place of a tour of the panels. Every circuit chip carries a small schematic glyph. A second run says what changed since the first, formatted the way the number itself is. Anything slow shows its elapsed seconds. An analysis tab holding a result says so with a dot. Ctrl+Enter runs from anywhere, and the manual's contents is a rail that stays put while the sections scroll.
  • The four-way comparison the plan asks for, built so its answer would survive review: a spec proved infeasible at the hand sizing before anything runs, a numerical arm starting cold at the centre of its own declared box rather than at the hand design, the load and the untuned widths frozen for every arm with any attempt to move them refused and recorded, one simulation budget for all four, and every arm scored on the design it declares, re-simulated afterwards, rather than on the best point it happened to touch. It refuses to rank four approaches when fewer than four ran.

1.10.0

  • The amplifier is laid out, not just its transistors. The two-stage's nulling resistor is drawn as a strip of poly sized off the sheet resistance the PDK states, marked with the same 66/13 layer the foundry's own LVS deck measures a generic poly resistor over, so the drawn value is the extracted value by construction: 2000.3 ohms after snapping to the manufacturing grid. The Miller capacitor is drawn as a metal2 over metal1 parallel plate sized off the overlap constant the PDK states: two picofarads is 14,941 square microns, far larger than every transistor together, which is not a mistake but the honest cost of building a capacitor from the two metals this stack has, and the reason real processes put MiM capacitors higher up.
  • Drawing them was paid for in measurements. The capacitor's bottom plate hangs 385 femtofarads on the output net, the parasitics went from 82 to 519 femtofarads, and the phase margin gave up 3.4 degrees, all measured by ngspice with the drawn geometry loading the nets rather than asserted.
  • The first placement parked the resistor's wire on top of the tap's supply wire, and the layout-versus-schematic caught it as a short between d2 and vdd before any person did: overlapping metal of one width looks like one wire to every spacing rule, which is exactly the class of error only a comparison against the netlist can see. The foundry's deck then caught the passives off the manufacturing grid, 81 violations, and a via pad five nanometres closer to the huge plate than wide metal allows. All fixed by reading three more facts from the PDK: the grid, and the wide-metal spacings.
  • Layout versus schematic is now also run by KLayout's own engine, in process. LayoutToNetlist is told what the layers mean and nothing else: it recognises the devices from the geometry, measures widths, lengths, resistances and capacitances off the drawn shapes, and NetlistComparer matches the result against the circuit by topology, the way sign-off LVS matches, not by the order devices were placed. All three amplifiers pass, the drawn resistor coming back at 2000.3 ohms and the capacitor at two picofarads with nothing telling the engine what to expect. Fed the wrong netlist, a missing via, or a lied-about width, it refuses, and there are tests that make it prove that.
  • The wires are priced in ohms. KLayout's square-counting extractor measures the squares of each net's worst pin-to-pin path over the drawn rectangles, the sheet values and the per-cut via resistances come out of the PDK, and the panel reports the longest wire. On the op-amp that is the compensation node at 250 ohms, because its track runs 373 microns to reach the far tab of the capacitor: a design insight that fell out of a measurement.
  • The folded cascode has a schematic at last: fourteen transistors in the house style, two cascoded branches, the pair folding into them, the bias column, and the two external gate references labelled as exactly that.
  • What is external is now called external and judged. A bias current and a load connect from outside as they would on a real chip, and the panel says so in green; the folded cascode's two ideal gate references are a stand-in for references a finished design would generate on chip, and the panel says that in red.

1.9.0

  • The drawing is now checked against the circuit it claims to be. Layout versus schematic walks the drawn shapes, works out what is electrically joined to what from the geometry alone, finds every transistor where poly crosses diffusion, and compares the nets that fall out against the netlist ngspice actually ran. All three amplifiers match. Every other check in this project asks whether the geometry is legal; this is the first one that asks whether it is right, and it is the only place the tool could have been wrong rather than merely incomplete.
  • A device became a device. Each transistor is drawn as the whole stack it takes to be one: the diffusion, the gate crossing it, the implant declaring the diffusion n-type or p-type, a column of contacts down the source and the drain, and the local interconnect over them. The gate got a contact too, on a pad above the channel, because poly cannot be contacted where it crosses the diffusion. Before this, every device had a gate that nothing could connect to.
  • The connectivity stopped being a list kept by hand. Two dictionaries recorded which devices shared a net and nothing checked them against the circuit that gets simulated. They are read out of the netlist now, terminal by terminal, which immediately showed what the hand-written version had been missing: the supply, the ground and both inputs were not in it at all. The measured interconnect went from 38 femtofarads to 82, because the nets that were never counted are now routed.
  • One metal layer cannot carry a circuit, and the old router had been pretending otherwise. On a single layer a stub coming down from a high track crosses every track below it, which is a short, and the rule checker could not see it, because two overlapping rectangles look like one wire. Metal1 now runs vertically and metal2 horizontally, joined only where a via says so.
  • The taps are drawn: an n-tap in the well and a p-tap in the substrate, contacted and tied to their rails. A well with nothing setting its voltage floats, and a floating well is how a CMOS circuit latches up and destroys itself. Drawing them found a violation that had been passing silently, because the checker had no rule for it: an n-diffusion has to stay 0.34 microns from an n-well and the row was leaving 0.09.
  • Twenty-two more rules, ten to thirty-two: the poly contact and its clearances, the contacts and the local interconnect, the implants, the vias between the layers and the metal that has to cover them, the second metal layer, the taps and the well spacings. Each is read from the PDK and each is tested against a shape built to break it. Two of them are not about dimensions at all: that every well holds a tap, and that every tap is contacted.
  • Placing the vias found that a device could be legal and unroutable. A transistor drawn to the transistor rules alone is 1.03 microns wide, but its source, gate and drain each need a via pad and the pads have to keep metal spacing apart, which needs 1.05. The footprint takes whichever binds.
  • A third topology, the folded cascode, which is V1.4 arriving late. The reason for it is not the circuit; it is the question a third one answers, whether the machinery built for the first two generalises. It did. Fourteen devices went through the placer, the router, the rule check and the comparison without one line of any of them changing, and came out clean on the first attempt. It earns its place too: 51.5 dB and 32.4 MHz against the five-transistor OTA's 37.0 dB and 14.3 MHz, for 230 microwatts against 69. The sizing was measured rather than chosen, over fifty-four bias points and a second sweep that found the n-channel cascode width moves the gain by seven decibels and nothing else comes close.
  • The layout panel reports two verdicts rather than one more row of numbers, because a rule check and a layout comparison answer different questions, and what was not checked is written underneath rather than left to be assumed. The drawing shows what the file holds, taps and both metal layers included, and the panel is called Layout rather than Floorplan, which it outgrew.
  • The loop closes. The strategist could design and measure and then it stopped: everything past that, drawing the geometry, checking it, comparing it against the netlist, running the foundry's deck, measuring the specs again with the interconnect loading them, was a thing a person did afterwards by clicking. It is one tool call now. A tool that turns a sentence into a sized schematic is a sizing tool; one that turns a sentence into geometry a foundry's own runset passes is a different claim, and the difference was that call.
  • The folded cascode can be designed to a spec like the other two, so the strategist chooses among three topologies rather than two. The seed is built on measurements rather than guesses: power is about 6.4 times the bias current times the supply, gain falls about 25 dB per decade of bias, and bandwidth rises about as its 0.7 power, all measured across a decade rather than assumed.
  • The search promptly beat the sizing that had been chosen by hand. Asked for 55 dB at 8 MHz under 80 microwatts, it returned 77.7 dB at 13.5 MHz on 78, which is twenty-six decibels more gain than the balanced preset at a third of the power. It was re-simulated on its own to confirm before being written down, and it is the High gain preset now.
  • The foundry's own deck runs now. KLayout is installed as machine tooling, and the SKY130 runset the PDK ships is pointed at the same GDS the tool already wrote. Nothing is reimplemented: the file goes over, the report comes back. All three amplifiers pass it, over the front-end, back-end and off-grid sections.
  • The first run of it failed geometry the hand checker had called clean, forty violations across three rules, all of them the same kind: a via needs more metal along one axis than it needs all round, and the hand checker had implemented the all-round half and stopped. The router draws to the directional rules now and the fast checker knows all three, thirty-two to thirty-five. That is the argument for running a real deck stated as an experiment rather than an opinion.
  • The hand checker stopped calling itself the answer. It is the inner loop, it says so in its own result and in the panel, and it points at the deck.
  • The comparison against the netlist stopped overstating. It compares transistors, because transistors are what the layout draws, and it never mentioned that the netlist also holds a bias current, a load, and for the op-amp the nulling resistor and compensation capacitor that make it stable. Those are listed by name now, in the panel, under what is not in the drawing.
  • KLayout also read the GDS the hand-written writer emits and agreed with it exactly: 762 shapes written, 762 read, right database unit, right layers, right bounding box. The writer has been checked against a tool that has no stake in the answer.
  • The manual has a contents, grouped the way the tool is used: getting a number, trusting it, building it. Seventeen sections in one column with no index is a document you scroll through hunting.
  • Two files stopped being one file each. circuits.py had grown to 2,456 lines doing four jobs and is now five modules of a few hundred each, verified by hashing every deck the tool can build before and after and finding all seventy-eight identical. app.js gave up its four measurement panels to their own files, and the three places that named every panel one by one became loops over what registered.
  • Splitting app.js found a bug that had been live and silent: stepValue was declared twice in one closure, once for arrow-key stepping and once to format a step metric, and the later declaration won for the whole scope. Pressing the up arrow on any form field replaced its contents with an em dash. Nothing failed and nothing logged. There is now a test that refuses any script declaring one name twice.

1.8.0

  • The interconnect capacitance had been coming from a length guessed off the bounding box of the devices a net touches. Nothing was drawn, so nothing could be checked, and the number was an estimate wearing the clothes of a measurement. Each net is now routed as metal on its own track with a stub down onto every device it serves, and the length is taken from the geometry that was actually drawn.
  • The correction was material. The default op-amp carries 38 femtofarads of its own interconnect, not the 21 the estimate claimed, and the phase margin it costs goes from 0.17 degrees to 0.29. The estimate was optimistic by nearly half, because it counted the run across the row and not the stubs down onto devices tens of microns tall.
  • Two more rules for the metal that is now there to check: minimum width (met1.1) and minimum spacing (met1.2). Ten rules, and the routing is in the GDS: 2434 bytes for the op-amp, clean on all ten.

1.7.0

  • The p-channel devices are drawn as p-channel devices. A PMOS has to sit in an n-well, and until now the floorplan drew every device the same way, which made the picture wrong rather than incomplete.
  • Drawing the well immediately broke a rule, which is the point of drawing it. Two separate n-wells have to stay 1.27 microns apart and PMOS scattered through the row put two of them 1.18 apart. The devices are now grouped by type, NMOS then PMOS, so the p-channel devices share one well. The grouping is not cosmetic and a test says why.
  • Three rules for the well: minimum width (nwell.1), the spacing between two that are not the same well (nwell.2a), and the surround the well owes the p-diffusion inside it (nwell.5).

1.6.0

  • The drawn geometry is checked rather than assumed. A drawing nobody has looked at and a drawing checked against the numbers it was supposed to satisfy are different objects, and only one of them can be reported as either.
  • Every rule is tested twice, once against geometry that satisfies it and once against geometry built specifically to break it, because a checker that never fails is worse than no checker: it turns unchecked geometry into geometry someone believes.
  • The result carries its own coverage, so a clean pass can never be presented as more than the rules it actually covered, and a test refuses any wording in the module that would claim sign-off.

1.5.0

  • The first answer to a question a schematic cannot ask: how much silicon does this sizing cost. The devices are placed in a row at the foundry’s own minimum diffusion spacing and drawn to scale. The default op-amp comes to 395.6 square microns, and the picture shows why: the 40 micron output driver is four times the width of anything else and sets the whole height.
  • Then the part that matters. Those positions give the wires between the devices a length, and metal of that length has a capacitance, so the capacitance is hung back on the nets and the same measurements run again. The default op-amp carries about 21 femtofarads of its own interconnect and loses about a fifth of a degree of phase margin to it. Measured, twice, not asserted once.
  • Every dimension and every capacitance is read out of the PDK’s technology file at run time: minimum poly width, the diffusion overhang a transistor needs, device spacing, metal width, and the capacitance of each layer per square micron and per micron of edge. Nothing is a remembered constant, and a test checks four of the rules against their published SKY130 values.
  • That test caught a real error while it was being written. The scalefactor lines in the technology file belong to its GDS output styles, not to its design rules, and using one made every dimension ten times too large: a 0.15 micron minimum gate came out as 1.5 microns. The rules are in nanometres, confirmed against four independent published minimums.
  • The geometry can now leave the tool. Download GDS writes the placement in the format every layout tool reads, on the real SKY130 layer numbers taken from the PDK: diffusion 65/20, poly 66/20. The writer is a hundred lines of standard library, because GDSII is a documented format and this project does not take dependencies it can write. Tests parse the stream back with a second, independent reader and check the geometry that comes out against the geometry that went in, including that the gate lands in the channel, overhangs it, and sits centred.
  • The geometry is now checked rather than assumed. Five rules read from the same technology file, each carrying the tag the foundry writes in its own error message: minimum poly width (poly.1a), minimum diffusion width (diff/tap.1), diffusion spacing (diff/tap.3), the diffusion overhang that makes a source and a drain (poly.7), and the poly overhang that keeps the channel from being shorted around the end of the gate (poly.8). Both amplifiers pass all five.
  • A checker that never fails is worse than no checker, so every rule is tested against a shape built to break it: a gate below the minimum width, a diffusion below its own, two devices drawn a tenth of a micron apart, a gate stopping inside its diffusion, and a device with too little diffusion for a source. All five are caught, and a legal device still passes, including one at the tightest sizing the form allows.
  • Writing the checker caught a remembered constant. The gate overhang was the number 0.13 typed into the geometry; it is the poly.8 rule, and it is now read from the PDK like everything else. It happened to be right, which is exactly why it was worth removing.
  • Five rules is not sign-off, and the result says so in its own words: the real deck has thousands and needs Magic or KLayout. What this is not, said plainly here and in the tool: a layout. There is no router, no design rule check, no layout versus schematic and no real extraction, because those need Magic and Netgen and neither runs on this machine. Devices are drawn as single fingers, so a wide transistor is drawn wide where a real layout would fold it. A test refuses any wording in the code that would claim otherwise.

1.4.0

  • The page had grown wrong. Every analysis stacked under the form that only sets a circuit up, so the left column ran 6356 pixels against a 962 pixel right one and the whole page was 9262 pixels tall. The four analyses now share one tabbed section below the form, one open at a time, and the page is 2452 pixels: a bit over a quarter of what it was, with nothing removed.
  • Each analysis that draws something now keeps its plot beside its own numbers instead of a column away. Only the tabs a circuit can answer appear, so a resistor divider shows none and the SKY130 amplifiers show all four.
  • A badge marked hidden had been rendering anyway, as a small empty box next to every reading, and the statistics row was holding thirteen pixels of space while hidden. Both were the same fault: a utility class that says display none can be beaten by any rule further down the file at equal specificity. It cannot be beaten now, and a test says so.
  • The step and rejection panels had been drawing every label on top of its own value. Their rows were wrapped in a div, which put both halves of a pair into a single cell of a grid that lays out its own children. The numbers were correct and unreadable. They are cells now, and a test refuses a wrapper in either renderer.
  • An empty frequency plot no longer reserves a full plot of empty ground before there is anything to draw in it.

1.3.0

  • The rest of the datasheet. Both amplifiers now report CMRR, PSRR, input common-mode range and output swing, which are the numbers that tell the two topologies apart. The two-stage op-amp measures 76.5 dB of CMRR, 67.1 dB of PSRR and 1.24 V of range; the OTA measures 57.0, 36.2 and 0.91. The OTA needs no compensation and is worse at all three, which is a trade the strategist can now reason about instead of guessing.
  • An AC analysis excites every source in a netlist at once, so one copy of a circuit cannot be asked three questions and give three separable answers. The deck holds four identical copies instead, each with a single stimulus: a differential drive, a common-mode drive, a moving supply, and a buffer swept from ground to the supply. One library load, four answers, about half a minute.
  • The first attempt reported supply rejection as supply gain, which is impossible. The servo inductor that closes the loop at DC is an open circuit above it, which left the inverting gate floating and the answer meaningless. Holding that gate still for the signal, while leaving the DC servo alone, turned an absurd 29 dB at 1 kHz into 67 dB flat from 10 Hz upward.
  • A second plot, the DC transfer curve, with the ends of the measured range marked on it, so the range is a number you can see where it came from rather than one you have to trust.
  • Following means tracking, not agreeing. At the bottom of a sweep the amplifier is off and its output sits at zero, which matches a zero input to well inside any error tolerance. The measurement asks for unit slope as well, and a test builds exactly that trap to make sure it is not fallen into.
  • The device list now lives in one place per topology instead of one per testbench. Four builders had been about to hold four copies of the same eight transistors, and a copy that drifts is a testbench quietly measuring a different circuit. The refactor was checked by generating every existing netlist before and after and requiring them to be byte for byte identical.
  • The strategist gained both new measurements as tools, and its instructions now say which analysis each number comes from, so it cannot state a slew rate or a CMRR it has not measured.

1.2.0

  • The first analysis here that is not a sweep. Both SKY130 amplifiers can now be measured as a unity-gain buffer hit with a 0.3 V step, which is a real closed loop with no servo in it, and the numbers that come back are the ones a sweep cannot give: slew rate, settling time and overshoot.
  • The measurement was checked against the physics before it was wired to anything. A two-stage amplifier should slew at its tail current over its compensation capacitor, 10.0 V/us for the default design; the measurement says 7.4, under that ceiling and in sight of it. Doubling the capacitor halved the measured rate and doubling the bias current raised it, both as the textbook says they should. A test pins the measurement between half the ceiling and the ceiling so a wrong answer cannot pass quietly.
  • Both edges are measured, because they need not match. The two-stage op-amp is slower rising, 7.43 against 7.65 V/us, and the OTA is slower falling, 6.71 against 7.00. The reported figure is the worse edge and both are shown, since a datasheet has to honour the slower one.
  • A new plot, the first in the time domain: output against time, with the moment of the step marked, drawn at the width it will occupy in the same idiom as everything else. The window sizes itself from the parts that set the slew, so a slower amplifier is watched for longer and its edge is still a visible slope rather than a vertical line.
  • Settling means settled. An earlier version of the measurement took the last sample as the final value and asked only whether it was near itself, which would call an output still climbing at the end of the window settled. It now checks the tail is flat first and answers “not in this window” when it is not, rather than inventing a number. The test that caught this is in the suite.
  • A trap in the parameter ranges is gone. Two widths on the op-amp offered up to 200 and 500 microns, but a SKY130 01v8 device accepts 100 and refuses 101, verified against the model library in both flavours. Anything above the limit failed with a raw simulator error, on the sweep as much as the step. The maxima now match what the device takes, and a test refuses any declared width that claims more.
  • What this does not do yet: the design iterator cannot target a slew rate, because a transient run costs a full simulation on top of the sweep. Making it a goal is the next step, not fine print.

1.1.0

  • Faradaem has a face. The mark is the AE ligature itself, white on the ink ground, its outline lifted from IBM Plex Sans SemiBold and baked into path data so no font is needed to render it. It ships as the favicon, the touch icon, and an Open Graph card, all generated from one geometry by tools/make_brand.py so the sizes cannot drift apart.
  • The header logotype now sets the name with the AE ligature, the ligature in accent cyan, and a trademark symbol sized from the font’s own metrics: one third of the cap height, top aligned to the cap line, tucked inside the brand tracking. In prose the name stays plain ASCII Faradaem, and a test keeps the ligature from leaking anywhere else.
  • The home page opens like a product instead of a form: a landing that says what the tool does, one button that jumps to asking for a design, and the facts that matter in a single row. The header follows you down the page, and the schematic column holds still beside the controls while you scroll.
  • Every page now carries a descriptive title, an application name, and a full Open Graph and Twitter card block, so a shared link unfurls with the mark instead of a bare URL.
  • Fixed on phones: below 560 pixels the header lost its side padding and sat flush against the screen edge.
  • The circuit list is a row of separate bordered tabs, the chosen one filled in accent like the run button. Before, nine names ran together into one block of text.
  • Figures size themselves to what they contain. A drawing unit may grow to 1.15 pixels and may shrink to 0.85, no further either way: a three-part divider stops expanding instead of filling the column, and a dense circuit holds its size and scrolls sideways instead of collapsing into an unreadable thumbnail. Between those limits the drawing is centred in a full-width frame, and the page itself is wider, so the op-amp draws about a third larger than it did in 1.0.0.
  • Wires stop where they turn. Every wire was drawn with a round cap, which added half a stroke past each endpoint, so at every corner two segments overshot the turn and left a stub. Caps are flat now, and each transistor lead is one polyline that turns rather than two that meet.
  • The plot no longer collides with itself. Its axis titles sat inside the frames, right where a lowpass response runs, so the trace cut through the words; they are now rotated into the margin. Frequency ticks read 10 kHz instead of 10.00 kHz, which stops neighbouring decades from touching, and the two floating trace labels are gone. The plot is also drawn at the width it will occupy rather than stretched to fit, so its type renders at the size it was designed at.
  • The manual no longer claims only one circuit needs the process design kit; all three SKY130 circuits do, and the page now says so.
  • Faradaem can be published. tools/build_static.py writes the four pages, the assets, and the circuit catalogue into a folder any static host can serve, and vercel.json at the root builds it the same way from the command line or from a git push. The pages ask for the simulator first, fall back to the published catalogue when there is none, and drop into a static mode that keeps the live schematics and puts away every panel that would need a measured number, with a note at the top saying why. No number appears that nothing measured.
  • One test could fail for the wrong reason. It looked for stray simulation files across the whole system temp directory, so running the corner suite in a browser while the tests ran was enough to fail it, which says nothing about whether the run under test cleaned up. It now works in a private directory that no other Faradaem can reach.

1.0.0

  • The loop is closed: specification in, verified schematic out. In the acceptance run, one sentence went into the panel and a strategist chose the two-stage topology for the gain requirement, generated a design from the targets, measured it, iterated to feasibility in six simulations, then verified it across all eleven PVT conditions.
  • Verified means verified: the shipped design holds every target at every corner. Worst gain 69.4 dB at low supply and hot, worst bandwidth 3.77 MHz at the slow corner, worst phase margin 63.3 degrees, worst power 67.2 microwatts, each named with the condition that caused it.
  • The whole flow is pinned by an end-to-end test that replays it with real tools, and the winning schematic is reproducible: rerunning its exact parameters lands on its exact numbers.
  • Deployment groundwork ships with it: a Dockerfile, continuous integration that runs the suite against a real ngspice on every push, and DEPLOY.md with the honest warnings about authentication and API credits.
  • What verified does not yet mean: layout, parasitic extraction, or silicon. Those are the next chapters of the plan, not fine print.

0.9.0

  • PVT corners. A Robustness panel on the SKY130 circuits reruns the design across eleven conditions: five process corners, the supply and temperature extremes, and the two classic cross corners. The table names the worst case per metric and the condition that caused it. Measured on the OTA: unity-gain bandwidth falls from 14.3 MHz nominal to 11.4 MHz at slow, hot and starved.
  • Monte Carlo mismatch: twenty samples from the PDK's statistical models at the typical corner, each under its own seed, reported as mean, sigma, minimum and maximum. The PDK's bare mc section ships without device models, so mismatch at the typical corner is what Monte Carlo means here, and the manual says so.
  • The machinery is one hook: robustness runs edit the finished netlist text, the corner in the .lib line, the supply, the temperature card. No circuit builder learned anything.
  • The strategist gained run_corners and now verifies a finished design across PVT, reporting the worst case with its corner named.

0.8.0

  • A second amplifier topology: the five-transistor OTA on SKY130, measured open loop through the same DC servo as the two-stage. One stage means no compensation, phase margin near 90 degrees, and better bandwidth per microwatt, at the price of gain: 37 dB at the base sizing against the two-stage's 71.5 dB.
  • Topology selection is now a real choice the strategist makes and explains: high gain points at the two-stage, modest gain with speed or power pressure points at the OTA. Both topologies seed from targets and both can be iterated.
  • The measured trade is pinned by a test: the OTA carries more than ten degrees more margin, the two-stage more than twenty decibels more gain.
  • View netlist, under the run button: the exact SPICE deck your values produce, updating live as you edit. Nothing on this site is hidden behind the schematic; the deck is the ground truth and now you can read it.

0.7.1

  • First contact with the real OpenAI API, and the fixes it demanded: current models take max_completion_tokens, and function tools on the chat endpoint need reasoning effort disabled. The default model is now gpt-5.6-terra, overridable through FARADAEM_OPENAI_MODEL.
  • Rate limits and transient provider errors are retried with backoff, honouring Retry-After.
  • Strategist tools accept partial parameters merged over the circuit's defaults, so a model can pass just the load capacitance, and the tool schemas now carry the real circuit ids and target keys so first calls land.
  • A design card's parameters now include the fixed conditions, not only the tuned values. Applying a card reproduces the card's measurement exactly; before this, the load could silently revert to the form's value.
  • Verified live: a plain-English request became a measured op-amp meeting all four targets, 72.1 dB, 4.73 MHz, 65.9 degrees, 65.9 microwatts, designed by GPT driving the seed, simulate and iterate tools.

0.7.0

  • The LLM layer. An Ask for a design panel takes a plain-language request, and a strategist drives the real tools: it reads the catalogue, sets targets, seeds, simulates, and iterates. Its words render as words; every number renders as a card taken from a tool result, with a button that loads the design into the form and reruns it.
  • The strategist never produces a circuit value, and when it believes a target should change, it asks instead of deciding. Sessions can be continued, stopped, and started over.
  • Two providers over the standard library alone: the Anthropic and OpenAI APIs through urllib, selected by whichever keys exist, with a picker when both do. Keys are read from the user environment, including keys set with setx after the server started. No new dependencies.
  • The whole layer is tested without a network against a scripted model, including tool failures, the turn limit, pausing on questions, and a full session over HTTP.
  • The four-way comparison harness from the research plan: human design, optimizer only, LLM only, and LLM plus optimizer, per provider, measured on the same spec by the same simulator. First offline result: the optimizer already edges out the hand design, 131 against 156 microwatts at the same spec.

0.6.3

  • The op-amp schematic is laid out cleanly: strict columns, more room, rails that span only the columns they feed, and the bias bus running straight along the bottom row's gates instead of detouring under everything. The diode tie no longer cuts through the bias source symbol.
  • No label touches a wire or a component anywhere. Every figure is now checked programmatically for text against text and text against wires, and the whole set passes with zero overlaps.
  • One deliberate wire crossing remains in the op-amp figure, at the mirror gate tie, which is where textbooks put it.

0.6.2

  • Schematics are now drawn directly on the dark ground, the way Kirchhoff draws them: light grey wires and symbols, cyan node dots, cyan net names, and the measured value as plain cyan text beside its node instead of a filled tag.
  • The Bode plot follows: cyan magnitude trace, grey phase trace, faint grid on the dark surface. The light paper figure is retired, and with it the second accent shade it required.
  • Not one drawing routine changed for the restyle. The figures take every colour from the stylesheet, so the whole change is tokens and classes.

0.6.1

  • Spec-first generation on the op-amp: enter only the targets, press one button, and a design is created, measured, iterated if it falls short, and confirmed with a final simulation. No starting sizes needed.
  • The starting design is scaled from the hand-designed op-amp by two declared rules: compensation tracks the load, bias current tracks the power budget. Seeds are launch points, never results; across four spec profiles, two were met by the seed alone and the others within two iterations.
  • Optimizing from the form's current values remains available as the second path.

0.6.0

  • The design iterator. Set targets for gain, bandwidth, phase margin and power, press Start, and a coordinate search sizes the circuit until every target is met. Each candidate is a full ngspice simulation; the measurements decide the next move, and nothing is ever predicted from a formula.
  • Verified end to end on the SKY130 op-amp: from a failing start at 28 degrees of phase margin, the search reached 73.4 dB gain, 6.8 MHz unity-gain bandwidth, 63 degrees of margin and 79 uW in nine simulations, and stopped the moment the spec was met.
  • The search runs as a server job. The page polls progress, shows the best point so far with a met or short verdict per target, and Stop actually stops it. Apply result loads the winning values and runs one confirming simulation, so what you see is measured, not remembered.
  • Candidates the simulator refuses, a bias that will not settle or a loop with no crossover, are recorded and skipped rather than ending the search.

0.5.0

  • Circuits can now declare a design surface: which parameters an optimizer may move, and which measured numbers count as goals, each with a direction and a default target. The op-amp tunes its bias current, input pair, output driver and compensation network. The two-pole macromodel tunes its gain-bandwidth and second pole, and doubles as the fast test bed for the search itself.
  • The parameterized netlist the roadmap called for: every device size, current and capacitor in the op-amp is a form field with declared bounds, and the netlist is rebuilt from them on every run.

0.4.0

  • A hand-designed two-stage Miller op-amp on SKY130: eight transistors, a mirror-loaded input pair, a common-source second stage, and compensation with a zero-nulling resistor. The shipped sizing measures 71.5 dB of open-loop gain, 13.6 MHz unity-gain bandwidth, 74.6 degrees of phase margin and 156 uW.
  • Measured open loop with the classic DC servo: an enormous inductor closes the loop at DC so the operating point is a stable unity buffer, and the AC drive arrives through an enormous capacitor whose zero-ohm source holds the input node, so the loop is open by impedance at every swept frequency.
  • One sweep yields the whole datasheet line: open-loop gain, unity-gain bandwidth, phase margin, power, and the servoed output voltage.
  • Removing the nulling resistor costs twenty degrees of phase margin on the measured device. That is the right-half-plane zero doing exactly what the textbooks say it does, and there is a preset for it.
  • A sizing that does not bias, with the output stuck at a rail, is refused with a message naming the measured voltage and which widths to rebalance.

0.3.0

  • Phase margin, measured from a real loop gain sweep. Every measurement before this one came from a closed loop response, and phase margin is not in there: it is a property of the loop gain, so the loop has to be opened.
  • A two-pole op-amp macromodel to measure it on. A single-pole loop has a phase margin of about 90 degrees no matter what you do to it, so it cannot tell a correct measurement from one that always returns 90. This one has a phase margin that is a real closed form and moves over a wide range.
  • The netlist carries two electrically separate copies of the circuit, one closed and one with the loop cut at the amplifier input. They share only ground, so one sweep measures both and the two responses cannot disagree about where the samples fell.
  • Measured against the closed form: phase margin agrees to 0.001 degrees, crossover to 0.05 percent, loop gain to 0.03 dB.
  • Gain margin is deliberately not reported. A two-pole loop never reaches 180 degrees of phase shift, so its gain margin is infinite and any number there would be an artifact of where the sweep stopped.
  • A user manual at /manual, covering how to run a simulation, how to read the result, what every warning means, and what to do when something goes wrong. Its tests check it against the code it documents, so it fails if a circuit is added without being written up.
  • Parameter combinations that cannot be swept now return 400 with a message saying which way to move, instead of 500.

0.2.1

  • Visual language aligned with Kirchhoff: cool dark chrome, one cyan accent, square corners, no shadows, and a sans body with a monospace lane kept for numerics and raw simulator output.
  • The accent exists at two lightnesses because it has to. Bright cyan sits at 1.6:1 on the light datasheet plate, so everything drawn on paper uses a darker cyan instead: the magnitude trace, the markers, and their labels.
  • Six worked examples per circuit, up from two or three, labelled as examples. Every one is verified against a real ngspice run.
  • Some examples are instructive rather than tidy: an op-amp with a finite open-loop gain misses its ideal closed-loop gain and says so, and a common-source stage biased into triode reports the caution alongside its real numbers.
  • Three contrast failures on the datasheet plate fixed in passing, and the focus ring now detaches from the filled Run button instead of fusing with it.
  • About page carries the full colophon and biography.

0.2.0

  • SKY130 NFET common-source amplifier: the first circuit built on a real process design kit rather than on ideal components.
  • PDK resolution from the PDK_ROOT environment variable, falling back to C:\pdk, with a message that says what to install when the model library is missing.
  • The operating point is measured in the same ngspice run as the sweep, so the readout carries drain voltage, drain current and power beside the gain and bandwidth.
  • A gate bias that leaves the device off is reported as a bias problem naming the measured Vds and Id, not as a failed measurement. A stage bottomed out in triode still measures, and says so.
  • This circuit ships no analytic check on purpose. Square law does not describe a 150 nm device, and its bandwidth is set by the transistor’s own output resistance, measured at 10.5 MHz against an ideal 7.96 MHz. It is the first Faradaem result that cannot be obtained without a simulator.

0.1.6

  • Design system tightening: one spacing scale, five type steps, one radius, one hairline, one shadow. Every margin and font size now comes from a token.
  • Preset chips load a worked example for each circuit in one click.
  • Bode plots read out any point on hover, snapping to the nearest swept sample.
  • Keyboard support throughout: arrow keys move between circuits and step component values, Enter runs, Esc dismisses an error.
  • About page says who builds this.

0.1.5

  • Circuit registry: every circuit is one catalogue entry describing its parameters, netlist, measurement and analytic checks. The page builds its forms from that catalogue.
  • RC high-pass filter, with the corner measured from the passband down.
  • Series RLC band-pass, with resonance found by quadratic interpolation and Q from the two −3 dB skirts.
  • Inverting amplifier on a single-pole op-amp macromodel, showing gain-bandwidth as a real trade rather than a formula.

0.1.0

  • RC low-pass circuit, selectable alongside the DC divider from a mode switcher.
  • AC sweep through ngspice: 20 points per decade, three decades either side of the corner, read back with wrdata.
  • Bode plot on the paper panel: magnitude and phase over log frequency, with the corner marked.
  • -3 dB extraction by interpolation in log frequency, checked against 1/(2πRC).

0.0.1

  • Visual identity: dark instrument chrome, paper datasheet figure, copper accent, monospace numerics.
  • Added the About and Changelog pages behind a shared nav and footer.
  • Live SVG schematic that redraws as you type and annotates the out node after a run.
  • Static asset routing: GET is served from a strict whitelist, and request paths never touch the filesystem.

0.0.0

  • Resistor divider simulated through real ngspice, with the analytic value shown only as a check.
  • Standard-library web server and a single-page interface.
  • 74 tests covering netlist construction, output parsing, request validation, and a live simulator run.