A clean, readable, cross-browser UI for Hacker News.
Open news.ycombinator.com and Easy for Hacker News takes over the page in place with a
themeable, distraction-free interface — no separate app, no accounts, no pro tier.
- Redesigned story lists — Top / New / Best / Ask / Show / Jobs, with domains, score, author, age and comment counts.
- Readable comment threads with one-click collapse/expand.
- New since your last visit — comments added since you last opened a thread are dotted in the margin, with a "N new" button that steps through them.
- Session — sign in / out with your Hacker News credentials; once signed in, upvote and reply (inline composer) straight through HN using your existing session.
- Profiles — a tabbed profile (About, Stories, Comments, Favorites, plus Upvoted / Hidden on your own Profile) rendered in place.
- Customization — theme (Light / Dark / Auto), font (sans / serif), font size and density. Applied live to every open tab.
- Keyboard navigation —
j/kto move,o/ Enter to open,cfor comments.
It works by parsing HN's own server-rendered HTML (not the JSON API), so the auth tokens HN needs for voting and replying stay intact and nothing leaves your browser.
Install from the Chrome Web Store.
Not on Firefox Add-ons yet. To run it there — or to try an unreleased build on Chrome — load it by hand from the Releases page:
- Chrome: download
easyhn-<version>-chrome.zip, unzip it, then openchrome://extensions, enable Developer mode, click Load unpacked, and select the unzipped folder. - Firefox: download
easyhn-<version>-firefox.zip, openabout:debugging#/runtime/this-firefox, click Load Temporary Add-on, and select the zip (Firefox drops temporary add-ons when it restarts).
Then open news.ycombinator.com. Prefer to build it yourself? See Development.
Just open news.ycombinator.com — Easy replaces the page automatically. Pages it doesn't redesign are left untouched, so the rest of HN still works as usual.
- Browse — use the top nav (Top / New / Best / Ask / Show / Jobs), or the
keyboard:
j/kto move the selection,oor Enter to open a story,cto jump to its comments. - Read threads — click any comment's chevron to collapse or expand it. Come back later and anything posted since your last visit carries an orange dot; the "N new" button next to the comment count jumps between them. Turn it off in Settings and it forgets which threads you've opened.
- Vote & reply — log in from the header. Once logged in, the upvote arrows and an inline reply box become active on stories and comments.
- Settings — click the gear in the header (or open the extension's options page) to change theme, font, font size and density. Changes apply instantly to every open tab.
- Toolbar icon — opens a small card with quick links (the HN front page and the author's profile).
Built with WXT + React + TypeScript. One codebase targets Chrome (MV3) and Firefox (MV2).
entrypoints/hn.content in-place takeover content script (parse → mount React)
entrypoints/popup toolbar about / links card
entrypoints/options full settings page
src/parse HN DOM → typed model (the core; covered by tests)
src/actions vote / reply write-backs
src/ui React views & components
src/settings schema, storage.sync store, theming
pnpm install
pnpm dev # launch Chrome with the extension + HMR
pnpm dev:firefox # launch FirefoxFor a persistent local install (rather than the pnpm dev HMR browser), run
pnpm install-local. It builds and copies the extension to ./unpacked, a stable
folder you can point Chrome's Load unpacked at. After a rebuild, click the
reload icon on the Easy card.
pnpm build # .output/chrome-mv3
pnpm build:firefox # .output/firefox-mv2
pnpm zip # store-ready chrome zip
pnpm zip:firefox # store-ready firefox zip + sources zipCut a release with a version script. Each one bumps the version in package.json,
commits and tags it, and pushes, which triggers
.github/workflows/release.yml to build both zips
and publish them to GitHub Releases:
pnpm release-patch # 0.1.0 -> 0.1.1
pnpm release-minor # 0.1.0 -> 0.2.0
pnpm release-major # 0.1.0 -> 1.0.0The DOM parsers are the fragile part (HN markup can change), so they're covered by tests that run against captured real HN HTML:
pnpm test # run parser tests against tests/fixtures
pnpm test:fixtures # re-capture fixtures from live HN