6 min read·

Some itches you just have to scratch

A Raspberry Pi, an e-ink display, and thirty minutes on a train turned a years-old idea into a live MLB scoreboard on my desk.

The finished e-ink scoreboard in its frame on a desk, showing live MLB scores in a grid layout

A 7.3-inch e-ink display powered by a Raspberry Pi Zero, showing live MLB scores from Saturday, August 16. The frame sits on my desk and refreshes throughout the day.

If you've ever been inside an MLB ballpark, you might have noticed that somewhere, tucked into an outfield wall or a corner of the main scoreboard, there's an out-of-town scoreboard. A board that shows the scores from every other game happening around the league while you're watching yours. At Wrigley Field and Fenway Park, they're still operated by hand. Someone sits inside the wall and slides steel number plates into slots, watching a laptop for score updates. The boards themselves haven't changed in decades, even as the information feeding them has gone fully digital. Most parks have replaced those manual boards with LED panels, though a few newer stadiums have gone retro on purpose, building digital displays designed to look like the originals. The concept has been around for over a century. It's part of the texture of being at a game, so embedded in the experience that most people stop noticing it.

I grew up a Mariners fan. Not in Seattle, but the way a lot of kids become baseball fans: I loved Ken Griffey Jr., I played Major League Baseball Featuring Ken Griffey Jr. on my N64, and I followed the team from a distance through a stretch where they were genuinely electric. Then they were terrible for a long time, the way the Mariners tend to be, and I kept following them anyway. Baseball is like that. It stays with you across long stretches where nothing much happens.

When I moved to Seattle in 2006 to attend university, the team was bad, but I loved going to games even though I had no money. I'd scalp tickets for five or six dollars and do my homework in the upper deck. The team didn't need to be good. The game itself was enough. You sit there and you're connected to something bigger than what's happening on the field in front of you. You glance up at the out-of-town scoreboard between innings and see that the Yankees are losing, or that some game on the East Coast went to extras, and you're part of this whole thing happening all at once across the country.

The hand-operated steel-plate scoreboard above Edgar's at T-Mobile Park

T-Mobile Park kept one corner manual: the steel-plate scoreboard above Edgar's, where someone behind the wall still slides number tiles in by hand.

At some point I started wanting to take a piece of that home with me. I carried the idea around for years without telling anyone. It just lived in my head alongside a dozen other half-formed ideas like it, things I assumed I'd never actually build, or might build one day far into the future.

Most people who make things have a backlog like this. Ideas they've been sitting with, sometimes for years, that never go anywhere because the gap between I wonder if I could build this and here's how I'd start is always wider than you'd expect. Not because the idea is bad, but because finding out if it's even possible is its own project.

What's changed is that the research phase has collapsed. Not the building, not the hard decisions, not the craft. Just the part that turns I wonder if into here's how.

The train ride

On the light rail home from a Mariners game last September, the idea popped into my head again, the way it had countless times before. But this time I opened Claude on my phone and started asking questions. Has someone already made this? No, nothing like it exists. How hard would it be to build myself? Not that hard, actually. What kind of hardware would I need, like a small screen and a Raspberry Pi? Yes, and here are your options. Claude pointed me to Pimoroni, a hardware startup in the UK that makes the Inky Impression, a 7.3-inch e-ink display designed to connect to a Pi. Is the score data I'd need available? Yes, MLB has a public stats API. Can you mock up what this might look like? And right there on my phone, Claude built an artifact that pulled live scores and rendered them in a grid.

Each answer made the next question obvious, and each question made the idea feel more real. By the time I stepped off the train, I'd already placed orders for the hardware I'd need. A thing I'd been vaguely turning over in my head for years had a parts list, a data source, and a working prototype on my phone. Thirty minutes on the light rail.

Constraints

The Raspberry Pi Zero 2 W costs $14. It has a quad-core ARM processor, 512MB of RAM, and no fan. It's roughly the size of a stick of gum.

The Inky Impression can display exactly six colors: black, white, red, green, blue, and yellow. That's the hardware. Everything that mattered about this project came from working within those limits.

The system works like this: a Flask web server running locally on the Pi pulls live scores from the MLB Stats API and renders them as a web page. Playwright launches a headless Chromium browser to screenshot that page. Pillow processes the screenshot and dithers it down to the display's six-color palette. Then the Inky library pushes the final image to the e-ink panel. The whole pipeline runs on the Pi, including the API server. There is no cloud, no external service. Just a $14 computer doing everything locally.

That pipeline is straightforward on a normal computer. On the Pi Zero, it meant running a headless browser on a machine with maybe 120MB of free memory. Chromium alone wanted more than that. I ended up writing memory checks, hard timeouts, and a process tree killer to keep the browser from taking the whole system down. It was a different kind of programming than I was used to.

DATA SOURCE
MLB Stats API
statsapi.mlb.com
WEB SERVER
Flask
Python + Jinja
HEADLESS BROWSER
Playwright
Chromium
IMAGE PROCESSING
Pillow
hitherdither
DISPLAY DRIVER
Inky
SPI interface

The full rendering pipeline runs locally on the Pi Zero. A Flask server fetches scores, Playwright screenshots the page, Pillow dithers the image down to six colors, and Inky pushes it to the display.

Then there's color. For each game, a gradient color optimizer evaluates every combination of two teams' primary, secondary, and tertiary colors and scores them on perceptual distance, color harmony, and brightness. White, orange, and yellow are banned from gradients entirely because they wash out on the e-ink panel. The algorithm favors dark, high-contrast pairings (green+blue, blue+red, black+blue) that survive the quantization step.

Once the color optimizer picks the best team colors, the image still needs to be mapped down to what the display can physically render. The display uses hitherdither with Bayer dithering at order 8 to approximate colors the panel can't produce. It's the same technique old video games used to fake color depth on limited hardware.

Six RGB values. That's it. The team logos and gradient backgrounds all get reduced to some combination of those six tuples.

# The Inky Impression's entire color vocabulary
inky_palette = hitherdither.palette.Palette([
    (0, 0, 0),        # Black
    (255, 255, 255),  # White
    (255, 0, 0),      # Red
    (0, 255, 0),      # Green
    (0, 0, 255),      # Blue
    (255, 255, 0),    # Yellow
])
 
# Bayer dithering to approximate full-color gradients
# using only the six colors above
dithered = hitherdither.ordered.bayer.bayer_dithering(
    img, inky_palette, thresholds=[64, 64, 64], order=8
)
The Inky Impression's six-color palette and the Bayer dithering call that maps full-color gradients down to it.

Bringing it home

Because the display renders a web page, I could build and test the entire interface in a browser without needing the physical hardware. I built a dev server that could load different game states, toggle display sizes, and pull live data from the MLB API, which meant I could iterate on the layout and the color algorithm on my laptop and only push to the actual display when I wanted to see the real thing.

The pipeline is deliberately indirect: web page → Playwright screenshot → Pillow processing → e-ink display. But each step gives me a place to intervene. I can test the web rendering in a browser, test the screenshot in a PNG viewer, test the dithered output without the hardware. Each layer of indirection is also a place I can debug.

I shipped the project with several configurable themes, one of which was modeled directly after the out-of-town scoreboard at T-Mobile Park. I took a photo of the actual board during a game and used it as a reference. It strips out the team logos and gradient backgrounds in favor of a minimal, text-heavy layout with diamond indicators showing base runners and outs. Building it felt like closing a loop.

The e-ink display in screensaver mode, showing a Mariners news article from the Seattle Times

When the last game ends, the display switches to screensaver mode. It pulls the latest Mariners coverage from the Seattle Times and cycles between articles and photos throughout the day.

The whole thing went from idea to working prototype in less than a day. I spent the next few weeks refining it. It sits on my desk now. When games are on, it refreshes with live scores. When the last game ends, or on off days, it switches to a screensaver that cycles between Mariners news from the Seattle Times and photography from the most recent game off the AP wire, mostly Lindsey Wasson's work. The images run through the same dithering pipeline as everything else, reduced to six colors. There's something about a wire photo of a play at the plate rendered like an old newspaper print. The display is always showing something. I open-sourced it from the start.

Most of the things I've wanted to build never made it past the thinking-about-it phase. This one did because thirty minutes on a train was enough to close the gap between the idea and the first step. The e-ink board sits on my desk as I write this, showing the same out-of-town board I still look up to find above Edgar's whenever I'm at T-Mobile.

Audio paused
Some itches you just have to scratch
0:00
7:53

About the author

Pat Dugan is a designer and engineer who has spent the last decade and a half shipping consumer products, building design systems, and growing teams at Google, Meta, Quora, Nextdoor, and the Chan Zuckerberg Initiative. These days he’s mostly thinking about how AI changes the way we make things.