Editing
Select, move, stretch, copy: editing layout without breaking it
How the selection in LayoutEditor decides between move and stretch, why a pad moved alone opens a joint without a DRC error, which SKY130 rules a stretch can break, and how copies differ from cell references, with tested LayoutScript and .ledrc examples.
Last edited: October 30, 2026

A layout edit changes stored coordinates, and four operations cover most of them. Select marks the objects or the individual vertices that the next command acts on. Move adds the same offset to every vertex of the selected objects: size and shape stay, position changes. Stretch adds the offset only to the selected vertices of an object: one edge of a box, one corner of a polygon, one end of a path; the unselected vertices keep their coordinates, so the object changes size. Copy writes new, independent shapes, while a stamp writes another reference to an existing cell. In LayoutEditor, Draw → Move performs both; the selection decides which of the two happens.
The image at the top is a LayoutEditor window during a stretch. Two SKY130 met1 joints are drawn: 0.620 µm pads (hatched) with four 0.170 µm mcon cuts each (black), connected by 0.140 µm wide straps. A point selection covers the right end of both straps and both right pads. The Draw → Move command is waiting for its destination point: the outlines on the right show where the fully selected pads and cuts land, the Mouse Help panel lists the next click, and the Select Status bar at the bottom counts 6 selected points and 10 selected boxes. After the click, both straps end 0.45 µm further right and still overlap the moved pads.
What the selection contains
LayoutEditor distinguishes a selected object from selected points. In Select/Edit mode a click selects one element and a dragged window selects elements; the Mouse Help panel lists the variants with Shift and Ctrl. Select → Fine Select offers three finer modes, each with its own key:
| Mode | Key | Selects |
|---|---|---|
| Point select | Ins | individual vertices; a dragged window takes every vertex inside it |
| Form select | Home | whole shapes |
| Cell select | PgUp | cell references; Shift+left-click steps through references sorted by distance to the pointer |
The matching deselect modes are on Del, End, and PgDown. An object with every vertex selected moves as a whole; an object with some vertices selected is stretched. Layers that are locked or hidden do not respond to mouse selection, which is the direct way to pick a cut under a wide metal shape. Where cell references overlap, Select/Edit picks the reference whose origin is closest to the pointer. A double-click opens the Properties dialog of the clicked element with its layer, datatype, and coordinates.
The Select Status bar in the lower right of the window counts selected points and selected shapes per type. It is the fastest check before a move. In the test for the lead image, a leftover full selection showed 0 points and 12 boxes: Draw → Move then shifted both straps as whole boxes, and the left ends of the straps no longer overlapped the left pads. With the point selection in place, the bar showed 6 points and 10 boxes, and the same move stretched the straps.
A selected instance is a reference, not geometry. Moving it changes its placement. Editing inside the cell changes every placement of that cell; see cells and instances.
Move and stretch in LayoutEditor
Draw → Move (key M) moves the current selection: the first click sets a source point, the second click the destination point. The Mouse Help panel lists a perpendicular move, which keeps one coordinate fixed. The stretch workflow uses the same command:
- Select → Fine Select → Point select (Ins).
- Drag a window over the vertices that should move, for example the end of a strap together with the pad it lands on.
- Check the Select Status bar for selected points.
- Draw → Move (M), source point, destination point.
For a single vertex or a single edge, Utilities → Adjust Utilities → Move Point (Ctrl+M) and Move Edge (Ctrl+U) are interactive modes that pick the vertex or edge under the pointer; in Move Point, a Shift+left-click opens a dialog for the new coordinates. Other editors separate the two operations: Virtuoso Layout has a Stretch command (key s) next to Move (key m), and KLayout stretches in its Partial mode.
LayoutScript, the Python interface of LayoutEditor, uses the same model: pSelect(rect) selects the vertices inside a rectangle, selectAll() on an element selects the whole element, and moveSelect(point) adds an offset to everything selected. The script below builds one joint twice, stretches the first and moves only the pad of the second:
from LayoutScript import *
d = project.newLayout().drawing
top = d.currentCell; top.cellName = "TOP"
def joint(y): # dbu = 1 nm
top.addBox(0, y, 500, 500, 68).setDatatype(20) # left pad
strap = top.addBox(400, y + 180, 2700, 140, 68) # strap x = 0.4 .. 3.1 um
strap.setDatatype(20)
pad = top.addBox(3000, y, 500, 500, 68); pad.setDatatype(20) # right pad
return strap, pad
def show(tag, e):
pa = e.getPoints()
print(tag, [(pa.point(i).x() / 1000, pa.point(i).y() / 1000) for i in range(pa.size())])
# Stretch: point selection over the strap end and the whole right pad
strap, pad = joint(0)
r = rect(); r.setLeft(2900); r.setRight(3600); r.setBottom(-100); r.setTop(600)
top.deselectAll(); top.pSelect(r)
top.moveSelect(point(1000, 0)) # +1 um in x
show("stretch strap", strap); show("stretch pad", pad)
# Move: the right pad alone is selected
strap, pad = joint(2000)
top.deselectAll(); pad.selectAll()
top.moveSelect(point(1000, 0))
show("move strap", strap); show("move pad", pad)
d.saveFile("joint.gds")
Each line prints the two stored corners of a box in µm:
stretch strap [(0.4, 0.32), (4.1, 0.18)]
stretch pad [(4.0, 0.5), (4.5, 0.0)]
move strap [(0.4, 2.32), (3.1, 2.18)]
move pad [(4.0, 2.5), (4.5, 2.0)]
The stretched strap now ends at x = 4.1 µm, inside the moved pad, which starts at x = 4.0 µm. The moved pad also starts at x = 4.0 µm, but the strap of the second joint still ends at x = 3.1 µm.

The second picture is the file that the script writes, opened in LayoutEditor. The bottom joint is the stretch: the strap runs from the left pad into the right pad. The top joint is the move: the right pad sits 1 µm further right, and the strap ends 0.900 µm before it.
A moved pad opens the joint without a DRC error
The gap in the top joint is an open: the strap and the pad no longer touch, so they belong to two different nets. A spacing rule does not report it, because the gap is larger than the minimum space. In the test layout below, the move case gives 0 DRC markers. A connectivity count does report it: merging all met1 shapes of the joint in LayoutScript (mergeSelect()) gives 1 polygon for the untouched and the stretched joint and 2 polygons for the moved pad. Opens of this kind are found by net extraction and LVS, not by DRC.
The fix is a selection fix. When the whole connection must slide, select the strap, both pads, and the cuts completely, then move. When the strap must get longer and the pads stay, point-select only the strap end, then move.
Rules a stretch must respect
A stretch changes widths, enclosures, and spaces, and every changed value is checked against the design rules again. The values below are from the SkyWater SKY130 periphery rule table:
| Rule | Requirement | Value |
|---|---|---|
| m1.1 | met1 width | ≥ 0.140 µm |
| m1.2 | met1 to met1 space | ≥ 0.140 µm |
| m1.4 | met1 enclosure of mcon | ≥ 0.030 µm |
| m1.6 | met1 area | ≥ 0.083 µm² |
| x.1b | vertex grid | 0.005 µm |
The test layout has one case per 10 µm column, each produced by LayoutEditor edit calls on the joint above. The deck checks the rules that the edits can break:
units 1e-6
layer mcon = input(67, 44)
layer m1 = input(68, 20)
check "m1.1" "m1.1 : met1 width >= 0.140 um" : width(m1) < 0.14 um
check "m1.2" "m1.2 : met1 spacing >= 0.140 um" : space(m1) < 0.14 um
check "m1.4" "m1.4 : met1 enclosure of mcon >= 0.030 um" : enc(m1, mcon) < 0.03 um
check "x.1b" "x.1b : met1 vertex on 0.005 um grid" : ongrid(m1) != 0.005 um
layout --drc edit_checks.ledrc edit_cases.gds --outdir=drc
| Case | Edit | Result | Markers |
|---|---|---|---|
| 0 | none | — | 0 |
| 1 | strap end and pad stretched by 1 µm | joint connected | 0 |
| 2 | pad moved alone by 1 µm | open, 0.900 µm gap | 0 |
| 3 | pad top edge stretched down by 0.140 µm | met1 ends 0.025 µm above the mcon | m1.4: 1 |
| 4 | pad right edge stretched by 0.002 µm | two vertices at x = 3.502 µm | x.1b: 2 |
| 5 | end of a path with extended end cap stretched by 0.100 µm | 0.130 µm to the next met1 shape | m1.2: 1 |
| 6 | same stretch, flush path end | 0.200 µm to the next met1 shape | 0 |
The report lists one line per marker with rule, description, severity, marker edges in database units (1 nm), and the measured value in database units:
m1.2 m1.2 : met1 spacing >= 0.140 um error 51970,320 51970,180 | 52100,128 52100,372 130
m1.4 m1.4 : met1 enclosure of mcon >= 0.030 um error 33148,360 33352,360 | 33165,335 33335,335 25
x.1b x.1b : met1 vertex on 0.005 um grid error 43502,0 43502,0 | 43502,0 43502,0 0
x.1b x.1b : met1 vertex on 0.005 um grid error 43502,500 43502,500 | 43502,500 43502,500 0
The figure shows cases 3, 5, and 6 at one scale. In panel A the pad and the cut still overlap, and the joint is electrically intact, but the enclosure is below the rule. In panel B the stored end point of the path is 0.200 µm from the neighbor; the end cap, not the centerline, sets the space. GDSII stores the end type of a path as PATHTYPE: 0 flush, 1 round, 2 extended by half the width, 4 extended by explicit begin and end values. For a 0.140 µm path, type 2 adds 0.070 µm at each end. Panel C has the same centerline with a flush end and passes. The same deck, run on the geometry of the figure, reports exactly these markers.
Case 4 shows the grid rule. A move or stretch by a value that is not a multiple of the manufacturing grid puts vertices off the grid, and x.1b reports each one. Utilities → Adjust Utilities → Round Elements... (Ctrl+R) moves all selected points onto a grid that it asks for. The area rule m1.6 applies when a stretch shortens a small shape; it is in the table because a strap that is shortened to a stub can drop below 0.083 µm².
Copy or stamp
Duplicating a shape raises a different question: whether the duplicate should follow later fixes of the original. A copy is a new set of shapes with no link to the source. A stamp is a reference to a cell: the shapes are stored once in the cell, and each placement stores a position and a transform. A fix inside the cell reaches every placement; a fix on one copy reaches nothing else.
LayoutEditor has three commands for this:
- Draw → Copy (key C) copies the selection. Copied shapes are independent shapes. Copying a selected cell reference adds a second reference to the same cell (tested with the LayoutScript equivalent
copySelect). - Cell → Group... moves the selected shapes into a new cell and places one reference to it where the shapes were.
- Draw → Cellarray (key A) places a cell array: one reference that repeats an existing cell in columns and rows.
The script below draws a met1 pad around one mcon with a top enclosure of 0.025 µm, which is below m1.4. It copies the shapes once, groups the originals into a cell, copies the reference, and adds a three-element array. Then it fixes the pad inside the cell by stretching its top edge:
from LayoutScript import *
d = project.newLayout().drawing
top = d.currentCell; top.cellName = "TOP"
pad = top.addBox(0, 0, 500, 360, 68); pad.setDatatype(20) # met1 pad, top edge 0.025 um above mcon
cut = top.addBox(165, 165, 170, 170, 67); cut.setDatatype(44) # mcon 0.170 um
top.deselectAll(); pad.selectAll(); cut.selectAll()
top.copySelect(point(8000, 0)) # Draw -> Copy: independent shapes at x = 8 um
top.deselectAll(); pad.selectAll(); cut.selectAll()
d.group() # Cell -> Group: new cell + one cell reference
cell = d.findCell("grouped_1"); cell.cellName = "PAD"
d.point(0, 0); d.cSelect() # select the reference
top.copySelect(point(2000, 0)) # copy of a reference = second placement
top.addCellrefArray(cell, point(0, 2000), point(2000, 2000), 3, 1) # Draw -> Cellarray
top.deselectAll()
d.saveFile("stamp_before.gds")
r = rect(); r.setLeft(-100); r.setRight(600); r.setBottom(350); r.setTop(400)
cell.deselectAll(); cell.pSelect(r) # top edge of the pad inside cell PAD
cell.moveSelect(point(0, 140)) # stretch it up: enclosure 0.025 -> 0.165 um
cell.deselectAll()
d.saveFile("stamp_after.gds")
group() names the new cell grouped_1 and places its reference at the origin; the script renames the cell to PAD. With the deck above, stamp_before.gds gives six m1.4 lines, one per pad: two references, three array elements, and the copy. stamp_after.gds gives one:
m1.4 m1.4 : met1 enclosure of mcon >= 0.030 um error 8148,360 8352,360 | 8165,335 8335,335 25

The third picture shows the file after the fix. The bottom row holds the two references at x = 0 and 2 µm and, at x = 8 µm, the copy made with Draw → Copy. The top row is the three-element array. The five placements show the corrected cell with the taller pad. The copy kept the short pad, and the red band along its top edge is the m1.4 marker that the deck reports.
Use a cell and an array for every structure that repeats with a pitch and a count, such as contacts, bit cells, and transistor fingers. A copy is sufficient for a one-off jog or patch. When one of two identical devices must differ, create a new cell with a descriptive name (for example device_long_finger) and place that, instead of editing an anonymous copy. Flattening one reference to edit it produces a copy as well; see hierarchy and flattening.
Matched pairs and pasted geometry
A stretch applies the same offset to every selected vertex. If one strap of a differential pair is stretched and its partner is not selected, the two lengths differ by the offset, and nothing in the command reports it. Select the ends of both straps in one point selection, stretch them together, and compare their lengths in the Properties dialogs afterwards.
Geometry pasted from another design keeps the conventions of that design. Check its database unit, its layer and datatype numbers, and its grid before relying on it. A paste can also land on the wrong layer, for example a row of metal squares that arrives on the contact layer. Hide every other layer after a paste and inspect what is left.
Checks after an edit
- Before Draw → Move, read the Select Status bar: selected points mean a stretch, selected shapes without points mean a move.
- After the edit, read the coordinates of one moved vertex and one vertex that should have stayed.
- Inspect every joint that the edit touched: shapes that overlap or share an edge are connected; a visible gap is an open, and DRC does not report it.
- For duplicates, check whether they are references to one cell or independent shapes; only references receive later fixes.
- Run DRC and LVS after each batch of edits, not only before tape-out.
Continue exploring
-
Paths in layout: centerline, width, end caps, and bends
A layout path stores a centerline and one width. How end caps and corners are built, when a path turns into a polygon, and how a wrong cap causes an open or a short.
-
Width and space
The two oldest rules: don’t be skinny, don’t cuddle. Everything else is a variation.
-
Cells and instances
Draw the pad once and stamp it many times. Each stamp is the same drawing in a new place, not a photocopy of the ink.
-
Hierarchy and flattening: why chips keep cells and boards go flat
Flattening replaces cell references with transformed copies of their shapes: what GDSII SREF and AREF records store, how the transform is applied, what it costs in file size, and how to flatten and check a layout in LayoutEditor.
-
Snapping, and the quiet disaster of off-grid points
The magnet on your cursor is how drawings stay manufacturable. Turn it off and you will invent illegal corners.
-
Boxes are just rectangles
An axis-aligned rectangle is a native four-number object. Rotate, chamfer, or boolean it and it becomes a polygon.