New species. Balance changes. Unresolved bugs.
A few good things on Earth, one patch at a time.
What if the news read like a game's patch notes?
+ New cat spawned
* Elder chimp vision patched
~ Airport map rework underwaychangelog.earth collects recent reporting and turns selected headlines into short planetary updates. Open a story's info button for the original headline, publisher summary and source link. The examples above illustrate the editorial style; the feed changes as new stories arrive.
- Daily editions. Aim for 3–6 worthwhile stories per publication day, prioritising discoveries, conservation wins and useful progress. Quiet days can have fewer.
- Reporting you can trace. Original links, publishers and dates stay attached to every update.
- Follow via RSS. Subscribe at
/feed.xmlfor the latest 100 published patch notes, with source links and stable IDs. The feed refreshes on the same 15-minute schedule as the homepage and never generates AI drafts. - A living terminal. A rotating ASCII Earth, dated panels and compact source stacks.
- Loading feedback. A mint Orbit indicator from loading.dev appears while a page is loading, respects reduced motion, and never delays the cached content.
- Saved editions during outages. Groq selects stories and writes patch titles. Failed requests leave the saved archive intact; raw headlines never fill the gap.
Requires Node.js 22.13 or newer and npm. Windows, macOS and Linux are supported.
git clone https://github.com/byalex33/changelog.earth.git
cd changelog.earth
npm ciCopy .env.example to .env.local, then add your Groq API key:
GROQ_API_KEY=your_key_here
GROQ_MODEL=openai/gpt-oss-120bnpm run devOpen http://localhost:5173. Without a Groq key, the app serves the saved archive but cannot select new stories. Restart the server after changing environment variables. Keep the key server-side. Configure the same variables in Vercel for production.
Collection also requires ARCHIVE_SECRET. Generate a random token with node -e "console.log(require('node:crypto').randomBytes(32).toString('hex'))" and set the same value in the hosting environment and the repository's GitHub Actions secret named ARCHIVE_SECRET. For local collection, add it to .env.local. Never use a NEXT_PUBLIC_ variable for this token. Missing or incorrect bearer tokens receive HTTP 401 before any feed or AI calls; public saved editions remain accessible.
flowchart LR
A[Twice-daily archive job] --> B[RSS, GDELT and Spaceflight News]
B --> C[Validate and deduplicate]
C --> D[Groq selects stories and writes titles]
D --> F[Commit saved editions]
F --> G[Homepage, API and RSS]
The Archive daily editions GitHub Actions workflow collects stories at 00:23 and 12:23 UTC. It requests drafts from /api/news?archive, then commits them to data/editions.json. Normal homepage, API and RSS requests read saved editions without calling feeds or AI. Failed collection leaves published stories intact.
Groq assesses headlines for worldwide relevance and writes game-style patch titles. Original source links, dates and publisher summaries remain attached. Generated labels can be wrong, so the linked reporting remains the reference. GDELT dates indicate indexing time rather than publication time.
On Vercel, Next.js serves the homepage as cached HTML and regenerates it on visits after 15 minutes. Failed or empty regeneration keeps the previous page; an initial build without a valid edition fails. Local development renders on demand, so use a production build to measure caching.
See collection, archive and caching details for the editorial rules, outage behaviour and provider limits.
| Change | File |
|---|---|
| Add or adjust an RSS feed | lib/rss-feeds.mjs |
| Tune story selection and patch-note wording | lib/changelog.mjs |
| Adjust freshness, filtering and source caching | lib/news.mjs |
| Change the ASCII globe | components/ascii-earth.tsx and lib/ascii-earth.mjs |
| Edit the page and theme | app/page.tsx and app/globals.css |
| Change story popouts and the source directory | components/news-details.tsx |
Built with React 19, TypeScript, Tailwind CSS 4 and Vinext, with a Cloudflare Workers development runtime and a Next.js build for Vercel. Groq uses the REST API directly. The interface uses shadcn/ui, Radix, Motion and Hugeicons.
Run npm run lint for ESLint. The contribution guide lists the focused checks for parsing, editorial rules, publication, caching, RSS and globe geometry. They use Node's built-in assertions and mocked provider requests.
Import this GitHub repository in Vercel. The included vercel.json selects Next.js, installs with npm ci, and builds with next build --webpack. Add GROQ_API_KEY as a server-side environment variable, optionally set GROQ_MODEL, then deploy. The news function allows up to 180 seconds for upstream fetches and generation.
For analytics, create a website in Tracwell, use its private collection mode, and add the production domain to its allowed domains. Set NEXT_PUBLIC_TRACWELL_PROJECT_KEY to the public browser project key before building. No analytics script is loaded when this value is absent. Never use a Tracwell server key in this variable.
Add your custom domain in the Vercel project settings and apply the DNS records Vercel provides at your DNS host.
npm run build
npm startThe build produces a Cloudflare Worker under dist/server; npm start previews it locally through Wrangler. To host it on your own Cloudflare account, configure your Worker and secrets, then deploy the generated Worker configuration. The default news feed does not require D1 or R2.
Set GROQ_API_KEY as a production secret and optionally set GROQ_MODEL. Do not commit credentials. Local hosting metadata is optional and is excluded from the public repository.
Read the contribution guide for setup, checks and pull request expectations. Everyone taking part should follow the code of conduct.
Project code is available under the MIT license. Third-party components retain their own notices:
- BeUI motion components
- shadcn styles
- Sites Vite plugin
- JetBrains Mono and Plus Jakarta Sans, under the SIL Open Font License
News articles, publisher summaries, names and logos belong to their respective owners. The software license does not relicense that content. This project is not affiliated with the publishers it links to.
