Readable in full sun
Reflective panel, no backlight. The brighter the day, the better it looks. Visor down, glance, done.
Heavy development · nothing here is finished
ExplorInk 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.
Built on CrossPoint Reader. Map data © OpenStreetMap contributors.
01 · why e-ink
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.
Reflective panel, no backlight. The brighter the day, the better it looks. Visor down, glance, done.
Holding an image costs nothing. Power goes only into changing the picture, so the X4 runs for tens of hours.
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.
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
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 and casings, buildings, forest, built-up, filled water with waves, and railways as a blocked line all draw on the panel, and the route draws with them, and so do place names. Junction dots exist in the spec, not yet on the glass, and neither do the edge markers for a village just off the screen. The laptop preview is the other way round for the route: it renders everything here except the route line, so that one is judged on the device only.
03 · how it is built
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.
The built maps are on a public server, so nobody has to run the map builder to go riding: the phone downloads the squares the reader is missing, one plain file per square, and reads a small index to tell an empty square from one nobody has built — and a square that has gone out of date from a current one.
It also builds what it does not have. A square that comes back missing is written to the server’s own log, and a builder on the host takes the ten most-asked-for squares of the last day and builds them from OpenStreetMap straight into what it serves — about twenty seconds for a 13 by 13 km area, which is the missing square and the ground around it. Nothing already published is ever rewritten, and the day is capped, so an unattended builder cannot run away with the disk.
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.
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. It touches GPS only while the reader is actually connected, and shuts itself down a few minutes after the reader goes away — the reader opening its map starts it again. It is also the reader’s way to the tile server: the reader asks for a missing square, the phone fetches it and pushes it over Bluetooth onto the SD card, mid-ride. Source: github.com/rfordinal/explorink-android.
04 · status
Formats, the render spec and the BLE protocol all still change without notice. Do not depend on any of it yet.
.tib tiles, three zoom levelsworks05 · development log
Until today the map drew a dot for every town and village and never a name. The dot tells you something is there; it does not tell you it is Modra. Names are on the glass now, in two sizes — towns bold, villages lighter — and at the widest zoom the reader fits a dozen of them across 24 by 40 kilometres.
The hard part on a screen with no colour is keeping a name readable over a road network without blanking out the map to do it. Each name is outlined in white, letter by letter, so the roads and the forest keep running underneath. And a name is dropped rather than laid across your route, over another name, or under the buttons — the dot stays either way, so nothing goes missing, it just goes unnamed. Twelve names cost 163 milliseconds of a redraw that takes nearly four seconds.
Turn the reader off and the phone app used to carry on: GPS at one fix a second, the processor held awake, and a notification saying it was still sending your position. It was not sending anything — there was nothing on the other end. Swipe the notification away and it came back within a second.
All of it now hangs off one question: is the reader connected, or are you recording a ride? If neither, the app asks for no position, holds nothing awake, and after five minutes it shuts itself down. Opening the map on the reader starts it again on its own, so there is nothing to remember and nothing to press. The notification tells the truth in the meantime, and once dismissed it stays dismissed.
The map's menu — the one behind the middle button — used to throw the map away when you closed it. Every dismissal read the map squares off the card again and repainted the whole screen, seconds of it, to arrive back at the picture that was already there. The reader now keeps the pixels the menu covers and puts them back, refreshing only that patch of glass. Nothing to wait for.
The menu itself reads like the settings screen now: every line starts at the same edge, and the part you can change — ride mode, north up or heading up, and the rest — sits on the right in a filled box, so you can see what a line is set to without opening it. And the middle button no longer says “Select” on the map. It opens a menu, so it says “Options”.
Keeping those pixels costs memory, and the reader has 54 kilobytes free with a map on screen — measured, not guessed. The menu was eating twenty of them, because the box grew a line taller with every option in it. It has a ceiling now: six lines on screen, the rest scrolls, and the box stops growing no matter how long the list gets. Nine kilobytes instead of twenty, and the map behind it stays visible.
The zoom buttons stopped at 20 metres per pixel, which is about ten kilometres of ground down the screen. Enough to see the next village, not enough to see where the hills you are riding actually go. There are two more steps now, and the widest shows 24 by 40 kilometres — the full width of the Malé Karpaty, both flanks, every road that crosses the ridge, on one screen.
Zooming out that far is not free: the reader pulls twelve map squares off the card instead of six and draws them in 3.6 seconds. That is half of what the closest zoom already costs, and the map is only redrawn when you have moved far enough to need it.
Two things had to stop being fixed sizes for this to feel right. The position marker: it is a fixed dot on the glass, so the further out you go the more ground it hides — two kilometres of it, at the widest step. It is drawn smaller up there now. And the distance you have to travel before the marker is redrawn, which was a fixed number of pixels: eight metres of ground at the closest step, but three hundred and sixty at the widest, so the view that needed a steady trickle of updates got almost none. It follows the zoom now too.
Until today, a square nobody had built yet stayed a hatched square. The reader asks the phone for it, the phone asks the tile server, the server does not have it — and that was the end of the story.
Now that miss is the request. The tile server watches its own log of squares it could not serve, takes the ten most asked-for from the last day, and builds them from OpenStreetMap straight into what it serves. One build at a time, and the area around the square goes with it, so the ground you are riding into is there too. Measured on the server: about twenty seconds per area.
The reader had to learn patience for that to be worth anything. It used to cross a square off for good once the phone said it could not get it — sensible when a miss meant nobody had it, wrong now that the miss is what builds it. It waits and asks again instead, backing off from a minute and a half to an hour so a square that truly does not exist stops costing anyone data.
Tested end to end on the reader, on a drive across ground the map did not cover: four squares missing, two arrived from the server, the other two were built from the reader’s own asking and drew a minute later, while it kept moving. Nothing on the server rewrites a square that already exists — a hole gets filled, everything else is left alone.
Two small things the map screen was missing. A classic scale bar, bottom-left: five alternating black/white segments, ticks, and a rounded distance — 100 m, 1 km, whatever the current zoom rounds to. Numbers that would run into each other at a loose zoom are dropped, not smeared; the endpoints always stay.
The header is now a fixed white strip with a real 1px separator below it — the map no longer draws underneath and gets covered, it stops at the line. Top-left, it now names the nearest place: read straight off the same tile data that already draws the place dots, no extra card read for it.
Until today a ride started with a chore: unlock the phone, find the app, open it, wait for it to find the reader. Now the reader does it. Open the map on the device and the phone starts sending its position by itself — app closed, screen locked, nothing tapped. The signal was already there: the reader only talks over Bluetooth while the map is on screen, so the map opening is the announcement. What was missing was a phone that could hear it while shut down.
The phone now pairs with one reader, once, in a system dialog. That fixed a second problem nobody had noticed: two of these readers look identical over the air, same name, same service. The app used to talk to whichever answered first, so a second device in the room was a coin toss — and the loser gets a stranger’s position on their map. It is now a fixed address, not a guess.
Verified on the real device with a real phone: app killed, map opened, the phone woke itself, connected and sent a position with nobody touching it. Then again after restarting the phone, which is the case that usually breaks this kind of thing.
Real hardware found a real bug in five minutes, again. The pairing screen sat empty while the app was connected to the very device it was looking for: the reader stops announcing itself once a phone connects, and the pairing screen can only offer what it can hear. So the app now steps off the link while you pair, and steps back on afterwards.
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
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 ExplorInk does has to fit in that.
07 · early access
ExplorInk runs on real hardware today, but installing it still means a cable and a flashing tool. The maps are no longer the hard part — they are on a server that builds what riders ask for, and the phone brings them to the reader by itself. One-click install and a downloadable app are what comes next. Leave an address and you hear from me once, when there is something to put on a device.
You are on the list.
You already have the hardware, so you get the app and the one-click installer the day they work. Nothing else lands in your inbox.
You are on the list.
You do not have the reader yet. This is what it would cost to start, all in:
Xteink X4 + ExplorInk
€79
Not available yet.
Nothing is for sale — that button measured whether the bundle is worth building at all, and your click counted. You are on the list, and you hear from me when it exists.
08 · get in touch
ExplorInk is developed by Comsultia, s.r.o., a software company in Slovakia. It started because 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 us.