TrailInk
GitHub

Heavy development · nothing here is finished

A map you can
read in the sun.

TrailInk turns a pocket e-ink reader into an offline map display for motorcycles and trails. No backlight to wash out, no battery gone by lunch. One still picture: where you are, where the route goes, what is around you.

  • 4.3″e-ink, 480×800, 220 PPI
  • 10 h+power only when the picture changes
  • 0bytes of network needed on the trail

Built on CrossPoint Reader. Map data © OpenStreetMap contributors.

The X4 panel drawing a town: outlined buildings, hatched forest, roads of different widths
real panel buildings, forest and water, 2506 ms

01 — why e-ink

A phone is a bad navigation display on a motorbike.

The screen washes out in direct sun. It cooks in a handlebar mount. The battery does not last a day of riding. E-ink has the opposite properties — and one hard cost you have to design around.

Readable in full sun

Reflective panel, no backlight. The brighter the day, the better it looks. Visor down, glance, done.

Days, not hours

Holding an image costs nothing. Power goes only into changing the picture, so the X4 runs for tens of hours.

Slow, and grey

A full refresh takes about 1.7 s; four grey levels cost an extra waveform pass, and lose their grey to the next one. That rules out a moving map.

So: a still picture

Position, route, surroundings — redrawn rarely, readable at a glance at speed. No rerouting, no voice, no traffic. The route is planned before you leave.

02 — the screen

Real framebuffers, not mockups.

The ones tagged device came off the panel over USB — send a coordinate and the device draws what is around it from tiles on its SD card. The one tagged preview is the same renderer running on a laptop against the same tiles, which is how styling gets tuned without reflashing. We keep the two labelled apart on purpose.

Honest caveat: the device renderer follows most of the style spec now — road widths, casings, buildings, forest, built-up and water areas all draw on the panel. Place labels, the route line and junction dots exist in the spec and in the laptop preview, not yet on the glass.

03 — how it is built

Three parts. All three exist.

  1. 01

    Map builder laptop

    Fetches an area from OpenStreetMap, projects and clips it, routes along real roads, and writes binary .tib tiles at three zoom levels. A browser tuning tool renders a pixel-exact 480×800 preview, so the styling gets judged as e-ink instead of as a pretty vector map.

  2. 02

    Firmware TrailInk, on the X4

    A fork of CrossPoint Reader. Map screen, BLE position receiver, tiles off the SD card, zoom and marker height on the physical buttons, ride / hike / cycle filter, and a command console over USB serial and BLE. The e-reader stack comes out; maps go in.

  3. 03

    Phone app Android

    Sends the phone's GPS fix to the device over BLE every few seconds and records every fix and packet for replay. One window, no settings screen, foreground service — it keeps sending with the phone locked in a bag. A GPS liveness gate throws away network fixes that would jump you across town.

OpenStreetMap map builder SD card .tib tiles X4 panel phone GPS over BLE

04 — status

What works today.

Formats, the render spec and the BLE protocol all still change without notice. Do not depend on any of it yet.

  • USB serial access, flash backup and inspectionworks
  • Map builder: OSM fetch, projection, clipping, routing on real roadsworks
  • Map builder: browser tuning tool with device-exact previewworks
  • Binary .tib tiles, three zoom levelsworks
  • Firmware: map screen and BLE position receiverworks
  • Firmware: tiles loaded off the SD cardworks
  • Firmware: command console over USB serial and BLEworks
  • Firmware: zoom and marker height on the buttonsworks
  • Firmware: ride / hike / cycle filterworks
  • Firmware: four grey levels, verified on the panel (map uses dither instead)works
  • Firmware: grey screenshots over USB serial, decoded on the laptopworks
  • Phone app: BLE position sender and ride recorderworks
  • Firmware: road widths and casings, buildings, forest, built-up and water areasworks
  • Firmware: map files pushed onto the SD card over BLEworks
  • Firmware: the marker follows the fix; the map only redraws when it has toworks
  • Firmware: track-up map, north indicator turns with itworks
  • Fetch missing tiles: the device asks, the phone brings them from the tile serverworks
  • Public tile server, so the phone does not have to build a mapworks
  • Map builder: build a route from waypoints, a GPX file, a recorded ride or the browser toolworks
  • Firmware: pick a route when the map opens, and see all of it at onceworks
  • Firmware: with a route loaded the map holds still — only the marker movesworks
  • Renderer: place labels and junction dotsplanned
  • Route following and off-route warning on the deviceplanned
  • Anything you could call a releaseplanned

05 — development log

Recent work, newest first.

  1. Following a route, the map stops turning

    The map used to swing round every time you turned far enough, because it kept your direction pointing up. Through hairpins that is constant: over one 3.4 km pass it redrew the whole screen eleven times into nine different orientations, twice ending up back where it started.

    With a route loaded it now stays the way the route runs, and only the marker moves — its arrow turns instead of the map. The same pass measured zero redraws in one orientation, and a recorded 7.4 km morning commute went from twelve down to two, both of those because the rider genuinely rode off the edge of the picture. On a screen that blanks to redraw, the picture holding still is the feature.

  2. The device asks for the map it is missing, and gets it

    It works now, all the way through. The device knows which map squares it never had, asks the phone for them, and the phone brings them down from a public tile server and hands them over Bluetooth. Five squares, 322 kB, 43 seconds — with a progress bar per square on the panel and a plain “not available” for anything the server has not been given yet.

    The phone keeps nothing. A map square belongs on the device or on the server, so the phone holds one only for the seconds it takes to pass it along. Nothing quietly fills up.

    It also got three times faster than the first attempt, and not by sending more at once. Bluetooth waits for an answer after every small piece, so the time between answers was the whole limit — the phone now asks for a faster rhythm while a transfer is running, and gives it back the moment it finishes, because holding it costs battery for nothing.

  3. The route goes on the device

    You plan a route on the laptop — from two clicked points routed along real roads, from a GPX file out of a planner, or from whatever the browser tool has drawn — and push it to the reader over Bluetooth. Opening the map now asks which route to load, or lets you skip and just have a map.

    Pick one and the first thing you see is the whole route on one screen. The device works out which zoom step and which direction fit it, by measuring the route itself rather than the box around it: a route running north-east occupies a thin diagonal strip, and turning the map to match it fits far more on the panel than keeping north up would. It also turns the route so your direction of travel runs up the screen. If the route is longer than the widest zoom can hold, it shows the middle and says so, rather than pretending.

    After that the route stays drawn over the map for the rest of the ride. It costs no memory at all, however long it is — the file is read a point at a time and each leg drawn as it arrives, so nothing is ever held. Measured on the panel: the whole-route screen takes 2537 ms, and a map redraw with a route loaded allocates nothing.

    One thing the laptop found before the hardware did. Choosing the direction purely by what fits drew a straight north-south route tilted 22.5° — mathematically the best fit, because a slight tilt trades screen height for width, and useless in practice since the zoom only comes in five fixed steps and both angles land on the same one. A map askew for a gain nobody can see. Direction of travel wins ties now.

  4. The marker moves; the map stays put

    A position update used to redraw the whole map. It no longer does. The new fix is placed inside the picture already on the panel, and only the marker is redrawn — the map is rebuilt when the marker nears an edge, when the rider has turned far enough that the map faces the wrong way, or after enough small moves to keep the panel clean. Over a real ride replayed onto the device, that turned 117 full redraws into 14, with 31 updates costing nothing at all.

    The map is also drawn track-up now: the direction of travel is up the screen and the north indicator turns to keep pointing north. That is what makes the look-ahead setting mean anything — with north pinned upward, the road ahead only landed in the empty half of the screen when you happened to be riding north.

    Two things we believed turned out to be wrong, and the panel said so. Refreshing a small rectangle costs exactly what refreshing the whole screen costs — 500 ms either way, the waveform does not care about area. So the saving is not the screen at all; it is the eight to fourteen seconds of reading tiles and drawing them that a redraw no longer spends. And the fix we expected to stop the map spinning in corners measured slightly worse than doing nothing. Corners are still the expensive case, and still open.

  5. The map reads like a map

    Buildings, forest and built-up areas now draw on the panel, filled with a dither pattern rather than hatch lines — at map scale a house is a handful of pixels, and lines across it read as dirt. Roads take a width per class, and the panel confirmed both.

    Which of the two a village gets is decided when the tiles are built: individual buildings up close, one built-up area from 6 m/px out. The device never reads what it would not draw, and that shows in the numbers — a viewport reset takes 2506 ms reading 484 KB at 3 m/px, and 1088 ms reading 198 KB at 6 m/px.

  6. Grey works on the panel — and the map still won't use it

    All four grey levels render and are distinguishable by eye. A full grey frame measures ~2.1 s, and it has to be the last thing that touches the panel: a refresh issued in the same breath breaks the picture. A repeated nudge lightens the same pixel and adds grain, so grey cannot be topped up in place.

    Judged side by side on the glass, the existing 2×2 dither simply read better for area fills — and it survives any refresh, because it is ordinary black and white. So fills stay dithered and four-level grey stays out of the map. The support layer and its test screen remain, behind a build flag, for the next panel question.

  7. Style tuning without a flash

    The device's own renderer now compiles as a host binary and runs against the style being edited, so the webapp preview shows real device output. Two seconds per edit instead of a build-and-flash cycle.

The full dated log lives in the repo, alongside one topic document per hardware finding — how the panel actually behaves, why the obvious approach fails. Read it on GitHub →

06 — the hardware

Xteink X4

A pocket e-ink reader, bought off the shelf. Not a dev board, not Android, no ADB — an ESP32-C3 with a display driver and physical buttons. Everything TrailInk does has to fit in that.

Panel
4.3″ e-ink, 480×800, 220 PPI, no touch
Grey
4 levels, ~1.7 s full refresh, ~0.5 s fast; map fills use 2×2 dither
SoC
ESP32-C3, WiFi + Bluetooth 5 LE
Storage
16 MB internal flash, maps on a separate SD card
Input
Physical buttons only
Wireless
BLE preferred over WiFi for everything
TrailInk boot screen on the X4: logo, name and version
Boot screen, firmware 1.5.0

07 — get in touch

Built by one person, in the open.

I ride, and I wanted a display that survives a sunny day on a handlebar. If you are doing something similar on Xteink hardware, or you want to try it, or you just want to tell me the map style is wrong — write to me.

Email

roman.fordinal@comsultia.com

Code

github.com/rfordinal/TrailInk

Firmware, docs and every hardware finding. MIT licensed.