1
0
Nico Verbruggen 290b8a32b7
All checks were successful
Build and test project / build-and-test (push) Successful in 1m29s
Don't use nginx locally
2026-03-19 20:16:00 +01:00
2026-03-18 17:39:27 +01:00
2026-03-19 19:56:24 +01:00
2026-03-19 19:56:24 +01:00
2026-03-16 20:43:13 +01:00
2026-03-16 20:43:13 +01:00
2026-03-19 19:56:24 +01:00
2026-03-19 19:56:24 +01:00
2026-03-19 20:16:00 +01:00
2026-03-19 19:56:24 +01:00
2026-03-17 13:59:57 +01:00

Note

If this project has been useful to you, I ask that you please star the repository, that way I know that the software is being used. Also, please consider sponsoring to support my open source projects, as this is something I work on in my free time. Thank you!

KoboPatch Web UI

A web application for customising Kobo e-readers. It supports two modes:

  • NickelMenu — installs NickelMenu fork with an optional curated configuration (custom menus, fonts, screensavers, UI tweaks). Works with most Kobo devices regardless of software version. Can also remove NickelMenu from a connected device.

    • The safest patch to install. These modifications tend to persist with system updates as long as NickelMenu remains functional.
    • Will automatically uninstall itself if Kobo releases an incompatible update in the future, which may happen with software v5.x at some point.
  • Custom patches — applies community kobopatch patches to your Kobo's system software. Requires a supported software version and device model, which is currently limited to Kobo Libra Color, Kobo Clara Color and Kobo Clara BW models.

    • A more experimental solution -- you need to choose what tweaks to apply.
    • These changes are wiped when system updates are released. Requires re-patching when system updates are installed.
    • Gives you a lot of customization options, but not all of them may work correctly.

How it works

The app uses the Filesystem Access API (Chromium) to interface with connected Kobo devices, or falls back to manual model/software version selection with a downloadable ZIP on other browsers.

If you choose to apply custom patches, patching happens fully client-side — no backend needed, can be hosted as a static site. Patches are community-contributed via the MobileRead forums and need to be manually updated when new Kobo software versions come out.

Note

This project is not affiliated with Rakuten Kobo Inc. Patching modifies system files on your Kobo and will void your warranty. If something goes wrong, you may need to manually reset your device.

User flow

  1. Connect or download — auto-detect your Kobo via File System Access API on Chromium, or choose manual download mode (any browser)
  2. Choose mode — NickelMenu (install/configure/remove) or custom patches
  3. Configure — for NickelMenu: select install options (fonts, screensaver, tab/homescreen tweaks) or removal; for patches: enable/disable patches (or select none to restore original software)
  4. Review — confirm your selections before proceeding
  5. Install — write directly to the device (Chromium auto mode) or download a ZIP/tgz for manual installation

File structure

web/
  src/                          # Source assets (committed)
    index.html                  # Single-page app template
    css/
      style.css
    js/
      app.js                    # ES module entry point: step navigation, flow orchestration
      kobo-device.js            # KoboModels, KoboDevice class
      kobo-software-urls.js     # Fetches download URLs from JSON, getSoftwareUrl, getDevicesForVersion
      nickelmenu.js             # NickelMenuInstaller: downloads/bundles NickelMenu + config
      patch-ui.js               # PatchUI: loads patches, parses YAML, renders toggle UI
      patch-runner.js           # KoboPatchRunner: spawns Web Worker per build
      patch-worker.js           # Web Worker: loads WASM, runs patchFirmware()
      wasm_exec.js              # Go WASM runtime (copied from Go SDK by build.sh, gitignored)
    patches/
      index.json                # Available patch manifest
      downloads.json            # Firmware download URLs by version/serial (may be auto-generated)
      patches_*.zip             # Patch files per firmware version
    nickelmenu/                 # NickelMenu assets (generated by setup.sh, gitignored)
      NickelMenu.zip
      kobo-config.zip
    favicon/
  dist/                         # Build output (gitignored, fully regenerable)
    bundle.js                   # esbuild output (minified, content-hashed)
    index.html                  # Generated with cache-busted references
    css/ favicon/ patches/ nickelmenu/ wasm/ js/
  build.mjs                     # esbuild build script + asset copy
  package.json                  # esbuild, jszip

nickelmenu/
  setup.sh                      # Downloads NickelMenu.zip and bundles kobo-config.zip

kobopatch-wasm/
  main.go                       # Go entry point
  go.mod
  setup.sh                      # Clones kobopatch source, copies wasm_exec.js
  build.sh                      # Compiles WASM, copies to web/dist/wasm/ and web/src/js/
  integration_test.go
  test-integration.sh

tests/
  e2e/
    integration.spec.js         # Playwright E2E tests
    playwright.config.js
    run-e2e.sh

Adding a new software version

  1. Add the patch zip to web/src/patches/ and update index.json
  2. Add download URLs to web/src/patches/downloads.json (keyed by version then serial prefix)
  3. The Kobo CDN prefix per device family (e.g. kobo12, kobo13) is stable; the date path segment changes per release

Building the WASM binary

Requires Go 1.21+.

cd kobopatch-wasm
./setup.sh    # first time only
./build.sh    # compiles WASM, copies to web/dist/wasm/

Setting up NickelMenu assets

nickelmenu/setup.sh

This downloads NickelMenu.zip and clones/updates the kobo-config repo to bundle kobo-config.zip into web/src/nickelmenu/.

Building the frontend

The JS source lives in web/src/js/ as ES modules. esbuild bundles them into a single web/dist/bundle.js.

cd web
npm install
npm run build    # production build (minified)
npm run dev      # dev server with watch mode on :8889

Running locally

./serve-locally.sh

This serves the app at http://localhost:8888. The script automatically:

  1. Sets up NickelMenu assets if missing (web/src/nickelmenu/)
  2. Builds the JS bundle (web/dist/bundle.js)
  3. Builds the WASM binary if missing (web/dist/wasm/kobopatch.wasm)

You can delete the entire web/dist/ folder and re-run serve-locally.sh to regenerate everything.

Testing

E2E tests (Playwright)

The E2E tests cover all major user flows:

  • NickelMenu — install with config (manual download), install NickelMenu only, remove option disabled without device
  • Custom patches — full patching pipeline, restore original firmware, build failure with "Go Back" recovery
  • Device detection — firmware version validation (4.x supported, 5.x incompatible), unknown model warning
  • Back navigation — verifies every back button returns to the correct previous screen in both auto and manual mode
  • With simulated Kobo Libra Color — install NickelMenu with config, remove NickelMenu, install custom patches, restore firmware

The simulated device tests mock the File System Access API with an in-memory filesystem that mimics a Kobo Libra Color (serial prefix N428, firmware 4.45.23646).

Custom patches tests download firmware 4.45.23646 (~150MB, cached in kobopatch-wasm/testdata/), enable a single patch, and verify SHA1 checksums of all 4 patched binaries. This specific combination is used because the author has tested it on an actual device.

cd tests/e2e
./run-e2e.sh

To run with a visible browser window:

./run-e2e.sh --headed

To slow down each action (500ms delay) for debugging:

./run-e2e.sh --headed --slow

Extra Playwright arguments can be passed after --:

./run-e2e.sh --headed --slow -- --grep "NickelMenu"

WASM integration test

Calls patchFirmware() directly in Go/WASM via Node.js:

cd kobopatch-wasm
./test-integration.sh

Output validation

The WASM patcher performs several checks on each patched binary before including it in the output KoboRoot.tgz:

  • File size sanity check — the patched binary must be exactly the same size as the input. kobopatch does in-place byte replacement, so any size change indicates corruption.
  • ELF header validation — verifies the magic bytes (\x7fELF), 32-bit class, little-endian encoding, and ARM machine type (0x28) are intact after patching.
  • Archive consistency check — after building the output tar.gz, re-reads the entire archive and verifies the sum of entry sizes matches what was written.

Credits

Built on kobopatch and NickelMenu by pgaskin. Uses JSZip for client-side ZIP handling and esbuild for bundling. Software patches and discussion on the MobileRead forums.

License

MIT.

Description
SRC. Experimental Web UI for patching your Kobo firmware, runs completely clientside.
https://kp.nicoverbruggen.be
Readme 2.3 MiB
Languages
JavaScript 68%
HTML 11.9%
CSS 8.5%
Go 5.9%
Shell 5.7%