Skip to content

About

Every NRK bulletin about Nord Stream since 2016, on one page with a timeline

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Nord Stream, in one place

Live: nordstream.rix1.dev

Every bulletin NRK has published in its Gassrørledningen Nord Stream feed — 263 of them, from August 2016 to today — on one scrollable page, with a timeline in the margin that shows the shape of the story.

Why

Hybrid warfare is designed to be hard to follow. A pipeline is finished, then halted; gas is cut off; something explodes on the seabed; leaks reach the press; suspects are named, then contradicted. Each of these arrives as a small news item, weeks or years apart, and the thread between them is easy to lose. That is not an accident — it is the point.

This is an attempt at the opposite: the record, in chronological order, arranged so the pattern is visible.

The bulletins are NRK's, unchanged. What's added is structure: each bulletin is sorted into a thread (construction, politics, gas supply, the sabotage, the investigation, the courts), tagged with the countries central to it, and weighted by how much it moves the story. That sorting is done by a language model (Jev 1.13 from TypeSafe), not by a person, and it can be wrong. The red markers are picked by hand.

The site is in Norwegian, like the source material. There's a "Translate to English" link that runs it through Google Translate.

What's on the page

  • Timeline rail — one tick per article, stacked in the left margin. Hover to magnify (dock-style) and read the headline; click to jump. Year labels sit where the year changes, so the density of September 2022 is visible at a glance. A minimap-style window tracks what's on screen.
  • Red markers — a handful of key moments (pipeline completed, halted, gas cut off, the explosions, the boat lead, the arrest warrant, the admission).
  • Threads and actors — every tick and every bulletin is coloured by the thread the model put it in, with chips at the top to filter by thread and by country. The filter lives in the URL hash, so a view can be shared: #t=investigation&a=germany.
  • Fjern støyen ("clear the noise") — one toggle that reduces the page to the turning points: the red markers plus the bulletins the model rates as defining moments, about 30 in all. The rail keeps every tick, dimmed, so the gaps in time stay visible.
  • About page — motivation, a time-proportional axis with every article as a tick, and a bar chart of articles per year.

How it works

deno task scrape     →  articles.json      (NRK's serum API → structured JSON)
deno task classify   →  annotations.json   (Jev, TypeSafe's System One API → typed labels)
deno task build      →  dist/              (prerendered from templates/; no network)

deno task update runs all three. There are no dependencies and no build tooling — the output is static HTML with two small ES modules for the interactive bits. The scripts are plain ESM and run under Node too (node build.mjs).

  • scrape.mjs fetches the compilation's item list from /serum/api/content/json/<id> and each bulletin as an HTML fragment from /serum/api/render/<compilation>.<article>, then extracts headline, body, timestamp and URL.
  • articles.json is committed, so git diff after an update shows exactly which articles are new.
  • classify.mjs sends each article, on its own, to Jev with a fixed set of questions from questions.js: which thread it belongs to (a choice), which countries are central (one yes/no per country), how much it moves the story (a 0–3 score), whether it repeats an earlier headline, and whether a historian would call it a defining moment. The typed, calibrated answers go to annotations.json, keyed by article id with a hash of the request, so re-running only sends new articles (or everything, if a question changed). A full run is 263 requests, about a minute, and costs about four cents.
  • annotations.json is committed like articles.json, so the build needs no key and no network, and a diff shows exactly which labels changed.
  • build.mjs applies the thresholds from questions.js to the annotations, renders the posts and stats into the templates, writes the site to dist/ (not checked in), and embeds a compact article list (id, ts, headline, event, thread, actors, weight, key) that the client scripts read — the browser never parses or fetches the full data. Without annotations.json the site still builds, with neutral ticks.
  • data.js holds the list of key events (by NRK article id) and is shared between the build and the browser; questions.js holds the taxonomy, the questions and the thresholds and is shared the same way.

To add a red marker, add an { id, label } entry to EVENTS in data.js and rebuild. To correct a label the model got wrong without re-running the API, add the article to OVERRIDES in questions.js, e.g. '1.16185000': { thread: 'legal' } or { key: false }, and rebuild. deno task candidates prints the model's top key-moment candidates that aren't markers yet, for deciding what to promote or override.

Running locally

deno task build    # → dist/
deno task dev      # serves dist/ at http://127.0.0.1:3000

Any static server works; the pages use ES modules, so they won't load over file://.

Only deno task classify needs anything more: a TypeSafe API key from console.typesafe.ai/keys, in the environment as TYPESAFE_API_KEY or in a .env file (gitignored). The task runs with network access to api.typesafe.ai only. --dry-run shows what would be sent and the estimated cost without calling the API.

Deployment

Cloudflare Pages, connected to this repo. Every push to main deploys:

  • Build command: node build.mjs
  • Output directory: dist

Scraping is deliberately not part of the build, so the live site always matches the committed articles.json. A full refresh is:

deno task update   # scrape + classify + build
git add -A && git commit -m "Update articles" && git push

Data and copyright

The articles are © NRK and are reproduced here for personal, non-commercial reference. Every bulletin links back to the original on nrk.no. Source feed: Gassrørledningen Nord Stream. For the labels, each bulletin's text is also sent, one at a time, to TypeSafe's API for classification; TypeSafe states it does not train on customer requests.

The code is MIT licensed.

About

Every NRK bulletin about Nord Stream since 2016, on one page with a timeline

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages