Skip to content


A Julia package for CAD of electronic devices, in particular superconducting devices operating at microwave frequencies.


Julia 0.7 and above

Activate package mode by pressing ] at the REPL in a Julia console.

  • add

Older versions

  • Pkg.add("Clipper")

When Clipper.jl is added, it will be built to compile shared library / DLL files. A compiler will be downloaded for you on Windows.

  • Pkg.clone("")

Quick start

Let's mock up a transmission line with two launchers and some bridges across the transmission line. We begin by making a cell with a rectangle in it:

using Devices, Devices.PreferMicrons, FileIO

cr = Cell("rect", nm)
r = centered(Rectangle(20μm, 40μm))
render!(cr, r, Rectangles.Plain(), GDSMeta(1,0))

Note that when you use Devices.PreferMicrons, this will also enable the unqualified use of the following units: pm, nm, μm, mm, cm, dm, m, °, rad. (By unqualified we mean that the symbols are imported into the calling namespace and do not need to be prefixed with a module name.) When adding length units together, if the units don't agree, the result will be in microns. You can instead do using Devices.PreferNanometers if you want the result to default to nanometers. (These are your two choices at the moment, though there's nothing fundamentally limiting other possibilities: see src/units.jl for how to do this for other units.)

When you specify the units for a Cell, you are specifying a database unit. Anything rendered into this cell will be discretized into integer multiples of the database unit. This means that nothing smaller than 1 nm can be represented accurately. Nonetheless, this is typically a satisfactory choice for superconducting devices.

A rectangle made with a width and height parameter will default to having its lower-left corner at the origin. centered will return a rectangle that is centered about the origin instead.

The rectangle is then rendered into the cell. Rectangles.Plain() specifies a rendering style. Other examples include Rectangles.Rounded (where the corners are rounded off) or Rectangles.Undercut. You can omit the style, in which case Rectangles.Plain() will be assumed. GDSMeta(1) indicates the target GDS-II layer. You can also specify the GDS-II datatype as a second argument, e.g. GDSMeta(1,0).

In another cell, we make the transmission line with some launchers on both ends:

p = Path(μm)
sty = launch!(p)
straight!(p, 500μm, sty)
turn!(p, π/2, 150μm)
straight!(p, 500μm)
cp = Cell("pathonly", nm)
render!(cp, p, GDSMeta(0))

Finally, let's put bridges across the feedline:

turnidx = Int((length(p)+1)/2) - 1 # the first straight segment of the path
simplify!(p, turnidx .+ (0:2))
attach!(p, CellReference(cr, Point(0.0μm, 0.0μm)), (40μm):(40μm):((pathlength(p[turnidx]))-40μm), i=turnidx)
c = Cell("decoratedpath", nm)
render!(c, p, GDSMeta(0))

How easy was that?

You can save a GDS file for e-beam lithography, or an SVG for vector graphics by using save with an appropriate extension:

save("/path/to/myoutput.gds", c)
save("/path/to/myoutput.svg", c)

Note that SVG support is experimental at the moment, and is not completely optimized. It is however used in generating the graphics you see in this documentation. If you use Juno for Atom, rendered cells are automatically previewed in the plot pane provided you enter Devices.@junographics at the start of your session. If you use Jupyter/IJulia, rendered cells are automatically returned as a result

Example without using units

For compatibility and laziness reasons it is possible to use Devices.jl without units at all. If you do not provide units, all values are presumed to be in microns. The syntax is otherwise the same:

using Devices, FileIO

cr = Cell("rect")
r = centered(Rectangle(20,40))
render!(cr, r, GDSMeta(1))

p = Path()
sty = launch!(p)
cp = Cell("pathonly")
render!(cp, p, GDSMeta(0))

turnidx = Int((length(p)+1)/2) - 1 # the first straight segment of the path
simplify!(p, turnidx+(0:2))
attach!(p, CellReference(cr, Point(0.0,0.0)), 40:40:((pathlength(p[turnidx]))-40), i=turnidx)
c = Cell("decoratedpath")
render!(c, p, GDSMeta(0))

Some caveats:

  • You cannot mix and match unitful and unitless numbers (the latter are not presumed to be in microns in this case).
  • It is somewhat annoying to maintain this behavior alongside unit support, so eventually I may drop support for this and require the use of units.

Performance tips

Since Julia has a just-in-time compiler, the first time code is executed may take much longer than any other times. This means that a lot of time will be wasted repeating compilations if you run Devices.jl in a script like you would in other languages. For readability, it is best to split up your CAD code into functions that have clearly named inputs and perform a well-defined task. At present, for performance reasons, it is also best to avoid writing functions with keyword arguments (though this will be addressed in Julia 1.0).

It is also best to avoid writing statements in global scope. In other words, put most of your code in a function. Your CAD script should ideally look like the following:

using Devices, Devices.PreferMicrons, FileIO
using CoordinateTransformations
using Clipper

function subroutine1()
    # render some thing

function subroutine2()
    # render some other thing

function main()
    # my cad code goes here: do all of the things
    save("/path/to/out.gds", ...)

main() # execute main() at end of script.

You can then include this file from Julia to generate your pattern. Provided you write your script this way, subsequent runs should be several times faster than the first if you include the file again from the same Julia session.


  • If you cannot save the GDS file, try deleting any file that happens to be at the target path. A corrupted file at the target path may prevent saving.
  • Decorated styles should not become part of compound styles, for now. Avoid this by decorating / attaching cell references at the end.