Skip to content

About

Lightweight open-source firmware for Xteink e-paper reader (X4 v2, X4 pro, X4, X3) • EPUB/FB2/MD/TXT support • Custom themes & fonts

Topics

Resources

Stars

501 stars

Watchers

6 watching

Forks

Repository files navigation

PapyriX

Changelog User Guide Customization Fonts Architecture Device Specs X4 Specs X3 Specs File Formats Images SSD1677 Driver Webserver Calibre Printer LocalSend

PapyriX

PapyriX is firmware for Xteink X3, X4, X4 Pro, X4 v2 Classic, and Seeed reTerminal Sticky e-paper readers. X3/X4 use one ESP32-C3 image. Pro, Classic, and Sticky use separate ESP32-S3 images.

Warning: Some Xteink units (for example, units from AliExpress) lock USB flash. If USB flash is locked, you cannot update or recover through USB. Install, update, and do emergency recovery from the SD card. Flash through USB only on devices that have unlocked USB.

Home screen

This project is not affiliated with Xteink. It is a community project.

Supported devices

  • Xteink X4 (original)

    • Release file: papyrix-xteink-c3.bin
    • Panel: 800×480 SSD1677
  • Xteink X3

    • Release file: papyrix-xteink-c3.bin
    • Panel: 792×528 UC8253 or UC8279
  • Xteink X4 Pro

    • Release file: papyrix-x4pro.bin
    • Panel: 800×480 UC8279 or UC8179
  • Xteink X4 v2 Classic

    • Release file: papyrix-x4c.bin
    • Panel: 800×480 SSD1677, UC8179, or UC8279
  • Seeed reTerminal Sticky

    • Status: implemented, not device-tested
    • App update: papyrix-sticky.bin
    • First installation: papyrix-sticky-install.zip
    • Panel: 800×480 SSD1677 or SSD2677

See the device support matrix for build targets and hardware services. Using the wrong binary can drive incorrect pins and can damage hardware.

Page caches use profile-specific folders. Moving an SD card between supported devices does not reuse incompatible rendered pages.

Devices tested on hardware

  • Xteink X3
  • Xteink X4 (original)
  • Xteink X4 Pro
  • Xteink X4 v2 Classic

Features

Reading & Format Support

  • EPUB 2 and EPUB 3 parse (nav.xhtml, with NCX as fallback)
  • CSS stylesheet parse (text-align, font-style, font-weight, text-indent, margins, direction)
  • Preformatted text (<pre>) and inline code (<code>, <tt>, <kbd>, <samp>) shown as italic (no monospace font in the firmware)
  • FB2 (FictionBook 2.0) with metadata, TOC navigation, and metadata cache (no inline images)
  • HTML (.html, .htm) files (standalone HTML documents)
  • XTC/XTCH native format
  • Markdown (.md, .markdown) files with formatting
  • Plain text (.txt, .text) files
  • Saved reading position
  • Books that you opened before (Books screen) so you can continue quickly
  • Reading statistics for each book (progress, reading time, and sessions)
  • Bookmarks (maximum 20 for each book, saved on the SD card)
  • Book cover display (JPG/JPEG/PNG/BMP, case-insensitive)
  • Table of contents navigation
  • Images in EPUB (JPEG/PNG/BMP; see supported formats and limits)

Text & Display

  • Font sizes that you can set (XSmall/Small/Normal/Large)
  • Paragraph alignment (Justified/Left/Center/Right)
  • Text layout presets (Compact/Standard/Large) for indent and spacing
  • Soft hyphen support for text layout
  • Liang-pattern hyphenation. Language comes from EPUB metadata (de, en, es, fr, it, ru, uk)
  • Vietnamese, Thai, Greek, and Arabic in the builtin fonts
  • CJK (Chinese/Japanese/Korean) text layout (book text only, not UI)
  • Thai text with correct mark positions
  • Arabic text shaping. Contextual forms and Lam-Alef ligatures with RTL layout
  • Knuth-Plass line break algorithm (TeX-quality justified text)
  • Text anti-aliasing on/off (grayscale text for builtin fonts and custom fonts)
  • Pages per refresh setting (1/5/10/15/30)
  • Sunlight fading fix (powers down the display after refresh to prevent UV fade)
  • Turbo LUTs with LUT cache for faster X3 page turns
  • 4 screen orientations
  • Touch controls on X4 Pro and Sticky
  • Front-light brightness and warmth on X4 Pro

Customization

  • Custom themes from the SD card (/config/themes/)
  • Custom fonts from the SD card (/config/fonts/, .epdfont format)
  • Custom sleep screens (Dark/Light/Custom/Cover/Keep Page modes)
  • Button remapping (side buttons and front buttons)
  • Power button actions (page turn, bookmark, or sleep on a short press)

Applications

  • Image Viewer and slideshow
  • Clock with multiple faces
  • Pomodoro timer

Network & Connectivity

  • WiFi file transfer (web server)
  • Calibre Wireless Device. Send books from Calibre desktop
  • LocalSend receiver. Send files and books from the LocalSend app to the device over WiFi.
  • Driverless network printer (AirPrint-compatible). Print from macOS, Windows, Linux, iOS, and Android to the e-paper screen. Printouts save to /printouts on the SD card

Maintenance

  • Cleanup menu (clear book cache, empty trash, clear storage, factory reset)
  • Firmware updates from the SD card
  • System info (version, uptime, memory, storage)

File System

  • exFAT and FAT32 SD card support
  • UTF-8 filenames through the Web UI for Latin (including Vietnamese), Cyrillic, Greek, Thai, and Arabic
  • File explorer with nested folders
  • Recycle bin (/trash). If you delete a book, the device moves it to /trash. It does not remove the book. You can browse to restore it or delete it permanently. You can empty the trash from the Cleanup menu
  • Hidden system folder filter (LOST.DIR, $RECYCLE.BIN, and other system folders)

Tip: The Web UI folder create, upload, and rename functions change supported Unicode names to NFC. Names have a limit of 255 UTF-8 bytes. Full paths have a limit of 1023 bytes. CJK filenames are not supported. The device file-browser UI does not have CJK glyphs. For deep folder trees with supported non-Latin names, use exFAT, not FAT32.

See the user guide for operation procedures. See the customization guide for themes and fonts. Example theme files and font files are in docs/examples/.

Installing & Firmware Updates

Do you need to recover a device that does not start? Go to emergency recovery.

Use the image listed for your device under Supported devices.

For Sticky first installation, follow the complete install procedure. It replaces stock firmware and can erase device data. Save full-flash and SD backups first. Stock restoration remains unverified.

Pro, Classic, and Sticky images are not interchangeable. Do not erase the chip or install a full-flash image from another device. For Classic partition and OTA-slot requirements, see the Classic specifications.

New firmware requires one matching board tag for SD, web-uploaded, and emergency updates. It rejects older untagged images, even when the MCU matches. An untagged downgrade requires unlocked serial flashing. USB-locked units can be unable to downgrade. Old installed updaters and serial flashing do not enforce the new board check. See update compatibility for the shared validation rules.

For X3 and the original X4, the usual installation tool is papyrix-flasher:

papyrix-flasher flash papyrix-xteink-c3.bin

Do not flash an S3 image to a C3 device or a C3 image to an S3 device.

SD app updates: This procedure requires an existing PapyriX installation. It does not install PapyriX over Sticky stock firmware.

  1. Copy the firmware file as /firmware.bin to the root of your SD card.
  2. Put the SD card into the device.
  3. Go to Settings > Firmware Update and press Run.

The updater validates the image before flash erase. A successful update restarts the device.

Emergency Recovery

If PapyriX cannot open the UI, copy the correct app image as /force_update.bin to the SD card. PapyriX validates and applies it before UI initialization. The update can run without a working display. The boot path removes the file after the attempt. Copy it again before a retry.

This path requires PapyriX to reach its boot code and mount the SD card. It cannot repair a damaged bootloader or restore stock firmware. See firmware recovery for the procedure and limits.

Development

Prerequisites

  • PlatformIO Core (pio) or VS Code + PlatformIO IDE
  • Python 3.12+ with uv (for font conversion)
  • Node.js 18+ (for sleep screen scripts and logo scripts)
  • USB-C data cable
  • A supported device with unlocked flashing, for upload and hardware checks

Install Node.js dependencies (for sleep screen scripts and logo scripts):

cd scripts && npm install

Using Nix

If you have Nix, shell.nix supplies all dependencies:

# Enter development environment
nix-shell

# Or run commands directly
nix-shell --run "make build"
nix-shell --run "make check"

First-time Nix setup:

# Install Nix (if not installed)
sh <(curl -L https://nixos.org/nix/install) --daemon

# Add nixpkgs channel
nix-channel --add https://nixos.org/channels/nixos-unstable nixpkgs
nix-channel --update

Checking out the code

PapyriX uses PlatformIO to build and flash the firmware. Clone the repository:

git clone --recursive https://github.com/bigbag/papyrix-reader

# Or, if you've already cloned without --recursive:
git submodule update --init --recursive

Building

Run host tests before you build firmware. Host tests require CMake 3.16 or later, Make, C and C++17 compilers, and the Expat development library. CMake downloads pngle 1.0.2 and checks its archive hash on the first configuration. The download requires network access. CMake keeps the source in test/build/_deps for later builds. Host tests do not require PlatformIO packages.

# Build and run host tests
make test

# Build development firmware for X3/X4
make build

# Build development firmware for X4 Pro
pio run -e x4pro

# Build development firmware for X4 v2 Classic
pio run -e x4c

# Build development firmware for Sticky
pio run -e sticky

# Build all four release environments
make release

# Build, verify, and package deterministic release files in dist/
make package

Flashing your device

For Sticky, use the complete first-install bundle. Sticky uses the CH343P UART0 serial port, not native USB-Serial/JTAG. The commands below apply to Xteink devices.

Connect the device through unlocked USB. Build and flash the release firmware for the device:

make flash-xteink-c3  # X3 and X4
make flash-x4pro      # X4 Pro
make flash-x4c        # X4 v2 Classic

On X4 Pro, hold Power throughout flashing. Release Power after verification completes and the application starts. Close the serial monitor before flashing. To select a port:

PLATFORMIO_UPLOAD_PORT=/dev/ttyACM0 make flash-x4pro

make flash-release and make upload-release select X3/X4 only. The following commands update only the application at 0x10000. Use them only when the device partition table matches and this slot is selected for boot. Use esptool 5.4 or later.

# ESP32-C3: X3/X4
esptool --chip esp32c3 --port /dev/ttyACM0 --baud 460800 \
  write-flash -z 0x10000 papyrix-xteink-c3.bin

# ESP32-S3: X4 Pro
esptool --chip esp32s3 --port /dev/ttyACM0 --baud 460800 \
  write-flash -z 0x10000 papyrix-x4pro.bin

# ESP32-S3: X4 v2 Classic
esptool --chip esp32s3 --port /dev/ttyACM0 --baud 460800 \
  write-flash -z 0x10000 papyrix-x4c.bin

PlatformIO upload remains available for a connected development target:

pio run -e default --target upload
pio run -e x4pro --target upload
pio run -e x4c --target upload

Replace /dev/ttyACM0 with the device port. Use COM3 on Windows or /dev/tty.usbmodem* on macOS where applicable.

Build Scripts

Build scripts are in the scripts/ directory.

Converting fonts

Convert TTF/OTF fonts to the PapyriX .epdfont format with Python (you need uv):

# Basic conversion (outputs to current directory)
uv run scripts/fontconvert.py my-font -r MyFont-Regular.ttf --2bit

# Full font family with all reader sizes (14, 16, 18pt)
uv run scripts/fontconvert.py my-font -r Regular.ttf -b Bold.ttf --2bit --all-sizes -o /tmp/fonts/

# With Thai script support
uv run scripts/fontconvert.py my-font -r Regular.ttf --2bit --thai -o /tmp/fonts/

# With Arabic script support
uv run scripts/fontconvert.py my-font -r Regular.ttf --2bit --arabic -o /tmp/fonts/

# Generate C header instead of binary (for builtin fonts)
uv run scripts/fontconvert.py my_font 16 Regular.ttf --2bit > my_font_16_2b.h

Options: -r/--regular, -b/--bold, -i/--italic, -o/--output, -s/--size, --2bit, --all-sizes, --header, --thai, --arabic

See the customization guide for the full font conversion procedure.

Creating sleep screen images

Convert an image to the sleep screen BMP format (run cd scripts && npm install first):

# With Makefile
make sleep-screen INPUT=photo.jpg OUTPUT=sleep.bmp
make sleep-screen INPUT=photo.jpg OUTPUT=sleep.bmp ARGS='--dither --bits 8'

# Or directly
cd scripts && node create-sleep-screen.mjs photo.jpg sleep.bmp --dither --bits 8

Options:

  • --orientation portrait|landscape - Screen orientation (default: portrait)
  • --bits 2|4|8 - Output bit depth (default: 4)
  • --dither - Enable Floyd-Steinberg dithering
  • --fit contain|cover|stretch - Resize mode (default: contain)

Copy the output BMP to the /sleep/ directory or as /sleep.bmp on the SD card.

Converting logo

Convert an image to a C header for the firmware logo (384x384 monochrome):

cd scripts && node convert-logo.mjs ../images/logo-light.jpg ../src/images/PapyrixLogo.h

Options: --invert, --threshold <0-255>, --rotate <0|90|180|270> (default: 270)

Calibre simulators (development/testing)

Two simulators let you test the Calibre Wireless Device feature with no real hardware:

cd scripts

# Simulate a PapyriX device (for testing Calibre desktop connection)
node device-simulator.mjs

# Simulate Calibre desktop (for testing device firmware)
node calibre-simulator.mjs

The device simulator listens for Calibre broadcasts and can receive books (saved to scripts/received_books/). The Calibre simulator sends discovery packets and sends test books to connected devices.

Serial monitor

A standalone Go binary reads device logs with no PlatformIO. Pre-built binaries are on the releases page. You can also build from source:

cd tools/monitor && go build -o monitor .

Usage:

./monitor                                  # Auto-detect port
./monitor -port /dev/ttyACM0               # Explicit port
./monitor -port /dev/ttyACM0 -log out.txt  # Also save to file
./monitor -speed 921600                    # Custom baud rate (default: 115200)

Reader test (desktop)

A desktop tool tests the content parse pipeline (EPUB, FB2, HTML, TXT, Markdown) with no flash to hardware. Use it to find parse defects, layout defects, or crashes.

# Build only
make reader-test

# Build and process a book
make reader-test FILE=book.epub OUTPUT=/tmp/cache

# Dump parsed text content of each page
tools/reader-test/build/reader-test --dump book.epub /tmp/cache

Options:

  • --dump — Print the parsed text of each page (use this to verify entity resolution, text extraction, and layout)

Creating a GitHub release

# With auto-generated notes from commits
make gh-release VERSION=0.1.1

# With custom notes
make gh-release VERSION=0.1.1 NOTES="Release notes here"

Generating changelog

Make CHANGELOG.md from git tags and commit history:

make changelog

This makes a changelog grouped by version tags, with commit messages and author data.

Internals

PapyriX retains the low-memory ESP32-C3 path. ESP32-S3 targets also use PSRAM for selected reader buffers. See the architecture and S3 reader platform.

Data caching

The device caches book data on the SD card. Each model uses a device-specific cache directory.

To clear cached data, use Settings > Cleanup (see User Guide). Clearing the book cache also removes reading progress. Deleting the entire .papyrix directory also removes reading history.

The cache does not clear automatically when you delete a book. If you move a book file, the device uses a new cache directory. This resets the reading progress.

See file formats for cache records. See the rendering pipeline for cache scheduling and ownership.

Related Tools

EPUB to XTC Converter (Web)

epub-to-xtc-converter — browser-based converter from EPUB to the Xteink native XTC/XTCH format. It uses CREngine WASM for accurate rendering.

  • Device presets for Xteink X4 (480×800) and X3 (528×792)
  • Font selection from Google Fonts or custom TTF/OTF
  • Margins, line height, and hyphenation that you can set (42 languages)
  • Dark mode and dithering options
  • Batch processing and ZIP export

Live version: liashkov.site/epub-to-xtc-converter

EPUB Optimizer (CLI)

xteink-epub-optimizer — command-line tool that prepares EPUB files for the Xteink X4 limits (480×800 display, limited RAM):

  • CSS Sanitization - Removes complex layouts (floats, flexbox, grid)
  • Font Removal - Removes embedded fonts to decrease file size
  • Image Optimization - Grayscale conversion, resize to 480px maximum width
  • XTC/XTCH Conversion - Convert EPUBs to the Xteink native format
# Optimize EPUB
python src/optimizer.py ./ebooks ./optimized

# Convert to XTCH format
python src/converter.py book.epub book.xtch --font fonts/MyFont.ttf

Contributing

Contributions are welcome.

To submit a contribution:

  1. Fork the repo
  2. Create a branch (feature/your-feature)
  3. Make changes
  4. Submit a PR

PapyriX is a fork of CrossPoint Reader by Dave Allie.

The IPP print server core (lib/Ipp) comes from the crosspoint-reader fork by Nishant Joshi, commit df0d5e3.

X4 hardware data comes from bb_epaper by Larry Bank.

Markdown parse uses MD4C by Martin Mitáš.

CSS parser is adapted from microreader by CidVonHighwind.

Not affiliated with Xteink or a manufacturer of the X4 hardware.

About

Lightweight open-source firmware for Xteink e-paper reader (X4 v2, X4 pro, X4, X3) • EPUB/FB2/MD/TXT support • Custom themes & fonts

Topics

Resources

Stars

501 stars

Watchers

6 watching

Forks

Releases

Used by

Contributors

Languages