Skip to content

0.4.0 — the imaging exits stop shipping a look, and rulers become data

Choose a tag to compare

@klinkdev2026 klinkdev2026 released this 19 Aug 01:43
· 45 commits to main since this release

This release breaks every existing call to the four imaging tools.
They each take a new required style argument. Nothing else changes —
if you do not use imaging.*, upgrading is a no-op.

本版对四个 imaging 工具是破坏性变更:每个都多了必填的 style 参数。
其余部分不受影响,不用 imaging.* 的话升级无感。

Why / 为什么

klink is the mechanism layer. It knew how to build a Principled BSDF, stage a camera, dilate an SEM rim and lay out a page — and it also held the numbers: sun energy, camera lens, film transform, beam blur, grain, page colour, the colour of every atom in a lattice figure. Those are not mechanism. They are taste, tuned by one person against one device, and a library that ships them is deciding what your process looks like.

So klink now ships none of them, and refuses to guess. A render with no style declared is an error naming the file to copy, rather than a picture drawn with somebody else's judgement.

klink 是机制层。它知道怎么搭 BSDF、怎么架相机、怎么画 SEM 边缘增亮、怎么排版一张图——但它同时还攥着一堆数字:太阳能量、镜头焦距、胶片色彩管理、束流模糊、颗粒、页面配色、晶格图里每个原子的颜色。那些不是机制,是某个人对着某台设备调出来的审美;一个库把它们随包发出去,就是在替你的工艺决定长什么样。

所以 klink 现在一个都不带,也不猜。没有声明 style 的渲染会直接报错并指出该抄哪个文件,而不是用别人的判断画一张图给你。

Upgrading in three steps / 三步升级

1. Get the style files. They ship with the package:

klink update            # refreshes example_template/, touches nothing of yours

You now have four files under example_template/imaging/:

file exit
section_style.py imaging.xsection_run (only when render=true)
sem_style.py imaging.sem_top
viewer_style.py imaging.render3d
blender_style.py imaging.blender

Each is a documented walkthrough: every number says what it controls, what happens if you raise or lower it, and where it came from. Copy the ones you need out of example_template/ before editing — klink update refreshes that directory.

2. Turn one into JSON. The MCP tools take a path, not a Python object, and each style file writes its own:

python sem_style.py        # -> sem_style.json

From Python you can skip this and pass the object directly.

3. Pass it.

  imaging.sem_top {
      stack: "stack.json",
+     style: "sem_style.json",
      output_dir: "figs"
  }
- render_sem_png(gds, STACK, "sem.png", out_color="sem_c.png")
+ render_sem_png(gds, STACK, "sem.png", STYLE, out_color="sem_c.png")

A section GDS has no look, so imaging.xsection_run without render still needs no style at all.

三步:klink update 刷出四个 style 文件 → python sem_style.py 生成 JSON → 调用时加 style=。
截面只要 GDS(不加 render)时完全不需要 style。

Two more things that will bite / 另外两个会绊人的地方

Stack layers need a colour. A VisualStack layer must declare color, unless it is kind="lattice" and drawn as atoms. There is no default colour any more.

Lattice figures need their species declared. blender_style.lattice.species must contain an entry for each atom the motif produces (C, or Mo and S). A missing one is an error naming the species and listing the ones you did declare.

层必须声明 color(画成原子的 kind="lattice" 层除外);晶格图必须声明每个原子物种的颜色和半径。

Also new / 顺带新增

  • SEM views get a scale bar. There was previously no way to ask for one, in a picture calling itself an SEM view. It rounds to a 1/2/5 length and sits on a contrast plate so it stays readable over bright metal.
  • window_um magnifies. width_px only ever added pixels to the same field of view — which is why the scale bar never changed with it. A window changes the field, and the bar follows.
  • z_window_um and axis reach the cross-section tool. Without a window the engine's multi-micron substrate fills the frame and your device is a hairline across the top. This is the single most common reason a section looks wrong.
  • Rulers are data. annotation.list / get / insert / update / delete / clear / measure. A ruler lives in the view, not the layout — invisible to selection.get and to any saved GDS — so these are the only way to read one. imaging.xsection_run cut_from_ruler=true sections along the ruler you drew. A multi-segment ruler is refused with its segments listed rather than quietly flattened to a line you never drew.

Fixed / 修复

  • The die render decided for itself what was metal. A luminance guess metallised 11 of 15 materials in a plain CMOS stack — the pale things there are substrate, wells, implants and oxides, while tungsten and silicide are dark — and since a metallic surface does not read as see-through it also defeated declared transparency, hiding every plug inside an opaque dielectric.
  • A Chinese step name rendered as tofu boxes, silently, into the PNG, the film strip, the GIF and the sidecar hash. Labels now resolve a CJK-capable face by asking the font whether it actually has the glyphs, and report any character no installed font can draw.
  • Step names that sanitise to nothing no longer leave dangling underscores in filenames.

If something used to work and now does not / 报错对照

error what it means
style=... is required this change — follow the three steps; the message names the exact file
'noise' is missing grain a hand-written style JSON; every field is required, start from the example
color is required (#RRGGBB) a stack layer without a colour
this motif contains a 'S' atom and the style declares no lattice.species['S'] add the species to your blender style

Two blind tests ran against this release before it was tagged — one on a fresh klink init project, one through the MCP tools against a live KLayout session — and the defects they surfaced are fixed in it.