Skip to content

CanPixel/brutalist-wiki

Repository files navigation

AURA - Offline Wikipedia

A brutalist, off-the-grid Wikipedia reader for ZIM archives. Built with Electron + React + @openzim/libzim, designed to run comfortably on small low-power devices (Hackberry CM5 / Ubuntu ARM) down to a 720×720 screen.

Aura

Home view Article view Search view

What it does

  • Reads any Kiwix .zim archive dropped into the project root or public/ (or linked via the import dialog). Multiple archives, switchable live.
  • Full media support - images, math SVGs, audio/video are streamed straight out of the archive through a custom zim:// Electron protocol. No extraction, no temp files. (Note: nopic and mini flavour ZIMs ship without photographs - use a maxi flavour to get pictures.)
  • Real article rendering - infoboxes, tables, figures and captions survive parsing and are restyled into the app's design language. Navigation clutter (navboxes, sidebars, reference lists, edit links) is stripped.
  • Full-text search (Xapian index) with live title suggestions, falling back to title search when the archive has no full-text index.
  • Featured feed - the illustrated featured-articles grid that ships on the ZIM's main page (the only photographs in a nopic archive) is harvested and shown on the home view.
  • Expedition feed - a shuffleable grid of random articles for aimless discovery.
  • Reader affordances - numbered table of contents, back/forward history, bookmarks, recent searches, reading-time estimate, image lightbox, paper/ink themes. All state persists per archive.
  • The Pretext ribbon - every article opens with a slim canvas band where the lead paragraph is typeset by a miniature Pretext-style layout engine: words are measured once, then re-wrapped with pure arithmetic at 60 fps while the wrap margin animates in. Drag the dashed margin with your pointer to reflow the text live; click to replay. The caption shows the honest numbers (n WORDS / m LINES / <0.1 MS).

Keyboard

Action Key
Focus search /
Back / Forward Alt+← / Alt+→ (or Cmd on macOS)
Navigate suggestions Enter, Esc to dismiss

Architecture

electron/
  main.js       # library management, zim:// protocol, article parsing IPC
  preload.cjs   # context-isolated bridge
src/
  store/auraStore.ts    # zustand app state: views, history, bookmarks
  components/           # TopBar, HomeView, SearchView, ArticleView, StatusBar
  styles.css            # the brutalist design system (paper + ink themes)

Article pipeline (main process): libzim entry → linkedom DOM → strip chrome/scripts → resolve every img/src, a/href against the article path → rewrite media to zim://<archiveId>/<path> and internal links to data-zim-path attributes → sanitize-html allowlist → renderer intercepts clicks and routes them through the store.

Search snippets and the random feed use a regex-based lightweight summarizer (no DOM parse) with an LRU cache, keeping cold-start costs low on ARM hardware.

Run

bun install
bun dev          # vite + electron with live reload
bun run build    # production renderer build into dist/

Place .zim files in the project root or public/. Get archives from library.kiwix.org - for a picture-rich experience pick a maxi flavour (e.g. wikipedia_en_top_maxi).

Packaging for Linux ARM64 (Hackberry CM5)

Two ways to produce the installable artifacts (.deb + .AppImage, output in dist-electron/):

Cross-build from a Mac (Apple Silicon) via Docker - the easy path. Start Docker Desktop, then:

bun run package:linux-arm64:docker

scripts/build-linux-arm64.sh runs the whole build in a native linux/arm64 node:22 container (node_modules isolated in a Docker volume, so your macOS install is untouched). Note that bun run package:linux-arm64 - electron-builder directly on macOS - cannot work: node-gyp can't cross-compile the libzim native module from macOS to Linux; that's what the container is for. The electronuserland/builder image doesn't work either - it's amd64-only, and under emulation the libzim installer downloads x86_64 binaries.

Or build on the device - @openzim/libzim ships prebuilt aarch64 binaries and Electron ships linux-arm64, so the stack runs natively on the CM5 (Pi 5):

# one-time toolchain (node-gyp needs these to link the libzim prebuilt)
sudo apt install -y build-essential python3 libatomic1

# install bun (or use node >= 20 + npm)
curl -fsSL https://bun.sh/install | bash

git clone <this repo> && cd pretexter-wiki
bun install                      # downloads libzim aarch64 + builds the binding
bun run start                    # build renderer + launch

# optional: produce installable artifacts (deb + AppImage)
bunx electron-builder --linux --arm64

Install with:

sudo dpkg -i dist-electron/pretexter_*_arm64.deb   # installs to /opt/Aura, desktop entry "Aura"
# or run the AppImage directly:
chmod +x Aura-*-arm64.AppImage && ./Aura-*-arm64.AppImage

The package ships a proper .desktop entry (aura.desktop, StartupWMClass=aura) and a 512 px icon, so it behaves in launchers and docks.

Hackberry CM5 / Ubuntu ARM64 notes

Device niceties, all automatic or via environment:

  • Small screens: on displays ≤ 800 px the window opens fullscreen; F11 toggles.
  • ZIM location: archives are discovered in AURA_ZIM_DIR, ~/Zim, the app's user-data zim/ folder, and the repo root/public/ when running from source.
  • GPU trouble: AURA_NO_GPU=1 aura forces software rendering.

To autostart on boot (labwc/wayfire session), add aura (or bun run start from the repo) to your compositor's autostart file.

Performance on the CM5

The app is tuned for slow storage and a modest GPU out of the box:

  • Library state lives in memory - navigation, bookmarks and searches never trigger a disk scan; the workspace file is written asynchronously and coalesced (single write per ~300 ms burst, flushed on quit). SD-card latency stays off the UI path.
  • Article/summary LRU caches in the main process mean back/forward navigation re-renders without re-parsing, and zim:// media responses are marked immutable so Chromium's HTTP cache serves repeat images without touching the archive.
  • Spellcheck is disabled (an offline device would otherwise waste memory and periodically try to download dictionaries).
  • Search snippets and the random feed use a regex summarizer (no DOM parse) to keep cold starts cheap.

Things you control:

  • Put ZIMs on the fastest storage you have. Full-text search (Xapian) and cluster decompression are I/O-bound; NVMe via the CM5's PCIe lane ≫ eMMC ≫ SD card.
  • Prefer the GPU. Leave AURA_NO_GPU unset unless you see rendering glitches - software rasterization costs far more CPU on a Pi-class SoC than the V3D GPU does.
  • On a Wayland session (labwc/wayfire), Electron picks its backend automatically; if you see poor scrolling under XWayland, try aura --ozone-platform=wayland.
  • Pick a ZIM that fits your RAM/storage budget - mini/nopic flavours keep the archive (and its search index) dramatically smaller than maxi.

About

Off-the-grid Wikipedia reader for ZIM archives, tuned for small ARM devices with a brutalist theme.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors