Evan Hahn (dot com)
https://evanhahn.com/blog/
My blog, mostly about programming.
フィード

Notes from July 2026
Evan Hahn (dot com)
July! What a month!Things I did this JulyGave a talk, for ClimateAction.tech’s “Responsible AI Series”, “What I know about local language models”. “Responsible AI” can feel like a bit of an oxymoron at times, but I hope I shared something useful.Participated in the Zelda Dungeon Marathon. My first time playing a video game (The Legend of Zelda: Oracle of Seasons) on stream!Released a new version of Helmet, my Node security headers package. Most notably, it sped up the Content-Security-Policy code by about 7% for common cases.Promoted an underrated SQLite feature: strict tables.Wrote a data-driven piece about the upcoming Legend of Zelda: Ocarina of Time remake. Can the wisdom of 32 Zelda experts make accurate predictions about the new game? We’ll see.Finished moving most of my repositories from GitHub to Codeberg. A few stragglers—and some mirrors—remain, but they’re my bigger projects that require more coordination.Links I foundMy favorite read this month: a detailed history of Arabic
13日前

Prefer STRICT tables in SQLite
Evan Hahn (dot com)
In short: I prefer strict tables in SQLite because they avoid some datatype problems, such as putting text in number columns.SQLite has a feature that I think is underrated: strict tables. Strict tables help enforce rigid typing, preventing mistakes like putting text into integer columns. I like them, and wrote this post to promote their use!To make a strict table, add STRICT to the end of its definition. Like this:-CREATE TABLE people (name TEXT);+CREATE TABLE people (name TEXT) STRICT;That’s it! But what does it do?Advantages of strict tablesBroadly, strict tables help enforce rigid types, like other SQL engines do.Prevents type mismatches on insert/updateMost significantly, strict tables keep you from inserting the wrong type into a column. For example, SQLite normally lets you put text into an INTEGER column, but not with strict tables.-- Non-strict tables let you put anything anywhere.CREATE TABLE people_nonstrict (age INTEGER);INSERT INTO people_nonstrict (age) VALUES ('garbage')
1ヶ月前

Notes from June 2026
Evan Hahn (dot com)
Chicago’s weather is pretty lousy most of the year, but when it’s nice, it’s very nice. June blessed the city with dozens of idyllic days. But don’t worry—I still spent most of the time inside on the computer.Things I didI launched my first big project at Ghost: automations! It’s still in beta, but it’s one of the biggest projects I’ve led. If you happen to be a Ghost publisher, please try it out and let me know what you think!For the sixteenth issue of the Taper online magazine, I visualized time by breaking each unit into sixteenths. For example, as I write this, I’m about 6 sixteenths through the hour. Like every Taper submission, my work had to be under 2048 bytes.Links about AI ethicsGenerative AI continues to, mostly, be a force for bad in this world:“If AI is going to 10x our productivity across the board, that means that I should be able to produce the same amount of output by midday on Monday that, in the before times, would have taken all week. So can I just take Friday off?”
1ヶ月前

"Sixteenth of a year", a 1.8 KiB art piece
Evan Hahn (dot com)
As I write this, we’re about 7 sixteenths through 2026, and it’s about 14 sixteenths through the day.For the sixteenth issue of the Taper online magazine, I split time into sixteenths to think about its passage in a different way.The code, which had to be under 2048 bytes, isn’t terribly complex. It does some date math and uses a Go server for minification. If you want, here’s the unminified source code.Go check out all the other entries from this issue! My favorites include "[SIC]", “Desperate Measures from a Dying Regime”, and "(un)done".See also: my previous Taper entry.
2ヶ月前

Notes from May 2026
Evan Hahn (dot com)
My blog turned 16 this month! I did nothing to celebrate, but made some little tools and clicked some links about tech ethics.Things from me this monthI published four little tools this month:ZIP Shrinker, a web app that shrinks ZIP files with higher compression ratiosA command line tool to do (completely offline) translationOpen Link in Unloaded Tab, a Firefox extension to open links without loading thempng-cmp, a command line tool to compare PNG pixel dataI also did some work on Helmet, my open source project:After over a year of quiet maintenance, I released version 8.2.0 with some small new features and documentation updates.In a step toward dropping GitHub, I moved the docs from a GitHub URL to helmet.js.org.And like every month, I wrote a few articles at Zelda Dungeon. I don’t feel I wrote anything special this month, but my colleagues put together a feature about Zelda and mental health which was very affecting!Links to click on“The vast majority of tech workers, at least those
2ヶ月前

Make ZIP files smaller with ZIP Shrinker
Evan Hahn (dot com)
I built ZIP Shrinker, a little browser tool to shrink ZIP files. It also works with formats that are secretly ZIPs underneath, like EPUB, JAR, and many more.Try it out!How does it work?At a high level, this tool (1) re-compresses every file in the ZIP archive with higher compression (2) removes all metadata (3) removes entries for directories.Re-compressingZIP files are typically compressed with an algorithm called Deflate.There are a few tools that can re-compress Deflate data and make it smaller, usually by spending more time on the computation. I took one of these tools, libdeflate, and applied it to each compressed entry in the ZIP. I chose libdeflate because of its performance; alternatives like Zopfli can achieve marginally smaller results but take much longer.I created libdeflate.js, a WebAssembly wrapper for libdeflate, as part of this work. (I always relish my time working with WASM!)Removing metadata and directoriesEach entry in a ZIP file can contain additional metadata like
3ヶ月前

Open Link in Unloaded Tab, a little Firefox extension
Evan Hahn (dot com)
In short: I just published Open Link in Unloaded Tab, a little Firefox extension that adds “Open Link in Unloaded Tab” to the right-click context menu.In Firefox, you can unload tabs to save system resources. But there’s no way to open a new tab in the unloaded state…until now! I built a very simple extension that adds a new option to do this. (It even has a cute icon which I paid ~$15 for.)I’ve built one-off extensions before, but this is the first one I’ve submitted to the Firefox Add-ons directory.Download the extension here or check out the source code.
3ヶ月前

png-cmp: like cmp for PNGs
Evan Hahn (dot com)
png-cmp is a program I built that checks if two PNGs are visually equivalent. It’s inspired by the cmp command. Here’s how you use it:png-cmp a.png b.pngLike cmp, it silently exits if the images are identical, and gives an error if they’re different.Unlike cmp, it checks pixel data, not binary data. PNGs can look the same but be stored differently. For example, png-cmp ignores text metadata.I was recently doing an experiment where I wanted to check if two PNGs were visually identical, so I built a tool for it!Grab the source code here.
3ヶ月前

Offline command line translation with TranslateGemma + Ollama
Evan Hahn (dot com)
I wrote a simple script that translates text at the command line, completely offline. Here’s an example of how it works on my computer:echo '¿Cómo estás?' | translate# => How are you?It combines a few tools:TranslateGemma, a special-purpose language model for translationOllama, a tool for running language models locallyEfficient Language Detector, a library that detects the language for a piece of textHere’s the pseudocode of how it works:source = read_stdin()# Uses Efficient Language Detectorsource_language = detect_language(source)# Uses JavaScript's `navigator.language`target_language = get_system_language()# Uses Ollama + TranslateGemmareturn translate(source, source_language, target_language)I built this because I couldn’t find anyone else who had done it. It’s written in Deno for my specific needs—for example, it only translates text into your system’s language—but could easily be adapted if you need something else.I like that I can do offline, private, automatic translation. It’
3ヶ月前

Notes from April 2026
Evan Hahn (dot com)
After a busy March, April was a little quieter. But don’t worry, I still have a bunch of little links for you to click on.Things I publishedGitHub’s uptime hasn’t been great recently. Even though I dislike the Microsoft subsidiary, I wrote “In defense of GitHub’s poor uptime”, which argues that it’s not as bad as folks seems to be saying. See this Lobsters thread for some discussion.Published version 0.2.0 of setbigtimeout, my JavaScript library for waiting a very long time.Like every month, I published a few articles over at Zelda Dungeon. We had a slew of shitposts for April Fool’s this year. I think my favorite (not written by me) was “Daily Debate: Do You Think Old Man Was Once Young Man?”.Links I clickedGhost, my employer, was recognized as a digital public good.“You can’t advertise people out of reacting to their own experiences. This is a fundamental disconnect between how tech people with software brains see the world and how regular people are living their lives.” From “The pe
3ヶ月前