Demos & examples

The public demos, explained

examples_klink/public is the public gallery — no NDA, no proprietary PDK, no committed private GDS. 8 example demos: 2 run fully offline, 6 need a live KLayout (still no external GDS), one of those (the gdsfactory takeover) also needs gdsfactory in the same interpreter. Everything device- and process-specific lives in the demo itself; klink ships zero process constants — copy a demo, edit its numbers, and the flow is identical for your process.

How you run them depends on how you installed

All 8 demos are starters bundled in the wheel, grouped into nanodevice/, photonics/, passives/, and digital/ categories: klink init <proj> scaffolds them into <proj>/example_template/<category>/ and a pip user runs python example_template/<category>/<name>.pyebl_wraparound, hallbar, neural_electrode under nanodevice/, gf_mzi_module under photonics/, idc_capacitor, spiral_inductor, saw_idt_filter, baw_fbar_planview under passives/, and fit_device_pnr_lvs, chat_to_netlist_pnr, multilayer_pnr_lvs, padframe_pnr_lvs under digital/ (the cards below give this command directly). The 4 digital/ demos additionally need a running KLayout session (they do live P&R+LVS); from a repo clone you can also run them as python -m examples_klink.public.demos.digital.<name>, which the cards below also give.

Running the demos needs no MCP. Each is a plain python -m … script talking to KLayout over the plugin port. MCP is the layer that lets your agent call klink as resident tools. Both paths use the same pip install klayout-klink.
A KLayout "port" is just a session — any port works; none has a special role. Use an empty or test-owned session, not your manual working tab.

The 8 demos at a glance

DemoCategoryRequiresMeasured
EBL wraparoundnanodevicefully offline40 electrodes · 12 patches · 0 violations · 0 overlaps
Hall barnanodeviceoffline (--live optional)semantic bundle + routed result
Neural electrodenanodevicelive KLayout48 ports · 24 nets · overlap 0 · hit 0
Fit device → P&R → LVSdigital P&Rlive KLayoutrouted 94/94 · LVS match=True · 173 devices
Netlist → lint → P&Rdigital P&Rlive KLayoutlint 0 err · routed 3/3 · LVS match=True
Multilayer P&R at scaledigital P&Rlive KLayoutrouted 405/405 · LVS match=True · 766 devices · ~17s
Probe-card padframedigital P&Rlive KLayoutrouted 94/94 · LVS match=True · 16 pads connected
gdsfactory MZI takeoverphotonicslive KLayout + gdsfactory6 optical nets · reroute 12 routes · 0 crossings

1 · EBL nanodevice wraparound fully offline

A parametric electron-beam-lithography wraparound generator. Offline it prints the generated bundle; --live writes to a KLayout session. The fastest path to a first result with no external geometry.

python example_template/nanodevice/ebl_wraparound.py          # [--live] [--keep]
# from a repo clone you can also run: python -m examples_klink.public.demos.nanodevice.ebl_wraparound
40electrodes
12patches
16 / 11 / 20fields/windows/crossings
0violations
0overlaps

Reusable core: klink.domains.nanodevice.devices.wraparound.build_wraparound_demo. Copy the demo and edit electrode count / pitch / writefield params — the flow does not change.

📖 Step-by-step walkthrough →

2 · Hall bar nanodevice offline (--live)

A parametric Hall-bar generator. Offline it prints the semantic bundle + routed result; --live writes a disposable KLayout cell (deleted unless --keep). It demonstrates the "device generator + delegate to the generic router" loop behind nanodevice.hallbar.

python example_template/nanodevice/hallbar.py                 # [--live] [--keep]
# from a repo clone you can also run: python -m examples_klink.public.demos.nanodevice.hallbar

Reusable core: tapered-hybrid router + port.mark / anchor.mark. From a HallBarSpec (bar length/width, contact count, pad dims, pitch, gaps) it computes the whole device geometry, then delegates contact→pad routing to the generic router.

📖 Step-by-step walkthrough →

3 · Neural-electrode harness live KLayout

A self-contained probe generator: defines pad/via geometry and Port/Anchor resources, then calls the tapered-hybrid router. No GDS, just live Port/Anchor PCells. Use an empty or test-owned session.

python example_template/nanodevice/neural_electrode.py --port <session-port> --elec-rows 4
# from a repo clone you can also run: python -m examples_klink.public.demos.nanodevice.neural_electrode --port <session-port> --elec-rows 4
48ports
24nets (12×1/0 + 12×3/0)
0sibling-overlap
0obstacle-hit
📖 Step-by-step walkthrough →

4 · Fit a device → digital P&R → LVS live KLayout

The full self-contained, IP-free digital flow: fit a parametric device PCell from synthetic exemplar geometry, place it, run detailed routing, and verify with live LVS. Swap in your own harvested exemplar boxes to fit your real device — the flow does not change.

python example_template/digital/fit_device_pnr_lvs.py --port <session-port>   # [--draw-only]
# from a repo clone you can also run: python -m examples_klink.public.demos.digital.fit_device_pnr_lvs --port <session-port>   # [--draw-only]
94/94routed
match=Truelive LVS
173devices

Reusable core: map_logic_to_devices(...) → place → FlexDR → live LVS.

📖 Step-by-step walkthrough →

5 · Hand-written netlist → lint → P&R → LVS live KLayout

The "describe it in chat, get a verified layout" flow: a 3-stage ring oscillator netlist is written by hand, validated by lint_netlist (every structural mistake gets a fix-it message before any geometry exists), then placed, routed, LVS-verified, and every stage node brought out as a bare labelled trace. Netlists are plain data — an agent (or you) can write one for any topology, no logic synthesizer required.

python example_template/digital/chat_to_netlist_pnr.py --port <session-port>
# from a repo clone you can also run: python -m examples_klink.public.demos.digital.chat_to_netlist_pnr --port <session-port>
0lint errors
3/3routed
match=TrueLVS
6devices
3/3taps CONNECTED

6 · Multilayer place & route at scale live KLayout

The scale demo: a bundled 766-device synthetic netlist (a toy 4-bit ALU, 268 gates, netted by an open logic synthesizer, remapped onto this gallery's synthetic fitted devices) is linted, then compared on two example process stacks with the built-in layer-count advisor — the 3-layer public process from the fit-a-device demo, and a 7-layer example stack defined in the demo itself. The advisor prints each stack's core-area cost so you can see why a design this size wants the extra layers. It then places, marks all 20 primary ports (13 in west, 7 out east), and routes with the multilayer engine.

python example_template/digital/multilayer_pnr_lvs.py --port <session-port>
# from a repo clone you can also run: python -m examples_klink.public.demos.digital.multilayer_pnr_lvs --port <session-port>
405/405nets routed
match=TrueLVS
766devices
20/20ports CONNECTED
~17send to end

Copy this file and edit PUBLIC_MULTILAYER for your own layer stack — the flow does not change.

7 · Probe-card-first place & route live KLayout

The reversed-order hardware flow: the probe card / pad ring exists first (positions frozen long ago) and the circuit must meet it — even when the card interior is too small for the whole block. The same synthetic 4-bit adder is linted, then a stand-in 20-pad probe card is fabricated and harvested back with pads_from_gds. A net→pad table assigns all 14 primary ports + VDD + GND; because the interior fits only half the rows, place_grid(forbid_y_bands=…) splits the block half inside / half below, and pdn_split_bands threads one power grid per region bridged by a spine strap.

python example_template/digital/padframe_pnr_lvs.py --port <session-port>   # [--no-card]
# from a repo clone you can also run: python -m examples_klink.public.demos.digital.padframe_pnr_lvs --port <session-port>   # [--no-card]
94/94routed
match=TrueLVS
173devices
85 / 80inside / below
16 + 4connected + redundant isolated

--no-card drops the card: every port leaves as a bare labelled wire-end trace at the periphery (inputs west, outputs east), power on the auto-labelled PDN tie rails — routed 94/94, LVS match=True, all 14 stubs CONNECTED. Copy this file and edit the pad table for your own card.

📖 Step-by-step walkthrough →

8 · gdsfactory takeover → editable photonic module live KLayout + gdsfactory

A complete thermo-optic MZI — tilted fiber GC → 1×2 MMI splitter → two thermal phase-shifter arms (bottom mirrored) → 2×2 MMI combiner → offset output GCs, plus heater pad rows and a fiber-loopback pair — written as an ordinary gdsfactory script, then taken over by a single import_gf_component call. One persisted net table then holds every kind of net: the script's own optics (re-drawn by klink), the offset output bank restyled to sbend, the tilted GC a Manhattan router can't reach (all_angle), the loopback pair (dubins arcs), and the heater→pad electrical nets on metal. A single photonics.reroute redraws all of them — so after you drag any component in the GUI, one reroute re-routes optics and metal together.

python example_template/photonics/gf_mzi_module.py --port <session-port>
# … drag a component in KLayout …
python example_template/photonics/gf_mzi_module.py --port <session-port> --reroute
# from a repo clone you can also run: python -m examples_klink.public.demos.photonics.gf_mzi_module --port <session-port> [--reroute]
6optical nets
13 / 5instances / device cells
12reroute routes
0 / 0crossings / device-hits
The drag → reroute loop is the point. --reroute re-routes from the dragged positions without rebuilding, keeping your edit. Re-running with no flag rebuilds from the gdsfactory source and snaps every component back to its original spot, undoing the drag — a common first-time surprise, so the flag is the fix. (An agent with the MCP tools calls photonics.reroute directly.)

Requirements: gdsfactory in the same interpreter that runs it. The demos are pinned to the tested line — pip install "klayout-klink[photonics]" gets a known-good gdsfactory. If gdsfactory already lives in another venv, add klink into that venv and run from there; do not sys.path-hack the repo into a foreign interpreter (that path leads to version mismatch and 1000×-off geometry).

📖 Step-by-step walkthrough →

Passive-device geometry templates offline (--live)

Four parametric passive-device geometry templates, starters in the passives/ category: after klink init, run python example_template/passives/<name>.py. Offline by default, each writes a GDS under test_outputs/ and prints a structured self-check summary; --live [--port <session-port>] pushes a disposable cell to a KLayout session instead. Every family marks klink Ports (999/99) on its electrical terminals, so the routing backends work on them out of the box. Each is a geometry template, NOT a validated electrical/acoustic design — tune the numbers for your process and verify with your own models (SAW/BAW make no frequency or material claims).

  • IDC capacitorpython example_template/passives/idc_capacitor.py (defaults, 10 fingers: 2 merged regions, no short, 2 ports)
  • Square spiral inductorpython example_template/passives/spiral_inductor.py (defaults, 3 turns: 1 merged region per metal layer, underpass crosses 4 segments, 2 ports)
  • SAW IDT filterpython example_template/passives/saw_idt_filter.py (defaults, 12 pairs: 2 merged regions per IDT, 1 per reflector grating, 4 ports)
  • BAW / FBAR plan viewpython example_template/passives/baw_fbar_planview.py (defaults, 2000 µm² target: no two edges parallel, area error <1%, 2 ports)

Every command supports [--live --port <session-port>].

📖 Step-by-step walkthrough →

Feature examples

examples_klink/public/features shows single capabilities, good to learn the API and copy into your project:

  • gdsfactory: route to KLayout (23), route ports (24), net examples (25), component marker (26), width mismatch + auto taper (29), routing zoo (30) — on the open gf.gpdk, same interpreter rule.
  • Port/Anchor walkthrough (anchor_port_5_example and its _pya variant).
  • Router stress: tapered, tapered segments, steiner, damped, plus future/missing-algorithm showcases.
  • measurement import, harness/probe generators.

The examples_klink/public/smoke folder has capability smoke demos (draw, PCell zoo, cells & shapes, delete/undo, exec, route run) — not full tutorials, but good to confirm a primitive works.

Public boundaries

The public gallery's contract is open + open-box runnable:

  • No NDA / proprietary PDK content.
  • No committed private GDS.
  • No dev-only PDK module imports.
  • Third-party deps handled as ordinary pip install.
If a flow needs your private device GDS, it may only read that path at run time in your project — never commit GDS/PDK files to a public repo or site example. The template .gitignore blocks *.gds/*.oas by default.