A fast, readable Hacker News client. Articles and comments side by side on a desktop, a native-feeling stacked app on a phone. Installable as a PWA.
Live: hn.4mn.org · static fallback at ben4mn.github.io/HN
- Feeds — Top, New, Best, Ask, Show, Jobs, plus Saved and full-text search (Algolia).
- Recently viewed — a running history of every story you open (last 2,000, this device only), grouped by day with the time of each view, and its own search over title, site, and author. Stories read before the history existed are recovered from the read ids the app already kept. It takes the fifth slot in the mobile tab bar.
- Settings — theme (auto, light, dark), story blurbs, the running version with Check for updates and Update now for installed copies, and a change log of short release notes.
- Reader — server-side Readability extraction with a Jina fallback, TL;DR (client-side TextRank), reading time, reading progress, adjustable type size.
- Comments — whole tree in one request, tap-to-collapse with counts, OP badges, collapse/expand all, "next top-level comment" jump on mobile, collapse state remembered per story.
- Layouts — three panes (feed | article | comments) above 1180px, two panes above 768px, single stack with a bottom tab bar below that.
- PWA — versioned shell precache, offline reading of anything already fetched, update toast, edge-swipe back, pull to refresh, safe-area aware, branded maskable icons.
- Desktop columns — drag the dividers to resize (double-click resets), swap article and comments with the ⇄ button or
x. - Keyboard —
j/kmove,↵open,ccomments,ooriginal,ssave,/search,rrefresh,atoggle pane,xswap panes,nnext root comment,1–6feeds.
index.html + static/ vanilla JS, no build step, self-hosted Figtree
server/ Node 22 + Express: feeds, comment trees, Readability, page metadata
Dockerfile / docker-compose.yml container on the Debian box, host port 3026
The client prefers the bundled backend (/api/*). When it is hosted as plain static files (GitHub Pages), it detects the missing API and talks to Firebase, Algolia, and Jina directly, with thumbnails and blurbs disabled.
cd server && npm install && cd ..
PORT=3099 node server/index.js # http://localhost:3099The service worker is skipped on localhost so edits show up on reload (?sw=1 opts back in).
ssh debian
cd ~/HN && git pull
APP_VERSION=$(git rev-parse --short HEAD) docker compose up -d --buildAPP_VERSION is stamped into sw.js at build time so every deploy invalidates the cached shell on clients.