Skip to content

nordstjernen-web/nordstjernen

Repository files navigation

Nordstjernen web browser

Nordstjernen is a web browser, written from scratch in C. Focused on supporting the HTML and CSS standards.
Nordstjernen is built in Norway.

Runs on the platforms Windows , Mac and Linux, Android, Java, FreeBSD and NetBSD.

HTML Standards: Behaviour is measured against the spec text, section by section, not against another browser — 136 spec rows fully implemented, 27 partial, 4 absent as of June 2026.

Security: each tab's engine runs in its own sandboxed process (seccomp + Landlock on Linux) behind an IPC + shared-memory-framebuffer boundary · no JIT.

Minimalism: The whole engine is about 123,000 lines of C (plus a thin C++ Qt shell) — small enough for one person to read and audit end-to-end.

Nordstjernen has no JIT so it is much more secure, and can still be fast enough. It ships no telemetry of any kind.

Nordstjernen start page — chatting with the local AI assistant

Nordstjernen Now!

Standards compliance

Nordstjernen is measured against the spec text, section by section, not against any other browser. The section-by-section walk-through of the in-scope WHATWG HTML standard (§1–§16) in docs/HTML-compatibility.md currently records 136 spec rows fully implemented, 27 partial, and 4 absent (June 2026), besides a handful that are non-goals by design, such as in-process media codecs. Highlights:

Spec area Status
§2 Common infrastructure — WHATWG URL, IDN, origins, encodings
§3–§4 Semantics, document structure & tabular content
§4.8 Embedded content — images, SVG, iframe, minimalist MathML presentation layout; <video> decodes and plays inline (MPEG-1); other codecs and <audio> hand off to an external player 🟡
§4.10 Forms — controls, validation, valueAs*
§4.12–§4.13 Scripting, custom elements
§6 User interaction — focus, inert, contenteditable, hidden/content-visibility, drag-and-drop incl. native file drops
§7–§8 Loading pages, web application APIs — fetch, XHR, timers, observers
§9 Communication — WebSocket, EventSource, postMessage
§10 Web workers — dedicated workers (fetch, crypto.subtle, transferable ArrayBuffers), Service Workers with FetchEvent interception, Cache API (Shared/module workers & worklets aside)
§12 Web storage — localStorage / sessionStorage
§13 HTML syntax (lexbor parser); §14 XML partial
§15 Rendering — CSS cascade, flex, grid, transforms

The full section-by-section walk-through lives in docs/HTML-compatibility.md.

Browser features

  • HTML/CSS via the lexbor parser — modern cascade, flex, grid, transforms, gradients, @keyframes.
  • JavaScript on the QuickJS interpreter — DOM, Shadow DOM, observer APIs, Canvas 2D (Path2D, ImageBitmap, DOMMatrix), WebCrypto (crypto.subtle over OpenSSL).
  • Networking over HTTP/2 with libcurl — HSTS, CSP, partitioned cookies.
  • Media — images, optional inline PDF; <video> plays inline for the built-in MPEG-1 codec (decoded in-tree by pl_mpeg, MIT-licensed), with autoplay, loop, and click-to-play/pause; other video codecs and <audio> are handed off to an external player; any script the host has fonts for.
  • MathML — a minimalist presentation-MathML renderer (src/mathml.c) covering mrow, mi/mn/mo/mtext, msup/msub/msubsup, mfrac, msqrt/mroot, munder/mover/munderover, mtable, mfenced, and mphantom, laid out over Pango/Cairo and embedded inline on the text baseline.
  • Spell checking — optional, via the Enchant library (src/spellcheck.c): misspelled words in editable text (text inputs, textarea, contenteditable) get a red wavy underline, honouring the spellcheck attribute. Dictionaries load before the renderer seals its sandbox; with Enchant absent it degrades cleanly to no checking.
  • WebGL — opt-in, per-site WebGL 1 / 2 mapped onto OpenGL ES; off by default and gated behind a trust prompt. See docs/webgl.md.
  • WebAssembly — the full JS API (compile, instantiate, Memory, Table, externref) over a vendored WAMR interpreter; runs wasm-bindgen bundles. See docs/webassembly.md.
  • Process-per-tab — each tab's engine runs in its own sandboxed nordstjernen-renderer process; the GTK and Qt apps are thin shells that blit the renderer's shared-memory framebuffer and forward input over an IPC control channel (src/rproc_http.c), so a page can't take down the UI. See docs/tab-isolation.md and docs/Rendering.md. An optional --single-process flag (GTK and Qt) runs every tab's engine inside the shell process instead — same protocol, threads instead of child processes — for low-memory machines, containers, and debugging. See docs/single-process-mode.md.
  • Local AI start page — the about:start new-tab page is a chat with a small language model running entirely on your machine via llama.cpp (no cloud, no network at inference time). Pick a model and it downloads once, integrity-checked against a pinned SHA-256 digest; optional GPU offload (Vulkan / Metal). The assistant can also pull a Wikipedia image, run a DuckDuckGo web search, or open a site for you. See docs/ai.md.
  • UI — tabs, bookmarks, find-in-page, save-to-PDF, JS console, settings, headless mode, and a C embedding API.

Download

Nightly builds, rebuilt from main each night. These point at the latest build — bleeding edge, expect rough edges.

Platform Download
Windows Windows store - nordstjernen-windows-x86_64.zip
macOS nordstjernen-macos.dmg
Debian nordstjernen-debian-amd64.deb
Ubuntu nordstjernen-ubuntu-amd64.deb
openSUSE nordstjernen-opensuse-x86_64.rpm
Linux (portable GTK+) nordstjernen-linux-x86_64.zip
Linux (portable, Qt) nordstjernen-linux-qt-x86_64.zip
Alpine (musl) nordstjernen-alpine-x86_64.apk (apk add) · .zip (portable)
FreeBSD (portable) nordstjernen-freebsd-x86_64.zip
NetBSD (portable) nordstjernen-netbsd-x86_64.zip
Java browser + API (JDK 21) nordstjernen-java.jar (runnable fat jar: java -jar) · sources · javadoc · API docs
Source nordstjernen-src.tar.xz

Checksums · all nightly files

Windows 10 or later is required: the GTK 4 frontend links DirectComposition (dcomp.dll), so the build will not start on Windows 7 (and GTK 4 targets Windows 10 anyway). The Qt frontend has the same floor — Qt 6 also requires Windows 10 — so there is no older-Windows build of either frontend.

Java (JVM). A Java binding embeds the engine on the JVM (requires JDK 21): org.nordstjernen.Nordstjernen drives fetch / parse / layout / script / render from Java — to RGBA, a BufferedImage, a PNG/PDF file, or extracted text — through a thin JNI bridge over the C embedding API (src/libnordstjernen.h). A no-JNI alternative (RemotePage / RemoteBrowser) drives a separate nordstjernen-renderer process over the renderer's HTTP/JSON protocol instead, so an engine crash can't take down the JVM. On top of that sits org.nordstjernen.app.Browser, a standalone Swing browser app with GTK-shell-style chrome (back / forward / reload / home / URL bar, a scrollbar, and keyboard shortcuts). The nightly ships a single runnable fat jar — java -jar nordstjernen-java.jar <url> launches the browser, and the same jar is the embedding library. See java/README.md.

Build

sudo apt install build-essential pkg-config meson ninja-build \
    libgtk-4-dev libepoxy-dev libcurl4-openssl-dev libssl-dev libuchardet-dev librsvg2-dev \
    libpsl-dev libsqlite3-dev libseccomp-dev libwebp-dev
meson setup builddir && meson compile -C builddir
./builddir/src/gtk/nordstjernen

lexbor, QuickJS, WAMR, Wuffs and pl_mpeg are vendored in-tree — no submodules, no downloads. The one exception is the optional local-AI feature: meson setup fetches and builds llama.cpp as a pinned subproject; pass -Dai=disabled for a fully offline build. Windows, Fedora, openSUSE and macOS instructions are in docs/. Keyboard, mouse and touch controls are documented in docs/Controls.md.

Dependencies

Nordstjernen is a clean-room engine — no upstream browser code. The moving parts:

Vendored in-tree (built from the main tree, no submodules):

Component Role
lexbor HTML5 → DOM parser, CSS, and the WHATWG URL module (ns_url_*)
QuickJS (quickjs-ng fork) JavaScript engine — no JIT, browser-side hooks added in-tree
WAMR (subset) WebAssembly interpreter behind the WebAssembly JS API (src/wasm.c)
Wuffs v0.4 Memory-safe image decoding — PNG, GIF, BMP, JPEG (WebP is decoded separately by libwebp)
pl_mpeg (MIT) Single-file MPEG-1 video decoder — inline <video> playback (src/video_decode.c)

Required system libraries:

Library Min version Role
GTK 4 ≥ 4.22.1 on Windows (MSYS2 stock), ≥ 4.14 elsewhere (≥ 4.22 preferred) UI toolkit, GSK renderer
GLib / GModule (ships with GTK) core types, dynamic module loading
libepoxy OpenGL/ES function dispatch for WebGL (src/webgl.c)
Pango (ships with GTK) text shaping and layout
libcurl ≥ 7.85 HTTP/2 networking, HSTS, cookies
OpenSSL (libcrypto) WebCrypto (crypto.subtle) — hashing, HMAC, AES, RSA, ECDSA/ECDH, HKDF/PBKDF2
uchardet charset detection for ns_html_decode_body
libpsl public-suffix list for cookie scoping
SQLite IndexedDB persistent storage
librsvg ≥ 2.46 SVG rendering / icons
libwebp WebP decoding (lossy VP8 + lossless VP8L)
libseccomp — (Linux only) syscall sandbox; no-op on macOS/Windows

Optional (auto-detected; feature compiled in when present):

Library Enables
poppler-glib inline PDF viewing
libavif AVIF images
fontconfig / pangoft2 extra font discovery backends

Video. <video> plays inline when the source is MPEG-1 (an .mpg / .mpeg / .m1v stream). The bytes are decoded entirely in-tree by pl_mpeg — a single-file, MIT-licensed MPEG-1 video decoder — inside the sandboxed renderer process; no external library, no GPU API, and no syscalls beyond memory are needed, so it runs comfortably under the seccomp filter. Decoded BGRA frames are advanced off the renderer's existing animation tick, honouring the autoplay, loop, muted, width/height, and poster attributes; a click toggles play/pause; and the HTMLMediaElement events (loadedmetadata, durationchange, canplay, timeupdate, play, pause, ended) fire on the element as it plays. Only one video codec is built in, by design — MPEG-1 is small, patent-free, and decodes in pure portable C.

The MPEG-1 stream's MP2 audio track plays too (unless the element is muted). The seccomp-sandboxed renderer can't open a sound device, so audio is handed to the unsandboxed nordstjernen-audio helper: pl_mpeg decodes the MP2 track to PCM and miniaudio (MIT / public-domain, vendored in-tree) plays it. The inline player drives the helper — open/play/pause/seek/stop ride the renderer→shell render channel, and looping re-syncs the audio at each wrap.

Other media. Nordstjernen ships no other media codecs. <audio> and non-MPEG-1 <video> render a poster and a play overlay; clicking it resolves the source URL inside the sandboxed renderer process and the UI shell hands it to an external player — mpv, VLC, celluloid, totem, mplayer or ffplay on Linux, otherwise the desktop's default handler for the media type (found via GAppInfo, so Flatpak players work too), the default app via open on macOS, and the registered handler on Windows. If none is found, a status-bar hint suggests installing mpv. A media player is therefore a recommended runtime dependency, not a build dependency: the .deb and .rpm packages Recommend one (defaulting to mpv) so playback works out of the box, while source builds need none. The player is launched from the UI shell, never from the page's untrusted renderer.

Streaming sites (YouTube and friends) drive <video> through MSE/blob: with no plain file URL. For those, clicking hands the page URL to the player instead, so mpv/VLC resolve it with yt-dlp — install yt-dlp alongside the player to watch them.

License

Nordstjernen Source License v1.0 — use, modify and redistribute freely, except as a competing browser; each release becomes MIT after ten years. See License.md. Commercial licenses by agreement.

Nordstjernen Source License is inspired by https://fsl.software/
The Functional Source License (FSL) is a Fair Source license that converts to Apache 2.0 or MIT.

Project home: https://nordstjernen.org · Copyright 2026 Andreas Røsdal.


Join the Discord

Builds

linux macos windows qt android java codeql Semgrep

Best viewed in Nordstjernen