A reader bought a tiny e-ink reader, installed a photo as its sleep screen, and discovered the display had developed faint vertical stripes. He spent hours chasing them down with two AI assistants, a dithering algorithm, and an FFT.
The Xteink X3 arrived cheap enough to satisfy curiosity. The reader installed CrossPoint firmware and loaded a few books. Then he converted a photo to a dithered black-and-white bitmap for the sleep screen, and noticed something odd: the grey pixels weren’t behaving.
Ghosts in the Grey
The first clue was a bug. Dark grey rendered as black, while light grey appeared almost white. That’s mildly annoying on a cheap device, but the reader had a hunch it wasn’t the whole story.
He tested a three-tone image, which reduced the black regions and uncovered a new problem: the viewer app showed ghostly traces of the previous screen contents in paler areas. The sleep screen didn’t suffer from this effect. That suggested two image renderers making different decisions, and the viewer app’s code was buggy.
The photo had distinctive vertical stripes that weren’t present in the original bitmap file. The reader knew next to nothing about e-ink, ESP32 development, or CrossPoint, so he turned to GPT-6 Astra in Codex. He captured the X3’s screen on his phone and dropped images into his Codex session.
What the Stripes Were Doing
An e-ink screen moves black and white pigment particles with voltage pulses. An incomplete update leaves ghosted traces of the prior image behind. To display grey, CrossPoint draws a black-and-white base and then runs a short voltage-pulse waveform to move selected pixels partway towards white. That “nudge” produces dark and light shades.
Astra found that the viewer did a fast black-and-white update and stopped, without ever performing the grey nudge. It fixed the ghosting quickly. The stripes proved harder.
Astra blamed the FloydâSteinberg dithering it had used to prepare the sleep picture. A different algorithm made no difference. It flagged the nudge waveform as worth investigating. But the two assistants couldn’t agree on what artifact they were even looking at.
Fable 5.1 in Claude Code took another pass. It averaged the brightness down each column with a sliding window 200 rows tall, which averaged away the dither texture and left the stripes visible. It then used an FFT on a one-dimensional brightness profile to measure the spacing and strength of the vertical pattern.
The stripes were roughly seven screen pixels apart. Removing either the grey or the pattern made the stripes disappear.
Why the Reader Found It Fascinating
The reader warned himself away from Astra’s naive image processing dead end and switched to Fable for another perspective. He identified the width of the stripes as significant, even as Astra struggled to find them.
The sources introduce noise: the image’s own dither pattern, sensor noise, variable focus, lens distortion, lighting and exposure variations, motion blur from his shaky hands. Fable averaged brightness down each column to filter through the mess.
The reader’s hunch paid off. The specific combination of grey pixels with neighbours of a different shade produced the vertical bands.
| Stage | Tool | Result |
|---|---|---|
| First bug | Astra | Dark grey rendered as black |
| Fast update | Astra | Black-and-white update only |
| Stripe hunt | Astra | Flailed on dithering |
| Measuring | Fable | FFT shows seven pixels apart |
The grey nudge waveform interacts with the screen’s physical characteristics in ways the reader can measure but not fully explain.
Get the Notebook.
The day's best stories and every fresh verdict, in plain English, in your inbox by seven. One email a day, no more.

