> blog // engineering

Text the way Windows draws it: ClearType in Neper

October 18, 2026 · lib/e/text/tthint.e, lib/e/gfx/cleartype.e

Neper's Windows look now draws its text as hinted ClearType, the way Windows itself does, instead of grey anti-aliasing. Against 77 native Windows dark captures the number of pixels that differ from Windows fell from 30,800 to 11,321. It is closer, not identical, and this post says how it works and where it still differs.

What ClearType is

A colour LCD pixel is three stripes side by side: red, green and blue, in that order. Ordinary anti-aliasing treats the pixel as one dot and shades it grey. ClearType treats the three stripes as three separate dots, so the screen has three times the horizontal resolution for text. A vertical stem can start a third of a pixel to the right and the neighbouring stripes show it.

Lighting stripes independently would put a coloured edge on every glyph, so ClearType filters: each stripe's brightness averages a window a few stripes wide. That keeps the extra resolution while spreading the colour enough that the eye reads a sharper edge instead of a rainbow. The coloured fringes you see when you zoom in are the stripes; at normal size the eye blends them.

The second half is hinting. A TrueType font carries small programs, in bytecode, that move the points of each outline at a given size so that stems and crossbars land on whole pixels. Without them an e at 12 pixels is a smear; with them the crossbar is one crisp row. Windows runs those programs, and the shapes it draws depend on running them the way Windows does.

How Neper does it

Neper's Windows look is compared against real Windows controls, and text is most of the pixels in a control, so the text has to match too. Three pieces do it, all written in Neper:

Pen positions follow Windows too: each glyph advances by its hinted whole-pixel advance, and the baseline sits on a whole pixel row.

It is a switch on the scene, not a global change:

scene.set_text_aa(.Grayscale)   // the default, and the only mode of every other look
scene.set_text_aa(.ClearType)   // what the Windows look asks for

$ NEPER_TEXT_AA=grayscale ./app   # draw the Windows look in grey; =cleartype forces it for any look

Setting the Windows look turns ClearType on. Every other look (Neper, Linux, Cupertino, Material) stays greyscale and unchanged. The fonts, Segoe UI and Tahoma, are read from C:\Windows\Fonts at run time and never shipped. Text that cannot take the path, such as a font without instructions, a rotated or scaled transform, a non-solid brush or a translucent canvas, falls back to greyscale for that text only, so nothing disappears.

What it looks like

Both figures are a crop of the same control, magnified with nearest-neighbour scaling so each square is one screen pixel. The top row is a capture of the real Windows 11 control in dark mode, the middle row is Neper with ClearType switched off, and the bottom row is Neper's default Windows rendering.

Magnified pixels of the words New and Open from a popup menu, in three rows. Windows native and Neper ClearType both show white letters with orange and blue edges; Neper greyscale shows the same words in smooth grey shades.
Popup menu items, 7 times. Top: Windows. Middle: Neper greyscale. Bottom: Neper ClearType. The stripes decide which pixels are orange and which are blue.
Magnified pixels of the words Line one and Line two from a multiline edit box, in three rows: Windows native, Neper greyscale, Neper ClearType. The first and third rows show coloured edges; the middle row is grey.
Multiline edit text with focus, 8 times. The greyscale row spreads each stem over two pixels; the ClearType row places it in stripes, as Windows does.

The bottom rows are not copies of the top rows. In the edit crop the stem of the L has a different colour mix on its first column than in Windows, and a few letters differ by a stripe. That difference is what the numbers below count.

What we measured

The check is scripts/looks_dark_native.py. It cuts each native Windows 11 dark capture to its control, finds the best whole-pixel placement in our rendered sheets, and counts the flat-area pixels where any channel differs by more than 2 levels. With LOOKS_GLYPHS=1 the glyph pixels count too, which is the strict form used here.

Dark native captureGreyscale textClearType text
All 77 captures, pixels off30,80011,321
Radio button, rest23828
Popup menu, rest90687
Multiline edit, focused54364

The ClearType total and the three single-capture rows were rerun for this post: ClearType from the committed sheets, greyscale from a render made with NEPER_TEXT_AA=grayscale. The greyscale total is the figure recorded when the feature landed.

Not pixel-exact yet.

Of the hinted points of Segoe UI at 12 pixels, about 55 percent land exactly where GDI puts them; the rest are off by one to three 64ths of a pixel. Tahoma at 11 pixels is weaker. 11,321 pixels still differ across the captures, so the result is closer to Windows, not equal to it.

Limits

Is it good enough?

For making the Windows look read like Windows, yes. Across the 77 captures the count of differing pixels fell by about 63 percent. What remains is mostly a stem sitting one pixel off, or a colour fringe slightly too strong or too weak. You can see it when the text is zoomed to 8x, as in the pictures above, but not at normal size. It is also optional: only the Windows look uses it, and NEPER_TEXT_AA=grayscale turns it off.

For being pixel-exact, no, and we do not claim it. A control only counts as matched in our progress tracking when the text edges are judged separately from the shapes around them. Counting every text pixel as well still fails several controls: the popup menu, the check list box, the page control, the toolbar button and the disabled label in the dark theme.

What it would take to be pixel-exact

It is possible if we limit it to the fonts and sizes the Windows look actually uses, Segoe UI and Tahoma at about six sizes. It is not realistic for arbitrary fonts. The gap has four causes:

The plan is to build a ground-truth oracle first: a small native program that renders every glyph of the used fonts, sizes and text colours with real GDI. We then diff our hinted outlines and rasterised pixels against thousands of known glyphs instead of a few screenshots, fix the interpreter until every glyph agrees, fit the blend per text colour, record the fonts and settings, and add a test that fails if any glyph differs. We have not started on this; until we do, treat the figures above as close, not exact.

Try it

The design record is D5163 in docs/decisions.md, and docs/ui/looks-howto.md has the section on rendering the sheets. To reproduce the table, render the Windows dark sheets and run the check from the repository root:

$ LOOKS_GLYPHS=1 python -I scripts/looks_dark_native.py
$ LOOKS_GLYPHS=1 python -I scripts/looks_dark_native.py radio menu-popup edit-multiline-focus

If your numbers disagree with ours, we want to know.