flasher · usb, in the browser
Flash ExplorInk from the browser
Plug the device in with a USB-C cable, pick which one it is, read its stock flash into a file you keep, then write ExplorInk onto it. No Python, no esptool, no toolchain. It all runs on your own computer over Web Serial: no image is uploaded anywhere and no server sees your device.
Flash it What gets written After the flash The command line way
Flash it, in four steps
The order matters. Read the flash before you write it: what the device shipped with is not downloadable from anywhere, so the copy you make here is the only way back to the vendor’s own reader firmware.
python3 tools/stage_firmware.py --pio-root <a built firmware checkout>
in web/ and reload. Reason given by the browser: unknown.
-
1
Connect the device
Plug it into the computer with a data USB-C cable. If it does not answer, put it in download mode by hand: hold BOOT, tap RESET, let go of BOOT. Then click connect and pick the port. Every board here shows up as vendor id
303a; a phone on the same machine shows up as a serial port too, so check the vendor id rather than guessing from the port name.Not connected.
-
2
Say which device it is
The chip answers for itself once connected, and this page refuses to write a build meant for a different chip family. That check is the whole reason the device picker is here: one USB id covers every Espressif board on the desk, so the port cannot tell an ESP32-C3 reader from an ESP32-S3 one.
-
3
Back up the stock flash
This reads all 16 MB off the device into one file. It takes several minutes and it writes nothing. Keep the file: writing it back is the same mechanism in reverse, and it is what turns this from a one way door into an experiment you can undo. A bare development board has nothing on it worth keeping, so there you can skip this step.
Connect first.
-
4
Write ExplorInk
Four images go on: the bootloader, the partition table, the eight kilobytes that say which app slot to boot, and the firmware itself. About a minute. When it finishes the device resets itself and boots the new firmware. Do not unplug it while the bar is moving.
Connect first.
Log
Everything the flashing tool says, verbatim. If a step fails, this is the text worth copying into a bug report.
What gets written, and where
Four images at four fixed offsets, the same four that a PlatformIO upload writes, in the same places.
| Offset | Image | How we know |
|---|---|---|
0x0 |
bootloader.bin |
Every 16 MB dump we have taken off these devices starts with 0xE9, the ESP image magic, so the bootloader really does sit at zero on both the C3 and the S3, and not at 0x1000 as on the original ESP32. |
0x8000 |
partitions.bin |
The same dumps start 0xAA 0x50 there, which is the partition table magic. |
0xe000 |
boot_app0.bin |
Eight kilobytes that say “boot the first app slot”. otadata sits at 0xe000 in our partition table, and the build tool writes the framework’s copy there on every upload. |
0x10000 |
firmware.bin |
An app image header, 0xE9 again, at the offset the partition table gives for the first app slot. |
Nothing else is touched. Settings, saved pins and the map cache live in other partitions and on the SD card, and this page does not erase the chip. Getting an offset wrong would brick a stranger’s device, so they are checked against real flash dumps rather than copied forward on trust.
One of the four is not in the download. The published archives for the C3 readers
carry three files and leave out boot_app0.bin. On a device that already
boots its first app slot, which is every one we have flashed, that changes nothing. On a
reader whose own firmware updated itself into the second slot it changes everything: the
bootloader would start the slot nobody wrote. So this page writes all four, and the fourth
comes from the build tool’s own copy rather than from the archive.
The images are served from this same site, next to the page. Firmware published as GitHub release assets cannot be fetched by a browser from here at all: that host sends no cross origin header. What this page serves is a copy, and every file carries the checksum from the release it came out of.
After the flash
Put a FAT32 microSD card in, install the Android app, and open Explore on the device. The card can be blank: map squares arrive over Bluetooth from the phone, and the firmware creates its own directories as they land. The install guide has that half in full, plus the phone app download.
What this page does not do
- It does not test anything. A write that reports success says the bytes are on the device, and nothing about whether that build works on your unit.
- It does not unlock a locked device. Units sold locked never enumerate over USB, so there is no port to pick and nothing to flash.
- It does not write your backup back for you. Restoring the stock image is the same mechanism in reverse and is not wired up here yet.
When it goes wrong
| What you see | What it is |
|---|---|
| No port in the picker | A charge only cable, a locked unit, or the device is asleep. A sleeping device drops off the USB bus until a button wakes it. |
Invalid head of packet |
Almost always the wrong port rather than a bad cable. Pick the one whose vendor id is 303a. |
| Connect times out | The device never entered download mode. Hold BOOT, tap RESET, let go, and connect again. |
| The chip does not match the device | The picker and the board disagree. An ESP32-C3 build on an ESP32-S3 board produces a device that does not boot, which is why the write button stays disabled. |
| It is written but the screen stays blank | Write it again, or write your stock backup back. The chip’s own boot ROM answers over USB even when the firmware on top of it is hung, which is why the way back is always reachable. |
The command line way still works
Nothing here replaces esptool. If you would rather see every byte go past,
the install guide has the three
commands, the backup command first.