The Curious Engineer

All blogs / Software / engineering practice

Evan Hahn (dot com)

evanhahn.com/blog

I'm Evan Hahn, a programmer.

Software / engineering practiceDev tools / editors / IDEsAI / MLDatabasesEngineering blogs

Posts
310 from 8 May 2010 to 24 Oct 2026
Posting
weekly (44 in the last year)
Kind
personal blog
Feed
https://evanhahn.com/blog/index.xml

2026 31

  1. List of Vim forks
  2. Notes from September 2026
  3. Anecdotally, programmers dislike "reduce"
  4. Notes from August 2026
  5. Vim's UserGettingBored autocmd
  6. Notes from July 2026
  7. Prefer STRICT tables in SQLite
  8. Notes from June 2026
  9. "Sixteenth of a year", a 1.8 KiB art piece
  10. Notes from May 2026
  11. Make ZIP files smaller with ZIP Shrinker
  12. Open Link in Unloaded Tab, a little Firefox extension
  13. png-cmp: like cmp for PNGs
  14. Offline command line translation with TranslateGemma + Ollama
  15. Notes from April 2026
  16. In defense of GitHub's poor uptime
  17. Notes from March 2026
  18. Little web app to pick a random programming language
  19. All tests pass: a short story
  20. human.json
  21. How I use generative AI on this blog
  22. Introducing llm-eliza
  23. The two kinds of error
  24. Notes from February 2026
  25. Read gzip metadata with gzpeek
  26. Track Zelda release anniversaries in your calendar
  27. Notes from January 2026
  28. An LLM that's 7500× stupider
  29. A mental math heuristic to convert between Fahrenheit and Celsius
  30. “I set all 376 Vim options and I’m still a fool”
  31. Notes from "On Writing Well"

2025 55

  1. Notes from December 2025
  2. Prediction: Mastodon will outlive Bluesky
  3. Notes from "Bad Company: Private Equity and the Death of the American Dream"
  4. How I implemented relative imports with Pyodide
  5. I made a little audio speed calculator
  6. Notes from November 2025
  7. Draft: Stopping bad guys from using my open source project (feedback wanted)
  8. Notes from "The Story of the Typewriter"
  9. Experiment: making TypeScript immutable-by-default
  10. Fizz Buzz without conditionals or booleans
  11. Kirby Air Riders demo impressions (from a big fan of the original)
  12. "Understanding Unicode": my October 2025 talk at Longhorn PHP
  13. Notes from "Tor: From the Dark Web to the Future of Privacy"
  14. Notes from October 2025
  15. Scripts I wrote that I use all the time
  16. Notes from September 2025
  17. People read your blog in many different ways
  18. @ts-ignore is almost always the worst option
  19. JS fetch converts string request bodies to UTF-8
  20. Notes from August 2025
  21. Notes from July 2025
  22. Notes from "The Weather Machine: A Journey Inside the Forecast"
  23. Notes from "Where Wizards Stay Up Late: The Origins of the Internet"
  24. Local LLMs versus offline Wikipedia
  25. Simple macOS script to extract text from images (OCR)
  26. “How I build software quickly”
  27. Notes from June 2025
  28. Notes from "Empire of AI: Dreams and Nightmares in Sam Altman's OpenAI"
  29. An unfinished post: "Compressing short Unicode strings with BOCU-1"
  30. Getting over my grudge against the periodic table
  31. Rainbow "code doodle"
  32. When Array uses less memory than Uint8Array (in V8)
  33. Simple script to sort Markdown lists
  34. Notes from May 2025
  35. List of "tech for good" job boards
  36. Things I wish I knew about Ring Fit Adventure
  37. Notes from April 2025
  38. UI tip: maybe don't round percentages to 0% or 100%
  39. Takeaways from The Economist's style guide book
  40. Notes from "Life in Code: A Personal History of Technology"
  41. Notes from March 2025
  42. Cheatsheet for Rink, the unit-aware calculator
  43. Everything we know about the next Zelda game, as of March 2025
  44. Filling in the gaps of the internet
  45. Notes from "Beyond Measure: The Hidden History of Measurement"
  46. Why "alias" is my last resort for aliases
  47. An ode to my favorite mobile game
  48. Notes from February 2025
  49. How to play a file in reverse with mpv
  50. LLMs: harmful to technical innovation?
  51. Notes from January 2025
  52. Whisper transcription vs. iPhone 11 Pro and iPhone 16 Plus: an informal test
  53. My experience upgrading from iPhone 11 Pro to iPhone 16 Plus
  54. My failed attempt to shrink all npm packages by 5%
  55. string-timing-safe-equal, a new Node package

2024 29

  1. A black cat in 2032 bytes
  2. Makeshift hot reload: my submission to HTMHell 2024
  3. 95% is very different from 99%
  4. A little trick to reduce Zoom bandwidth
  5. How does SQLite's "changes" API handle no-op UPDATEs?
  6. MIME types and atom bombs
  7. My notes from the Lua 5.4 reference manual
  8. How to download every game from js13kgames
  9. setBigTimeout
  10. Mapping Mario Kart 8's real-life courses
  11. Remember The Milk script to get task permalink
  12. Announcing Helmet v8
  13. Python: how to change the extension of a pathlib.Path
  14. Using ESLint to (help) avoid non-deterministic randomness
  15. How I played Halo: Master Chief Collection in chronological order
  16. My programming beliefs as of July 2024
  17. How to set a Zsh option only if supported
  18. Progressive enhancement for content
  19. "Understanding Iterables": my April 2024 talk at ChicagoJS
  20. Five apps in two kilobytes
  21. Clojure: distinct versus dedupe
  22. Remember The Milk script to estimate selected tasks
  23. How to use crypto.timingSafeEqual with strings
  24. What's the best way to concatenate Uint8Arrays?
  25. systemd-inhibit: a built-in Linux alternative to macOS's "caffeinate" command
  26. import myModule from "./my-module.torrent": requiring Node modules from BitTorrent
  27. Remember The Milk CSV export script
  28. “The world’s smallest PNG”
  29. Torrent snapshot of my open source projects, as of 2024

2023 39

  1. When static types make your code shorter
  2. Introducing Sqids Crystal
  3. How to do integer division in Crystal
  4. How sleep mode works on the Anbernic RG35XX (with GarlicOS)
  5. Introducing NONOGRAM NIGHTS
  6. How to use the JavaScript Compression Streams API to (de)compress strings
  7. Conditional Express middleware
  8. Track flights on iOS without installing anything
  9. How big is a kilobyte?
  10. How does Swift decode "weird" JSON numbers?
  11. Short C program that repeats a string forever
  12. "JavaScript and the farmer emoji": my talk at the Chicago JavaScript Meetup
  13. My mnemonic to remember tar commands on Linux
  14. How to set the (deprecated) valign attribute with JavaScript
  15. Subscribe with email if you want
  16. Play a jingle on Git commits
  17. Which Zelda dungeons are actually called "dungeons"?
  18. Proof of concept: drop-in JSON replacement that produces smaller payloads
  19. A picross game in 1024 bytes
  20. What's the largest possible PNG?
  21. You might not need Helmet.js
  22. Python's nonstandard JSON encoding
  23. Crystal: how to compute a CRC32 checksum
  24. Working with the UTF-8 bytes of JavaScript strings
  25. Getting the UTF-32 bytes of JavaScript strings
  26. Getting the UTF-16 bytes of JavaScript strings
  27. Utf 21
  28. My favorite little Markdown feature: reordering ordered lists
  29. How to compute the distance between two Cartesian points in JavaScript
  30. “Why does ‘👩🏾‍🌾’ have a length of 7 in JavaScript?”
  31. Converting UIColors to CSS colors
  32. Everything we know about The Legend of Zelda: Tears of the Kingdom, as of April 2023
  33. Nested array permutations in JavaScript
  34. “The lone developer problem”
  35. Everything we know about The Legend of Zelda: Tears of the Kingdom, as of February 2023
  36. How to format SQLite BLOB columns as hex
  37. 9 years maintaining a sorta-popular open source package: lessons learned
  38. How I fixed broken Wi-Fi on my 2012 Mac Mini running Zorin OS
  39. Everything we know about The Legend of Zelda: Tears of the Kingdom, as of January 2023

2022 14

  1. Everything we know about The Legend of Zelda: Tears of the Kingdom, as of December 2022
  2. Ruby: how to get the MD5 hash of a file
  3. Everything we know about The Legend of Zelda: Tears of the Kingdom, as of November 2022
  4. Everything we know about The Legend of Zelda: Tears of the Kingdom, as of September 2022
  5. Re-implementing JavaScript's == in JavaScript
  6. Consider Node's built-in test runner
  7. Everything we know about The Legend of Zelda: Tears of the Kingdom, as of August 2022
  8. The difference between "=" and "IS" in SQLite
  9. maintained for ~15 years
  10. Disable SwiftLint for a file
  11. Everything we know about The Legend of Zelda: Tears of the Kingdom, as of May 2022
  12. How to read tab-separated values (TSV) files in Python
  13. Remember The Milk script to find tasks with invalid start times
  14. Everything we know about The Legend of Zelda: Tears of the Kingdom, as of April 2022

2021 2

  1. When stringify doesn't return a string
  2. How to block Google's FLoC tracking with Express

2020 2

  1. Should you use semicolons in JavaScript?
  2. How to reverse an array in JavaScript

2019 3

  1. Profit, not welfare
  2. The hype train
  3. Gotchas with Express query parsing (and how to avoid them)

2018 5

  1. An interview with me on JavaScript Jabber
  2. "Fancy code is exclusionary"
  3. My entry to JS1k 2018: "Zap"
  4. Show only production dependencies with npm
  5. On modern censorship

2017 12

  1. Import Pinboard bookmarks into Standard Notes
  2. On multi-paradigm languages
  3. "Facebook Wins, Democracy Loses"
  4. Clojure's "zero?" has some quirks
  5. Petition to open source Flash
  6. Lessons learned from last week's cyberattack
  7. Think of the journalists
  8. Ball lightning
  9. On becoming comfortable with privacy violations
  10. "Six other times the US has banned immigrants"
  11. Z-index seems so simple...
  12. Prevent Homebrew from gathering analytics

2016 6

  1. Automatically ls when changing directories in zsh
  2. "If my code helped one developer at least once"
  3. "X marks gender-neutral"
  4. "The last thing we all need is for the 'data' economy to destroy another medium"
  5. Detect global JavaScript variables with iframes
  6. Parse URLs with <a> tags in JavaScript

2015 14

  1. How to transfer Android Neko Atsume saves using adb
  2. Disable ESLint for a file
  3. The CSP module is the largest part of Helmet
  4. Vim's :x command: like :wq but better
  5. Only customize where you are unusual
  6. Programming languages and their ecosystems
  7. How to clear all inline styles from an HTML element
  8. Overwriting document.head in strict mode on Safari
  9. Pietime, my entry to JS1k 2015
  10. "This Incredible Hospital Robot Is Saving Lives. Also, I Hate It"
  11. Scrape Delicious bookmarks with 3 command-line tools
  12. Skip the header of a file with Python's CSV reader
  13. "Raising the wall" for open source
  14. Install a list of Atom packages from a file

2014 18

  1. Thoughts on CoffeeScript after ECMAScript 6
  2. Disable the beer emoji in Homebrew
  3. The Internet no longer a wild west
  4. A deep dive into Express's static middleware
  5. Mostly on screens, at scales unimaginable
  6. A quick romp through default values in CoffeeScript
  7. Install Node Version Manager without the source line
  8. "About Feminism"
  9. "Writing the code was typically less than half the problem"
  10. The Internet as public infrastructure
  11. "We Are All Intelligence Officers Now"
  12. Strangecoin
  13. Dealing with the User-Agent of Python's Requests library
  14. "Is jQuery too big for mobile?"
  15. How to publish a simple package to npm
  16. Understanding Express.js
  17. Disable JSHint for a file
  18. Introducing cyborg.txt: robots.txt utilities for Node

2013 22

  1. Proteus
  2. The Underhanded C Contest
  3. Two-factor authentication list
  4. An experiment: syntax highlighting for the English language
  5. Origin: my entry to js13kgames 2013
  6. Visualizing cracking AES-256
  7. Gribbagrab your resources
  8. Four CSS tips that have changed me
  9. Vim's dw_red for terminal Vim
  10. "JavaScript folks are really nuts"
  11. Understanding Express.js version 3
  12. Concept: making asynchronous loading look synchronous
  13. Resources from my 6th semester at the University of Michigan
  14. The intended purposes of JavaScript and the Internet
  15. "All magic comes with a price"
  16. Vim's killer feature
  17. Backbone.js is larger than you think
  18. University of Michigan students can use Virtual Sites to do cross-browser testing
  19. "Using the web in 2013 means using JavaScript"
  20. HTML and the "living standard"
  21. Circles 1K
  22. Why should AI be humanlike?

2012 44

  1. Are we shook up?
  2. Resources from my 5th semester at the University of Michigan
  3. Why GNU grep is fast
  4. Smoothing out setTimeout in CoffeeScript
  5. "Ramadan code"
  6. Detect the Vimium Chrome extension
  7. Under 1% of English words are alphabetical
  8. "Technology itself does not transform anything"
  9. "10 Timeframes"
  10. Private members in CoffeeScript
  11. First impressions of Rails
  12. JavaScript/CoffeeScript sleepsort
  13. On my internship at UniversityNow
  14. Nicer committing with Vim
  15. Meeting the computer halfway
  16. Start Vim and temporarily ignore your .vimrc
  17. Timeline of sexist incidents in geek communities
  18. Hardware Vim petal
  19. CoffeeScript's existential operator
  20. Airplane mode
  21. Cancel a git-flow branch
  22. Make console methods work in Internet Explorer
  23. Apple and the majority
  24. Is it worth cheating Caltrain?
  25. Week three of Vim
  26. Maurice Sendak
  27. The most important decisions are non-technical
  28. LinkedIn's app is HTML5
  29. Caesar shift in JavaScript and CoffeeScript
  30. What the Google-Oracle trials mean for coders
  31. Douglas Crockford on making JSON a standard
  32. Doing without jQuery
  33. Resources from my 4th semester at the University of Michigan
  34. Quietly awesome
  35. Papyrus Watch
  36. The Midwest Mentality
  37. "Inventing on principle"
  38. Evil sum and average of a JavaScript array
  39. "We actually think people have to pay for content."
  40. Nintendo's changing logo
  41. Post-active state for links
  42. I love CoffeeScript
  43. Remove one element by index from JavaScript array
  44. Resources from my 3rd semester at the University of Michigan

2011 10

  1. "Traditional" for loops in CoffeeScript
  2. The comprehensive guide to disabling selection on the web
  3. Newline necessary at the end of JavaScript files?
  4. Detect the RockMelt browser from JavaScript
  5. Randomly generate either -1 or 1 in JavaScript
  6. How do I Jasmine: a tutorial
  7. Old Notational Velocity icon
  8. Use text-to-speech if you can't proofread aloud
  9. Only organize when you cannot search
  10. Euler method calculator in C++

2010 3

  1. A mindless to-do list
  2. How to: play custom Portal maps on macOS
  3. And the blog begins

Undated 1

  1. several other places