Skip to content

About

No description, website, or topics provided.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

10 Commits

Folders and files

Repository files navigation

Moonlight Oil 🌙

One double-click installer that turns a Windows PC into a private home library for someone who isn't technical.

Built for an 80-year-old dad: he clicks one icon, his books open. No accounts, no terminal, no cloud. Everything runs on his own computer in containers.

It bundles two open-source reading apps behind a single big-button home page:

App What it does Self-hosted
Storyteller Reads your ebooks with the audiobook narration in sync ✅ official image
FlowState Reader Calm, distraction-free focus reading ✅ built from source

The "combine to improve" idea

Storyteller ships a clean, declarative docker-compose self-hosting recipe. FlowState is a lovely little app but only shipped as a GitHub Pages site with no container. Moonlight Oil takes Storyteller's compose approach and extends it to both apps in one stack, then hides the whole thing behind:

  • a single installer that also sets up the container engine and WSL2, and
  • a single large-print home page so there's one icon to click, not two setups.

That's the improvement: the non-technical person gets one turnkey thing instead of two half-technical ones.

How a family member uses it

  1. Download MoonlightOilSetup.exe and double-click it.
  2. Pick Docker (recommended) or Podman, click Next, wait.
  3. Restart the PC once (only the first time).
  4. Double-click Dad's Library on the desktop. Done.

The full, gentle walkthrough is in docs/for-dad.md.

What the installer does under the hood

  • Turns on WSL2 (the Windows engine both Docker and Podman use).
  • Installs Docker Desktop or Podman silently.
  • Copies the stack to C:\Users\Public\MoonlightOil, generates a secure STORYTELLER_SECRET_KEY, and creates the desktop shortcut.
  • The shortcut runs launch.ps1, which cold-starts the engine, runs compose up -d, waits until the page answers, and opens the browser.

Details for tinkerers: docs/self-hosting.md.

What the home page does

It's the only screen the person this is built for ever sees, so it does rather more than link to two ports:

  • It knows what's actually running. Caddy proxies a same-origin probe for each service, so each button reads Starting up… or Ready rather than guessing. Clicking a service that isn't up yet explains itself instead of dropping you on a browser error page — which matters, because a cold container engine takes a minute and "This site can't be reached" is a dead end for someone who won't think to retry.
  • It never hardcodes a port. Caddy publishes the real ones at /config.json, so changing a port to dodge a conflict doesn't silently break the links.
  • It hands the library to a tablet. If the PC has an address on the home network, the page shows a QR code; point a phone camera at it and the library opens there, on the device someone actually wants to read on.
  • The text gets bigger. Three sizes, remembered between visits, scaling the whole page rather than just the body copy. Plus light/dark.

The QR code is generated by stack/home/qr.js — a from-scratch byte-mode encoder (Reed-Solomon, mask selection, the lot) in about 400 readable lines. A CDN would break the premise that nothing leaves the house, and a minified blob would leave nobody able to read it.

Repository layout

installer/
  moonlight-oil.iss      Inno Setup script → compiles to MoonlightOilSetup.exe
  AFTER_INSTALL.txt      the friendly "you're done, restart once" note
  assets/library.ico     desktop icon
  scripts/               PowerShell: install, launch, stop, uninstall, common
stack/
  docker-compose.yml     home + Storyteller + FlowState
  .env.example           documented settings (installer generates the real .env)
  caddy/Caddyfile        serves the home page; adds /config.json and /up/<service>
  home/index.html        the big-button landing page
  home/boot.js           applies the saved theme before the first paint
  home/app.js            live status, links, text size, tablet hand-off
  home/qr.js             dependency-free QR encoder (see below)
  flowstate/Dockerfile   builds FlowState Reader from source
site/                    VitePress documentation site
tests/                   validation suite (node:test) + a browser suite
docs/                    standalone markdown guides
.github/workflows/       CI pipelines (build + test)

Building the installer yourself

You don't have to — every push builds MoonlightOilSetup.exe in GitHub Actions (download it from the run's Artifacts, or from a v* tag's Release). To build locally on Windows with Inno Setup 6:

iscc installer\moonlight-oil.iss

The .exe lands in dist\.

Running the tests

npm test

186 tests, no Docker and no dependencies required. They cover the compose config, the Caddy config, the home page's markup and behaviour, the Dockerfile, the installer scripts, and the environment file — plus 58 for the QR encoder, which check its output against the constants printed in ISO/IEC 18004, verify that every Reed-Solomon block has zero syndromes, and read the payload back out of the finished matrix the way a decoder would.

To also drive the real page in a real browser:

npm run caddy:check     # ask Caddy whether the Caddyfile is valid
npm run home:up         # start just the home service
npm run test:browser    # 22 checks in headless Chromium
npm run home:down

That suite deliberately runs with Storyteller and FlowState down, because "not listening yet" is the state the home page exists to handle well. It has already earned its keep: it caught a Content-Security-Policy that blocked the page's own startup script, and an aria-disabled attribute that made a still-clickable card unreachable to assistive technology.

Documentation site

cd site
npm install
npm run dev

Builds with VitePress. Covers architecture, installation, self-hosting, branching strategy, CI/CD, and testing.

Contributing

See CONTRIBUTING.md for the branching strategy, CI checks, and how to set up locally.

Credits & licensing

This project only orchestrates other people's work — it doesn't copy their code. Storyteller and FlowState Reader are each under their own licenses; please respect them. FlowState is fetched and built from its upstream repository at image-build time.

About

No description, website, or topics provided.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages