Arrange — alignment, distribution, transform, boolean
The Arrange menu and the Transform toolbar group (which nests the Align dropdown) cover every geometric transform; boolean ops have their own Boolean toolbar group (a flyout listing all four with their hotkeys), plus the Edit menu, the right-click context menu, and the U/D/I/X keys directly (see below).
Running Align, Fillet/Chamfer, Convert path to polygon, or Flatten text with nothing (or the wrong kind of thing) selected shows a one-line toast naming what to select first — "Select a boundary with corners to fillet or chamfer.", "Select a path to convert.", "Select a text label to flatten." — instead of quietly doing nothing.
Alignment and distribution
When 2+ shapes are selected, the alignment buttons light up:
- Align left, horizontal centers, right
- Align bottom, vertical centers, top
- Distribute horizontally (requires 3+ selected)
- Distribute vertically (requires 3+ selected)
Transform
With a selection, the Properties panel shows an inline Transform section — no modal dialogs. Type a value and press Enter (or click the button); the panel stays open so you can repeat (e.g. Rotate +90 twice):
- Move — translate by Δx / Δy in the active display unit. A click in a Transform field selects its value, so what you type replaces it. The first key you type after a Move resets the other field to 0, so the two fields always show exactly what the next Move applies;
Enteragain with nothing typed repeats it.Ctrl+Drepeats your last Move or drag when the selection is what you just moved ("transform again"), and each press hands that step on to the new copy, so repeated presses build a regular row. An arrow-key nudge is not a Move and is not repeated. Undo takes the step back too: undo a Move andCtrl+Dno longer repeats it (it repeats the earlier Move or drag of that selection if one is still in effect, and otherwise nudges); undo a repeated copy and the nextCtrl+Drepeats the step from the object before it. OtherwiseCtrl+Dplaces the copy a small step off the original so you can see it, and the first Move you type right after it is measured from the original: Δy 60 puts the copy exactly 60 above what you duplicated. A second Move is an ordinary one. (A Redo does not bring the repeat back.) - Rotate — arbitrary angle, with ±45/±90/180 preset chips, about the point the Rotate about chips name: Center (the selection's centroid, the default) or Origin (0, 0) — one undo entry, instances and images included.
]/[are still the quick ±90° keyboard steps (holdShiftfor 45°),Ralso rotates +90° whenever no placement ghost is armed (a KLayout-idiom rotate key, one undo entry), and the Transform toolbar group has a Rotate +90° button that applies the same rule: it turns the armed placement ghost if you have one, otherwise the selection. - Scale — uniform scale (×0.25 / ×0.5 / ×2 / ×4 presets) about the point the Scale about chips name: Center (the selection's centroid, the default) or Origin (0, 0), which keeps a drawing's coordinates in place — the choice for fixing a unit-less import by ×1000. The Rotate field starts empty, so a stray Enter rotates nothing.
- Offset / Inflate / Deflate — polygon offset on selected boundaries (outset positive, inset negative; runs via
polygon-clipping).
and are discovery shortcuts, not separate dialogs: with a selection, either one switches to the Select tool and scrolls/focuses the matching field above, so picking them from the menu (or the command palette — see The workspace) lands you on the same Scale / Offset controls described above.
Array… ( or the toolbar), Polar array… (Arrange) and Chamfer / Fillet corners… (Arrange) remain their own parameter dialogs. Array…'s column/row step fields pre-fill from the selection's own bounding box, rounded up to a round number, so the default array tiles the selection edge-to-edge at any scale instead of guessing a fixed step; with nothing selected, the step falls back to 1 µm.
Chamfer / Fillet corners… cuts or rounds every corner of the selected boundary polygons by one setback or radius. A cut or arc never runs past the middle of an edge, so a value that is too large for a corner is not applied there in full: a chamfer is cut short at half the corner's shorter edge, and a fillet leaves that corner sharp. The dialog says so before you apply — for example "4 of 6 corners will stay sharp: a radius of 2.5 µm does not fit there. Up to 1.999 µm rounds every corner." — and, after you apply, the same count shows in a message. A fillet radius that fits no corner at all is refused: the dialog stays open, nothing changes and nothing is added to the undo history. Every new corner vertex lands on a whole nanometre, and one apply is one undo step.
The component library also carries two shapes Clewin offers as direct tools: a Regular polygon (any number of sides, with the radius measured to a corner or to an edge — the across-flats dimension a hexagon is usually specified by) and a Trapezoid (independent top and bottom widths, plus a top offset that turns the isosceles shape into a right trapezoid). They are components rather than drawing tools on purpose: both shapes are defined by numbers, so typing them beats dragging and correcting, and a placed one stays editable from the Properties panel.
Polar array repeats the selection around a centre instead of along a lattice: give a centre, a number of copies and a swept angle. The centre starts at the centre of the selection (a placed instance counts by its origin point) — type the ring's real centre over it. A full 360° sweep spaces the copies evenly all the way round — 4 copies land at 0/90/180/270, so the last one does not sit on top of the first. A partial sweep (say 90°) fans them across that arc with the first and last copies ON the endpoints. Rotate each copy with the arc is on by default, which is what a radial test structure wants; turn it off and each copy keeps its original angle while only its position revolves, which is what alignment marks and labels need. It works on shapes and on placed instances — unlike the rectangular Array…, which copies shapes only and refuses a selection of instances, naming the Cells panel's Insert cell array (AREF) button as the way to grid an instance (Polar array is offered too, for a radial pattern); with exactly one SREF selected, Array… opens the Insert-array dialog for that instance instead, gridding it in place (Instances: SREF and AREF). GDS has no radial array primitive, so every copy is a separate object rather than one array record; the count is capped at 2000 and the dialog shows the resulting angular step live. One undo step.
Fill empty regions… (Arrange, since v0.132.0) tiles a fill cell into the empty space of a region: pick the fill cell (the dialog pre-selects only a cell named as a fill tile; New square tile… creates one at a suggested size on the layer you choose), a pitch, a keep-out halo, and which layers count as keep-out — the dialog previews "would place N instances" before anything is committed, and Place is one undo step. The fill region is either the active cell's own content bbox (default) or a typed rectangle (X0/Y0/X1/Y1 in the dialog, with a "Use current selection's bbox" convenience button that reads whatever is currently selected); either way, sites are only ever generated inside that rectangle. A site is kept out when its tile comes closer than the halo to keep-out geometry by true straight-line distance, so a site beside a diagonal strip, a ring or a curve is placed when it fits, and the empty middle of a ring or frame is filled; with a halo of 0 a tile may touch geometry but never overlap it. Width>0 paths on keep-out layers count as their widened ribbons. Keep-out geometry inside placed instances (SREFs and AREFs, at any depth, through each instance's rotation, mirror and magnification) counts too, construction shapes and text excepted, by the same exact distance. A keep-out that flattens to more than 400,000 shapes is refused with the count. Placement is capped at 10,000 instances; the refusal names the number and a pitch (or, with a target, a tile size) that fits. Surviving sites that form a regular, unbroken rectangular run of at least 4 compress into a single AREF instead of N separate SREFs — a ragged remainder (smaller runs, or sites broken up by keep-out geometry) stays individual SREFs; the preview and the placed toast both state the honest split (e.g. "as 2 AREFs + 6 SREFs"). An optional Target density (%) (empty = the behaviour above) fills to a density instead: Pitch X/Y become the minimum pitch, and the dialog keeps the fill tile and chooses the pitch so that the fill cell's layer covers the target share of the fill region within ±1 percentage point — counting geometry already on that layer (the active cell flattened, earlier fill runs included), which is always kept clear of. Among the pitches within that point it picks the most evenly spaced grid. Grids are spread edge to edge across the region; when none of them reaches the target because a keep-out runs along the region's border (a frame or seal ring on the fill layer, a pad row), it also tries grids inset past that border, so the first and last rows no longer sit on the frame. The preview and the placed toast name the achieved density and the pitch used (e.g. "Density on layer 5/0: 25.00 % (target 25.00 %, pitch 22.5 × 22.5 µm)"). The fill cell must draw on one layer. A target that cannot be reached is refused beside the Preview button with the reason, and nothing is placed: when the layer is already denser than the target, when the densest grid the minimum pitch allows falls short, when it needs more than the 10,000-instance cap, or when no pitch lands within the point (the closest is named). The density is measured over the whole fill region as ONE window; a deck's moving-window rule is still checked with Verify → Design rules.
Move up in hierarchy (Arrange, since v0.132.0) promotes the selected objects from the active cell into its parent, transformed through the parent's own instance placement — defined only when the cell is referenced exactly once, by a single unscaled SREF (a multi-parent, array-instanced, magnified, or self-referencing cell refuses with the reason). One undo step.
Resolve arrays (Arrange, since v0.132.0) explodes a selected AREF into its individual SREF instances for per-instance editing — capped at 2000 like Polar array, one undo step.
Place SREFs from CSV… (Arrange) is the wafer/stepper-job workflow: read a coordinate CSV and place one SREF of a chosen cell at every row. Recognised columns, in this fixed order — x, y (required), rotation, magnification, reflect, cell (all four optional) — mirror the marker importer's own CSV idiom (View navigation): comma or tab delimited, a header row auto-detected and skipped, # comments and blank lines ignored. x/y are read in the unit picked in the dialog (µm/mm/nm), converted to integer world nm. The cell column, when present, overrides the dialog's chosen cell for that row only — useful for a job file that mixes die types. Every row the file can't use is refused and counted, never silently dropped: a malformed x/y/rotation/magnification/reflect value, a cell naming a cell that doesn't exist, a row that would place a cell into itself, or one that would create a reference cycle. The dialog previews the valid/refused split (with reasons) before anything is placed, and refuses the whole file up front — naming both the requested count and the limit — over the same 2000-copy cap Polar array uses. Nothing is placed until you press Place; a mixed file places only its valid rows, and the confirmation toast states both counts. One undo step for the whole file, regardless of row count.
Generate identifiers… (Arrange) stamps systematic labels in one undo step — the no-scripting replacement for Clewin's label function. Array labels mode writes an A1..H12 grid (rows × cols, configurable pitch, alpha/numeric row & column schemes, prefix, A1/1A order) across a die array; Mask ID block mode stacks large human-readable lines (project / designer / version / mask turn). Both use the normal text + font pipeline, so the labels flatten to polygons on GDS export like any other text. The column/row pitch defaults to 1 mm — the same physical pitch whatever display unit you're working in, not a value in that unit.
Search & replace cell references
Ctrl+Shift+F (or ) opens a dialog that rewrites every SREF/AREF whose target is the "from" cell to point at the "to" cell instead. The dialog shows a live count of how many refs will be affected before you commit. Scope is the whole document.
Find shapes & instances
Ctrl+F (or ) opens a searchable list of shapes and instances; it re-opens with your last query, selected so typing replaces it. A text match lists its string (text “PAD_A” 20/0); other shapes list their area. Predicate grammar (terms separated by space = AND):
layer:N— only shapes on layer idNdatatype:N— only shapes on datatypeNkind:shape|path|text— restrict by shape kindref:CELL— match SREF/AREF whose target isCELLtext:NEEDLE— substring match on text-shape contentsarea>NUM/area<NUM— true polygon area filter (in nm²; bbox area for non-polygon shapes)width>NUM/width<NUM/width=NUM— path width filter (in nm) — e.g.kind:path width<450flags sub-min-width routes as a cheap pre-DRC pass
A value that contains a space goes in double quotes: ref:"Block 1", text:"MARK A". Inside the quotes, \" is a quote and \\ a backslash. A quote that is never closed is refused with a reason, and nothing is searched. Everything after the key's first colon is the value, so ref:LIB:CELL finds LIB:CELL, and a quote in the middle of a value (ref:A"B) is an ordinary character.
Query numbers are always nm / nm², whatever your display unit, and every shape is tested — a box or boundary has no width, so it counts as width 0 and width<450 matches it too (add kind:path to ask about paths only). Select by property below differs on both counts: it takes the display unit and skips objects a property does not apply to. A number typed with a unit (area>1mm2, width<5um) is refused rather than read as nm, and the message offers the nm form (area>1e12, width<5000); a non-integer layer or datatype (layer:1.9) is refused too.
Scope is a three-way toggle:
- Active cell — only the cell you're currently editing.
- Active cell and below — the active cell, plus every cell it reaches transitively via SREF/AREF (cycle-safe; each referenced cell is searched once). A match found this way is reported once against the cell that actually owns it, not once per placement — a leaf cell instanced 500 000 times via one AREF still shows as a single hit, tagged
[CELL_NAME]. - Whole document — every cell in the file, whether or not the active cell can reach it. This is the only scope that also surfaces orphan cells and unrelated sibling branches.
Click any row (or press Enter in the query box, for the first row) to centre the viewport on it and select it — a match on a hidden or locked layer is centred on but not selected, and a message says which layer to show or unlock, with a button (Unlock 20/0 & select, Show 20/0 & select) that does it and selects the match in one step — a show is a view change like the Layers panel's eye, an unlock is an edit you can undo; for a match owned by a cell other than the active one (either multi-cell scope), this also enters that cell (KLayout-style "show as new top") so the match is visible and editable, and the breadcrumb reflects the new context. Select all selects every match in the active cell a user can select, at once — shapes on hidden or locked layers stay listed but are skipped, and the dialog says how many (cross-cell matches aren't included, since canvas selection is per-cell). While the Select by property Value below is empty, the orange Select matching button does the same thing for a typed query — the note beside it says "Selects the Query's N matches (Value is empty)" — or, with Append to current selection ticked, "Adds the Query's N matches to the selection", keeping what was already selected; once you type a Value (or pick any value) the button answers the property section instead. (You can also select every shape on a layer from the Layers panel — hover a row and click the marquee icon.)
Select by property (the section at the bottom of the same dialog) builds a selection from one test instead of a typed query: pick an Object type (All objects, Any shape, Boundary, Box, Path, Text, Instance (SREF), Array (AREF)), a Property that applies to it (Layer/datatype, Path width, Area, Bbox width, Bbox height, Target cell, Text string), a Compare (=, ≠, <, >, contains for text and cell names, or any value) and a Value, then press Select matching (or Enter in the Value field). Lengths are typed in your display unit and area in its square (the unit is shown beside the field); a layer value is N (every datatype of layer N) or N/D; text contains ignores case, = does not. The live count beside Append to current selection says how many objects match before you commit; when your display unit is not nm, the threshold is echoed beside it in nm too (< 0.45 µm = 450 nm), so it can be compared with a query's nm numbers. Rules worth knowing:
- It works on the active cell only, whatever the Scope toggle above says — canvas selection is per-cell.
- An object the property does not apply to never matches —
Path width ≠ 1under "All objects" is a question about paths only. - Shapes on hidden or locked layers are never selected; the count says how many matched but were skipped. A path with no width has no area, so an Area test skips it.
- Tick Append to current selection to add the matches to what is already selected; untick it to replace the selection.
- It is a view act, like
Ctrl+A: nothing is added to undo and the file is not marked changed. - A value that is not a plain number (
abc,1,5,0x10), a negative size or a malformed layer is refused in place — the field turns red and the reason appears beside Select matching, which then selects nothing. On a very large cell the count showsCounting… N%for a moment while it works in the background; the dialog stays responsive.
Convert path to polygon (Arrange → Convert path to polygon)
Design-rule width/spacing/area checks and the boolean/layer operations above all work on filled polygon area — a path shape (a centreline plus a width) is invisible to them, so a routed trace can carry a sub-minimum width or overlap a keep-out layer and neither DRC nor a layer boolean will ever see it. Select one or more widened paths and run this to replace each with a boundary polygon tracing its exact stroked outline — same layer, same datatype, joints mitred and end caps honoured (flush / round / square) exactly as the path already drew. A path carrying custom per-end extensions (GDS PATHTYPE 4) is extended along its centreline before stroking, so the polygon has the same footprint a GDS reader would draw for the original path rather than shrinking by the extension at each end. Once converted, the geometry is checkable and boolean-able like any other polygon.
Every selected path lands in exactly one outcome, and the toast accounts for all of them:
- Converted — a real, positive-width path became a polygon.
- Zero-width — a bare centreline has no area to stroke, so it's left alone rather than fabricating geometry that was never drawn.
- Too narrow — width is real but rounds away to nothing once snapped to integer nanometres; left alone rather than silently vanishing.
- Construction — a construction-flagged path (draw-only aid, never exported) is left alone rather than being turned into real, exportable geometry.
Any non-path shapes in the selection pass through untouched and aren't counted. Single undo step for the whole selection.
Close open contours (Arrange → Close open contours…)
Outlines drawn in AutoCAD are very often not polygons — they are separate LINE and ARC entities whose endpoints happen to meet. They look correct on screen, but they enclose no area, so they export to GDS as PATH records and expose nothing. The failure is invisible until the mask comes back blank.
This command chains those open paths into filled polygons, merges duplicate or overlapping segments, and drops zero-length remnants.
It also runs automatically on every DXF, DWG and SVG import, on by default. A Close open contours & heal geometry checkbox appears on the DWG and SVG import dialogs (DXF has no import dialog, so the Heal CAD imports (close open contours, drop duplicate segments) toggle in File → Setup → Settings decides on its own); untick it to import the file exactly as drawn. GDS, OASIS and CIF are never healed — they carry a real area primitive, so an open path there is a path you meant, not a CAD export artifact. Whichever way it's set, the import tells you how many open segments it found — with healing on, it also states what changed (contours closed, gaps bridged, duplicate segments merged, zero-length segments dropped), and if any contour stays open, or a join bridged a gap wider than 0.1 µm, the notice is a warning that names the widest gap and its layers; with healing off, it names the count and points you at this dialog or the Settings toggle. A genuinely clean file says nothing. For a DXF or DWG import the endpoint tolerance scales with the drawing: 0.1 % of its diagonal, kept between 0.1 µm and 10 µm, so a 10 mm chip outline whose corner misses by 2 µm closes.
Two settings, both of which exist because neither has a safe universal value:
- Endpoint tolerance (µm) — how far apart two endpoints may be and still be joined. Within 0.1 µm they become one point; farther apart, both are kept and an edge bridges the gap, so healing never moves a corner. A gap wider than 0.1 µm is bridged only when it lies in a line — the bridge runs within 45° of a segment it joins — never when it hops from one line to another: two parallel traces 5 µm apart, a comb's free teeth, or two electrodes whose ends face each other stay as drawn, and a slot left open at one end is closed only when it encloses the minimum area below. An outline whose only miss is such a hop (a rounded corner whose arc misses its line sideways by 0.3 µm) is closed the same way whichever order the file lists its pieces in. Raise it if a drawing refuses to close; lower it if two separate features are being welded together. Defaults to 0.1 µm for DXF and DWG. For SVG import, which has no physical unit to anchor a fixed tolerance to, the tolerance instead scales down automatically with the drawing's own size — so a small icon-scale SVG doesn't get its opposite sides welded together, while a real mm-scale SVG heals the same as DXF/DWG.
- Minimum area to bridge a gap (µm²) — a chain that never closes is left alone unless it encloses at least this much area. This is what stops leader lines, centrelines and dimension marks — open by nature, enclosing nothing — from becoming zero-width slits of exposed resist, while still letting a real outline with a sloppy gap close. Defaults to 10 µm².
Chaining never crosses a layer or datatype boundary, and never touches a path that already has a width. Every removal is counted and reported. A chain that stays open keeps the paths it came from, but exact-duplicate and overlapping segments are merged away and zero-length remnants are dropped — the manual command runs this as a single undo step.
Layer operations (Arrange → Layer operations…)
The selection-based booleans above replace whatever you select. Layer operations runs the same four ops (union / difference / intersect / XOR) between two whole layers instead, and is non-destructive: input layers A and B are left untouched, and the result is stamped onto a separate output layer — pick an existing layer or type a new layer/datatype number inline to create one on the spot (named the way the Layers panel's + names a new row: Layer 4, or Layer 4/7 for a non-zero datatype). It refuses to run if the output layer is also input A or input B (writing back onto a source layer would just pile the result on top of the geometry that produced it) or if the output layer is locked.
Grow and Shrink size a single layer by a distance instead — layer B is ignored and a Distance box (in your display unit) replaces it. This is true morphological sizing with round corners (a Minkowski offset), the same construction the design-rule checker uses, which is what stops a shrink from filling in a concave notch — a shrink that quietly welded a dumbbell's thin neck back into solid metal is the exact bug this avoids. Because the band construction costs roughly eight times a boolean on the same layer, grow/shrink is capped by input vertices (200 000) rather than shape count; past that it refuses immediately instead of grinding.
Tick Flatten instances first to expand every SREF/AREF in the active cell before collecting each side's shapes — off, only the active cell's own shapes on that layer are used, so geometry that only exists inside an instance is invisible to the op (same rule DRC uses, §8 below). Large jobs run on the same cancellable background worker as the selection-based booleans, above a 10 000-vertex threshold. The whole operation — including creating the output layer if it didn't exist — is one undo step.
Wafer layout (Arrange → Wafer layout…)
Steps one die cell across a round wafer with dicing lanes, so you don't hand-place hundreds of identical instances. Pick a 100 / 150 / 200 mm preset (each with its standard flat or notch orientation feature already set) or a custom diameter, choose the die cell, its pitch, and an edge exclusion (a keep-out ring near the rim where dies never get placed even if they'd fit). A live stats preview shows how many dies will be placed and how many candidate grid positions get dropped at the edge or by the orientation feature's keep-out, before you commit anything. Dies are instanced as full-width AREF rows (one array per row, not one SREF per die), so even a wafer with thousands of dies stays a handful of objects. Optional dicing lanes are drawn as thin rectangles derived from the pitch, on their own layer. One undo step places the whole wafer.
CIF export and import (File → Export ▸ Export CIF…)
CIF (Caltech Intermediate Form) is Clewin's third interchange format. Glyph
reads it (, or drag a .cif in) and writes it
().
Coordinates are written in nanometres via CIF's DS n 1 10 scale, and
layers are named L{layer}D{datatype} — the convention KLayout uses — so a
layer number and its datatype stay distinct instead of merging. A layer with a
real name is written the way KLayout's own CIF writer names one,
L{layer}D{datatype}_{NAME} — upper-cased, letters, digits and _ only, so
Align marks is L1D0_ALIGNMARKS to another tool. Glyph also writes the exact
name into the layer's CleWin comment (below), so re-opening the file in Glyph
gets Align marks back, spaces and case included.
Import colours. A layer newly discovered on import gets a distinct colour (and hatch stipple)
from the same default palette a GDS import uses, in the order layers are first encountered — not
one flat grey for every layer. A layer whose colour the file genuinely declares (a CleWin (CleWin: …) comment, below) still wins over the default.
What CIF cannot carry, stated plainly rather than lost quietly:
- Widened paths become polygons. CIF's wire record has no portable end-cap rule — KLayout reads a bare wire back with its ends extended by half a width — so a path is stroked to its exact outline instead. The geometry is right; the "this is a path" structure is not preserved. Zero-width centrelines are kept as wires.
- A magnified reference is flattened. A CIF call carries mirror, rotation and position but no scale, so a ref placed at anything other than 1× is expanded into its parent. Every other reference keeps its hierarchy.
- Layer stipples, visibility and field tone have no CIF equivalent — export
the layer map alongside () to carry
the rest of the palette. Fill/frame colour now round-trips through
Glyph's own inert
(CleWin: idx num/fill frame)comments (see below) — a tool other than Glyph will simply ignore them. - Text becomes a plain label: font, size and alignment are dropped.
Exporting also names most of the losses above in a toast right after the "Exported" confirmation — the magnified-reference flattening, the CleWin-comment-only colour, the dropped layer stipple/visibility/field-tone, and the text styling that doesn't survive — so the reminder shows up at the moment it matters, not only here. It carries a Details button, which ranks it ahead of plain notices in the message stack, so it is not the one folded away into "+N more". (The widened-path-to-polygon change above is not repeated in the toast — the exported geometry is correct either way, so there is nothing there for a warning to flag.)
Geometry, hierarchy and layer assignment are checked against KLayout and gdstk on
every release (npm run validate:cif); the four points above are the losses on
that geometry path.
Opening a CleWin library. A CleWin structure library is itself a .cif, and
it carries each symbol's parameter declarations and its source script inside
CIF comments. Glyph reads them: open the file and the imported symbol shows the
parameters CleWin declared — name, default and the valid range — in the Properties
panel, along with a Show source script toggle. The layer colours CleWin stored
are picked up too, so an imported stack is not uniformly grey.
Those parameters are read-only, and the panel says so. Glyph does not run the C script that consumed them, so the geometry in the file is already generated and changing a number here could not rebuild it. You get the geometry, and you get a record of how it was made — which is enough to redraw or re-parameterise it in Glyph deliberately, and honest about what it is not. Imported script text is stored and displayed only; Glyph never executes it.
Saving a CleWin library back out round-trips its parameter surface. Until
v0.94.0, Export CIF… silently dropped an imported symbol's declared
parameters and script text — the geometry above's "only losses" claim was
wrong for exactly this field, since it was never on that list at all. Exporting
a cell that carries CleWin-declared parameters now re-emits its (C5Param …)
declarations and (CleScript …) text verbatim, so a colleague still using
CleWin sees the same Properties → Parameters tab and script on reopening. This
is passthrough of the same read-only values described above, not new editing
capability — a parameter you cannot change in Glyph before saving, you still
cannot change by round-tripping through Glyph.
Layer colours also round-trip now (R32-4). Every export writes a
(CleWin: idx num/fill frame) comment for each declared layer (when the
document has at least one cell — the records ride inside the first symbol,
so a cell-less document emits none), fill from Layer.color and frame from
Layer.edgeColor (falling back to the fill colour when no edge colour is
set) — not only for layers that were originally read from a CleWin file.
This closes the one gap the CleWin-import feature left open: previously a
colour picked up on import, or set in Glyph, was silently dropped again on
export. This is judged only against Glyph's own reader, never claimed as
verified against a real CleWin install — the decode this write-back mirrors
was itself inferred from observed files, not probed through CleWin (see the
CleWin-import paragraph above), so treat it as a faithful Glyph round trip,
not a guarantee about what a real CleWin will show. Two colour states do
NOT survive the round trip (C32-V1): a pure-black fill (#000000) reads
back as the default #cccccc (the importer deliberately rejects black — a
CleWin file's black usually means "unset"); and an edge colour set exactly
equal to the fill reads back as no edge colour (an equal fill/frame pair is
how "no independent frame colour" is encoded, so the two states are
indistinguishable in the file) — note the latter also moves that layer off
the edge-framed render path after a round trip. Pick an edge colour that
differs from the fill, and avoid pure black, if the distinction matters.
OASIS export and import (File → Export ▸ Export OASIS…)
OASIS (SEMI P39) is the modern, more compact companion to GDSII used in
foundry flows. Glyph reads it (, or drag a .oas/.oasis file
in) and writes it (, or pick a .oas filename in
Save as…).
Output is compressed by default. .oas is never bound for save-in-place —
Ctrl+S on a document opened from OASIS falls through to Save as… instead of
overwriting it — because the OASIS writer is lossy in two small, deliberate
ways: a round-capped path exports with a squared cap instead (OASIS has no
round-cap concept); and bitmaps and construction shapes are dropped, the same
exclusion every Glyph writer applies. Text size, font and PRESENTATION
justification now survive an OASIS round trip — OASIS's TEXT record has no
field for any of them, so they ride as element properties alongside the
string, layer, texttype and position, and are read back the same way, so a
GDS → OASIS → GDS trip no longer resizes your labels. Layer names round-trip
too — except for a layer Glyph itself named on import because the file had no
name for it (shown as "Layer 1", "Layer 2", …); that placeholder is never
written back out as if it were a real name, so opening a nameless-layer
OASIS file and re-exporting it doesn't invent names its author never gave it.
When a nameless import carries two datatypes of one layer number — GDSII,
OASIS, and a .lyp/CSV layer map can all do this — only the non-zero
datatype's placeholder is suffixed (e.g. "Layer 1" and "Layer 1/10"), so the
rows stay tellable apart instead of both reading the same thing.
Exporting also names the round-cap loss in a toast right after the "Exported" confirmation, so a round-capped design doesn't have to be checked against this section to notice its caps came out square.
DXF export (File → Export ▸ Export DXF…)
Glyph writes AutoCAD R2000 ($ACADVER = AC1015) — the oldest widely
supported DXF flavour that still carries blocks, arrayed inserts and
constant-width LWPOLYLINE, so the file opens in essentially anything that
reads DXF. See "DXF import" below (File I/O) for the read side of this exchange —
this section is the write side, documented on its own because until now it
had no section at all.
A DXF written from the editor is in your display unit (File → Setup → Settings → Display
units: nanometres, micrometres or millimetres), and the header's $INSUNITS
says which — 12 nm, 13 µm, 4 mm — so a mechanical-CAD tool opening it
reads the drawing in the unit you work in. Every length (coordinates, path
widths, text heights, array spacing) keeps nanometre precision in any unit, and
a label with no size of its own is written at the 1 µm Glyph draws it, whatever
the unit. The standalone converter always writes nanometres ($INSUNITS = 12,
the same "1 unit = 1 nm" convention as CIF's DS scale above, so every
coordinate is an exact integer). A file Glyph writes reopens (in Glyph, or any
tool that honours $INSUNITS) at the same physical size.
Boundaries and boxes become closed LWPOLYLINEs; paths become open ones
with a constant width. A boundary/box outline drops its own repeated
closing vertex (the closed flag already implies the wrap edge) and writes
exactly; a path carries its GDS width in LWPOLYLINE's constant-width group
— DXF's own "ribbon path" model, matching a GDS PATH's width exactly. A
path's end-cap style (pathType) has no DXF counterpart and is lost: every
exported path reads back flush-capped regardless of how it was drawn.
Zero-width paths still export, as a zero-width polyline.
Layers keep the (layer, datatype) pair distinct, via the same
L{layer}D{datatype} naming CIF uses above (L{layer}D{datatype}_{Name}
when the layer has a real name, so the human label survives alongside the
pair) — DXF's own symbol table has no datatype, so without this two rows
sharing a layer number would collapse into one DXF layer. That is the naming
KLayout's own DXF writer uses and its reader decodes, so KLayout opens a Glyph
DXF with every layer on its own (layer, datatype) and named — except a layer
on 0/0, which KLayout's reader gives to the DXF's mandatory layer 0 (the
same happens to KLayout's own DXF), and KLayout shows a non-ASCII character in
a name as its \U+XXXX escape. A hidden Glyph
layer is written switched off (a negative colour index), never dropped,
and a locked layer carries the LAYER table's own locked flag. Re-opening a DXF that
Glyph wrote turns L1D0_Metal back into a layer named Metal on 1/0. DXF
files from earlier Glyph versions used Metal_L1D0 instead; those still re-open
the same way, because that ending is decoded only in files carrying Glyph's own
writer mark, so a foreign layer that merely ends in _L1D0 keeps its full
name. Non-ASCII characters in layer names,
block names and text (µ, ·, 日) are written as \U+XXXX escapes — the
form an R2000 reader such as ezdxf decodes — and read back exactly.
On import Glyph also decodes the older \M+ double-byte escape AutoCAD
wrote for Japanese, Chinese and Korean text (code pages Shift-JIS, Big5,
Korean and GBK), in names and text, the way ezdxf does.
Layer colour is written twice — exact, and as the nearest AutoCAD Color
Index (ACI). Each LAYER record carries the colour snapped to the nearest
entry (by squared RGB distance) of a small, fixed 16-swatch ACI palette
(ACI 1–9, four mid-palette accents at 30/90/140/200, and three greys at
250/252/254), which is the only colour field DXF R2000 defines, and also the
exact #rrggbb as a true-colour value (group 420 — introduced with R2004,
written as an extra tag a strict R2000 reader skips). Glyph's own reader
prefers the true colour, so a Glyph → DXF → Glyph trip gets each layer's exact
colour back, and ezdxf was measured reading it too. One exception: a colour
the DXF import lightened for the dark canvas is written back as the file's own
ACI, with no true colour, until you recolour that layer. A layer setup saved
and loaded back (.lyp or .csv) does not carry that source colour (KLayout
reads an extra .lyp field but drops it on its next save, measured), so after
one the layer writes its lightened colour both ways. A tool that looks only
at the ACI slot sees a genuinely lossy colour, not a close approximation:
#00ffaa and #ffee00 land on ACI 4 (cyan, #00ffff) and ACI 2 (yellow,
#ffff00), nowhere near the original hue. If the recipient's tool shows only
ACI colours and needs your house colours, hand off a .lyp/.csv layer map
alongside the DXF ().
References become blocks and inserts. An SREF becomes a block INSERT,
preserving position, rotation, mirror and scale exactly — DXF's INSERT
carries all four, unlike CIF's call, so no reference is ever flattened for
scale reasons the way a magnified CIF reference is. A rectangular,
axis-aligned AREF becomes a native arrayed INSERT (DXF's own row/column/
spacing groups); anything sheared or rotated off-axis is expanded
instance-by-instance instead, up to 20 000 instances — past that only the
four corner instances are written, with a 999 comment at the top of the
file recording that the array was truncated (the same policy Export SVG…
and Export figure… use for an oversized array).
Text collapses to a plain TEXT entity in the STANDARD style — font,
letter spacing and PRESENTATION justification are not concepts Glyph maps
onto anything in DXF, so they are dropped; position, rotation and size (as
the TEXT height) are kept exactly, with the justification already baked
into the insertion point so the text lands in the right place even though
the justification groups themselves are never written.
Construction shapes, bitmaps and Cell.dimensions are excluded — the
same contract as every other Glyph writer.
Structural validity (never colour, which is cosmetic by nature here) is
checked against the independent ezdxf Python library's Auditor on
every release (npm run validate:dxf), which treats an auto-fix as a
failure, not just a hard error — a round trip through Glyph's own DXF reader
is deliberately never used as that check, since a lossy writer and a lossy
reader can agree with each other while both are wrong.
Grid presets (Shift + a number key)
Ten snap steps live on the number keys, Shift+1 through Shift+0. Pressing one
switches the grid to that fixed step and turns snapping on; the step is shown in a
brief toast so a keypress never changes the grid silently. The current preset is
ticked in , which also lists all ten with their values. One
caveat: under the KLayout keyboard preset, Shift+8 is the same physical
keystroke as that preset's * (show full hierarchy), so grid preset 8 is unbound
there — nine presets on keys, with the ticked menu still reaching all ten.
Edit the ten values in Settings → Advanced → Grid presets. They are entered in
nanometres, shown on every row regardless of the display unit set at the top
of the dialog — a grid is an exact integer distance, and rounding it through a
display unit would change it. Reset restores the default ladder (1 nm to
100 µm).
They take Shift because the bare number keys belong to the KLayout keyboard
preset's hierarchy levels, and both migrant habits are worth keeping. Every one of
the ten is remappable in like any other command.
< and > step the live grid to the next finer/coarser stored preset without
needing to remember which slot it is in — the same idea as KLayout's
increase/decrease-grid keys. At either end of the ladder they clamp rather than
wrapping around. Both are also in and remappable like any
other command.
EPS figure export (File → Export ▸ Export EPS…)
writes an Encapsulated PostScript figure — the vector page format Clewin emits and every LaTeX toolchain consumes. It uses the publication look by default (white ground, solid fills, outlines, a scale bar and a legend), because reaching for EPS means making a figure for a paper.
Its one advantage over SVG is that the figure has a real printed size: it is written at a width in millimetres, so it lands in your document at a known width instead of at whatever the importing tool guesses. For full control over the annotations, use instead and choose EPS as its Format — when its Size is set to Print, the mm width you enter is the EPS page width.
Two things PostScript cannot do:
- No transparency. A layer drawn at partial opacity is blended onto the page background when the file is written. That looks identical for geometry that does not overlap; where two translucent layers cross, the blend you see on screen is not reproduced. The publication preset uses full opacity, so this only affects a deliberately translucent export.
- Base-14 fonts only. All text is written in Courier — this includes any
text-kind shapes in your design, not just the scale bar / legend / title annotations discussed above. Any character outside printable ASCII becomes?rather than a silently wrong glyph, and a rotated text shape prints upright: text is set with a PostScript font rather than flattened to the glyph outlines the canvas rotates.
What survives each format
A quick-reference for "if I hand this file to someone else, what changes?" —
each cell states the honest behaviour of that format's own writer, not a
goal. GDS is the baseline every other row is measured against, since it's
Glyph's native, lossless round trip (bitmaps, construction shapes and
Cell.dimensions are the one universal exception — every writer below
excludes all three, so that column isn't repeated per row).
| Format | Geometry | Layer pairs (layer + datatype) | Colours | Text styling | Refs / arrays |
|---|---|---|---|---|---|
| GDS | Exact — Glyph's own native, lossless format. | Exact — layer + datatype ARE the format's own key. | None — GDS carries no colour field at all; hand off a layer map (File I/O) for your palette separately. | Position/rotation/size/PRESENTATION preserved; an imported TTF/OTF font is even embedded whole, in a private __GLYPH_FONTS__ cell your top cell references (one top cell, no added geometry; Fonts). |
Exact — SREF/AREF are native GDS records, hierarchy intact. |
| OASIS | Exact, except a round path cap exports squared (no round-cap primitive). | Exact — native layer/datatype (+ texttype) fields. | None — OASIS has no colour field either; reopening shows Glyph's own auto-assigned default palette, not yours. | Size, font and PRESENTATION justification do survive, riding as S_GDS_PROPERTY element properties. |
Exact — native placement and array records. |
| CIF | Near-exact — a widened path is stroked to its outline (the shape is right, "this is a path" isn't); zero-width paths stay wires. | Exact — L{layer}D{datatype} naming (see above). |
Preserved, but only through Glyph's own reader — an inert (CleWin: …) comment other CIF tools ignore. |
Dropped — becomes a plain label; font, size and alignment are lost. | Position/rotation/mirror preserved; a magnified (≠1×) reference is flattened into its parent. |
| DXF | Exact outlines; a path's end-cap style is lost (always reads back flush-capped). | Exact — same L{layer}D{datatype} naming as CIF (see above). |
Exact in Glyph and in any reader of true colour (group 420, written beside the nearest AutoCAD Color Index); a reader that knows only the ACI sees the nearest of its entries. | Dropped — becomes a plain TEXT entity, STANDARD style; position/rotation/size are kept, font/spacing/justification are not. |
SREF exact; an axis-aligned rectangular AREF becomes a native arrayed INSERT; anything sheared/rotated is expanded instance-by-instance (capped at 20 000). |
| SVG | Exact, but always flattened — SREF/AREF fully expanded, hidden layers dropped. | Not preserved as pairs — becomes flat coloured shapes; only the colour (not the original layer number) can round-trip, via "Split colours into layers" on reimport. | Preserved exactly, including opacity (fill-opacity). |
Emitted as SVG <text> in a monospace font — position/rotation kept, exact glyph outlines are not (flatten to boundaries first). |
None — always flattened; an over-budget array draws a footprint outline plus a bounded sample of instances instead of every one. |
| EPS | Exact, flattened the same way as SVG (shares the same flattener). | Not preserved — flattened to coloured fills; EPS is export-only, there's no reimport path to preserve them for. | Preserved but flattened — a translucent layer is composited onto the page background at write time, so an on-screen overlap blend is lost. | Set in a PostScript base-14 font (Courier), always printed upright regardless of the shape's own rotation; non-ASCII characters become ?. |
None — always flattened, same as SVG. |
Foreign GDS element properties (preserve-only). A GDS file authored by
another tool can attach arbitrary metadata to a BOUNDARY/BOX/PATH/SREF/AREF/TEXT
element — a foundry device tag, a dose-class annotation, an LVS pin number — as
GDSII PROPATTR/PROPVALUE pairs. Glyph now carries these through a GDS →
GDS round trip byte-for-byte, in the order they arrived, duplicates
included: opening such a file and saving it back out no longer silently drops
that metadata. This is preserve-only — there is no editor UI to view,
add or edit these properties, and they do not cross into any other
export format (OASIS, CIF, DXF, SVG, EPS all drop them, the same as every
other GDS-only field in the table above). OASIS's own S_GDS_PROPERTY
mechanism for text size/font/justification is its own separate mechanism, unaffected by this — and since v0.138.0 a foreign S_GDS_PROPERTY the OASIS importer cannot model is counted and named in the import warnings instead of vanishing silently (the GDS importer likewise names properties that arrive out of record order, a layout some tools refuse outright).
Recipes (Edit → Recipes…)
A recipe is a saved, ordered list of editor commands you can re-run on any document — "run the design-rule check, then export per layer", every time, the same way. Add steps from the action picker, reorder them, save the recipe to a file, and load it again later. It is plain data: nothing in a recipe file is executed as code.
Steps can now carry parameters. Two actions run without opening their dialog when you fill in their fields:
- Layer operations — give an operation (
union,diff,intersect,xor,grow,shrink), the input layer numbers, an output layer, and for grow/shrink a distance in nanometres. This is what lets a recipe say "union layer 1 with layer 2 into layer 3" rather than just "open the layer-operations dialog". - Export per layer — name a layer number to write one mask, or leave it blank to write every layer that carries geometry.
Leaving a step's fields blank keeps the old behaviour: the action opens its dialog when the recipe reaches it, exactly as before. So a recipe you saved earlier runs identically today.
A step that names a parameter the action does not have, or gives it the wrong type, stops the recipe and says which step and why — it is not skipped. That matters most when nobody is watching: a step that quietly did nothing would let the run report success over a layout that is wrong.
Recipes are not atomic. Each step dispatches its own commands, so undo unwinds a recipe one step at a time rather than all at once.
Technology presets (File → Setup → Technology presets…)
A technology preset bundles the layer palette, the DRC rule deck (including layer-pair rules), the ten grid presets, and a default grid into one named process bundle you switch to in a single Apply — the KLayout "technology manager" idea, sized to what Glyph already has.
Three read-only starters ship with the dialog, each citing exactly where its numbers came from (shown as the row's own description text): Microfluidics (soft lithography) (the bundled Flow/Control/Vent layer palette, and the "Soft litho / PDMS (20 µm)" min-feature floor already named in Verify → Design rules…), Laser writer (1.5 µm), and E-beam (200 nm) (both using Glyph's generic three-layer starting palette plus their matching named writer preset). None of the three invents a process number that isn't already in the repo somewhere else.
Save current as snapshots your document's current layer palette, DRC rules, pair rules, grid presets and effective default grid under a name of your choice — a starter's name is reserved, so you can't accidentally overwrite it. Export… writes any preset (starter or your own) to a .tech.json file; Import… reads one back and refuses it outright if it was written by a newer Glyph than yours understands (a stated schema-version mismatch), rather than half-applying it.
Apply asks you to confirm first, and the confirm names both halves honestly because they behave differently:
- The layer palette is replaced through the same import path
.lyp/ CSV / JSON layer imports already use — one undo step,Ctrl+Zrestores your previous palette, and any (layer, datatype) pair your drawing still uses but the preset doesn't declare is kept rather than dropped. - DRC rules, pair rules, grid presets, and the default grid are session state, the same as the "Grid presets" (§8, above) and "Design rules" (§8, below) settings they overwrite — they're overwritten in place, are not on the undo stack, and applying turns grid snapping on. Any unsaved edits to them are lost.
Objects panel
The Objects tab in the right panel, below Properties, lists everything in the cell you are
editing — every polygon, path, text, bitmap, instance and array — with its kind,
its (layer, datatype), and its size. Click a row to select that object and frame
it. Type in the filter box to narrow the list by kind, layer, id or note.
It is the fastest way to answer "which object is on the wrong layer" on a symbol that renders wrong. A few details worth knowing:
- The list covers this cell's own contents, not the flattened hierarchy — an
instance appears as one row saying what it points at, and an array as one row
with its instance count (
3×4 = 12). - Construction guides and reference bitmaps are listed, each noted as not
exported, so a stray object is visible rather than hidden by the same rule that
keeps it out of your
.gds. - The list is virtualized, so a cell with hundreds of thousands of objects scrolls normally. Past 200 000 rows it says so rather than quietly stopping.
- Each row's size picks its own unit per axis and shows width and height stacked on
two lines (
1.85 mover× 677.40 µm), so a CAD-scale import (millimetres or metres) never truncates a single line in your fixed display unit; hover a row for the full-precision size in your chosen unit.
There is no per-object show/hide. Visibility is per layer and per cell; hiding an individual object would cost drawing speed on every frame for every design, and selecting the object plus isolating its layer covers most of the same need.
Results panel and importing a KLayout report ()
The Results tab in the right panel (alongside Layers, Cells and Objects) lists every published
finding — a DRC run (§8, above), a .gds diff (File I/O), CSV review markers (View navigation), or a KLayout DRC
report database (.lyrdb) imported via — grouped by rule (a DRC group reads its kind, e.g. Min width) and
severity, each row ending in its measured value against the limit (20.00 < 50.00 µm), with the same F2 / Shift+F2 stepper the canvas overlay uses. Importing a .lyrdb asks
before replacing markers you already have, as a CSV import, a diff and a connectivity check do (View navigation;
a design-rule check asks only when some of the markers shown did not come from one). Click a
row (or a group heading) to waive it — waived findings stay in the list, struck through, but
stop drawing on the canvas and stop counting toward a pass/fail summary; Undo on a waived row
un-waives it. Waivers are per (rule, location) and are a session-only review aid, like the marker
list itself — they are not saved with the .gds. Before anything has been published, the empty
Results tab shows a "Run design rules…" button that opens the same dialog as ; the command palette also finds it by "waive" / "ignore" / "suppress", which waives whatever
finding the F2 stepper is currently on. Once a run has published findings, a "View report"
button in this tab reopens the full text report at any time — even after you've dismissed the
toast that first announced it — so dismissing that toast never loses the detail.
Findings belong to the tab they were produced in. Switch to another tab and back, and the markers, the Results list, your place in the F2 stepper and the "View report" text all come back with it; a new tab starts with none. Closing a tab, or opening another file into the same tab, discards them — they describe a document that is no longer there (notices about the file just opened, such as its skipped-content list, are kept).
Check connectivity (Verify → Check connectivity)
A read-only companion to Connect ports (Instances: SREF and AREF): it finds every connector-bearing instance whose port
is not actually joined to a route, and publishes each dangling end as a marker — step through them
with F2 / Shift+F2, exactly like a design-rule violation. It never touches your drawing or the
undo stack; use it after routing a microfluidic/photonic layout to catch a port you forgot to wire
up before you export the connectivity graph (, File I/O).
Alignment marks across a mask series (Verify → Place alignment marks… / Check mark alignment…)
Place alignment marks… puts one mark type at a list of wafer coordinates on every layer you tick, as a single undo step — so a five-mask series gets its marks from one action instead of twenty-five placements that have to agree by hand.
Emission is tone-aware. On a clear-field level the mark is drawn as geometry. On a level whose field tone is dark, the same mark is emitted as a clear window — the mark shape knocked out of a surround — because that is what prints the same image on a dark field. Drawing solid geometry there would print its complement, and the aligner would not find its mark. The dialog says which of the selected levels are dark-field before you commit.
Check mark alignment… is read-only: it finds small shapes on each layer, clusters them into marks, matches marks across layers, and reports any site where the layers disagree by more than 1 µm or where a layer is missing a mark the others have. It expands SREF/AREF instances first, so a mark that lives inside a sub-cell on one level and is drawn directly on another is still compared. On a document too large to expand (a full wafer step-and-repeat) it falls back to the active cell's own shapes and says so in the report rather than narrowing silently.
It is purely geometric, so it works on marks that were drawn by hand, imported from a foundry file, or copied between documents — nothing has to be tagged as a mark.
Related pages
- Boolean operations and layer merge — Union, difference, intersect, and XOR selected shapes, and merge every shape on the active layer into one polygon.
- Design-rule check (DRC) — Run min-width, min-spacing, and min-area checks with hierarchy flattening; step through violation markers on the canvas.