Initial commit: Chatter — assistive-writing app for reMarkable Paper Pro Move

Direct-framebuffer ink pipeline (stock-quality strokes), finger-wipe erase,
growable scrolling canvas with color-ghost cleanup, bidirectional toggle with a
persistent 4-finger return launcher, instant button feedback. Includes prebuilt
aarch64 binaries (dist/), build/deploy/install scripts, a user guide, and a
complete technical reference.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-27 16:34:28 +02:00
commit 5f21d9099c
43 changed files with 2878 additions and 0 deletions

View File

@@ -0,0 +1,140 @@
# Chatter — Phase 1 On-Device Findings
**Date:** 2026-06-25
**Device:** reMarkable Paper Pro Move (RM03A, codename "Chiappa")
**Method:** Read-only SSH probing from Jatke (`ssh chatter`). No changes made to
the device except enabling developer mode / SSH (Phase 0) and adding our SSH key.
This document records what we learned and the implementation decisions those
findings support. It feeds the phase plan in
[`Chatter_implementation.md`](Chatter_implementation.md).
---
## 1. Hardware & OS
- **SoC / arch:** NXP **i.MX93**, **aarch64** (Arm Cortex-A55). Kernel
`6.12.49+git-imx93-chiappa`.
- **OS:** Codex Linux 5.7.121 (Yocto **scarthgap**), image `3.27.1.0`. glibc
(`/lib/ld-linux-aarch64.so.1`, `libc.so.6`).
- **RAM:** 2 GB (~1.4 GB free) — ample for our app.
- **Storage (matters for deployment):**
- `/` (rootfs): ~435 MB, **only ~88 MB free (78% used)** — also an
OS-managed overlay, likely reset by firmware updates. **Do not install here.**
- `/home`: **46 GB encrypted volume, ~45.8 GB free.** Install Chatter under
`/home` (e.g. `/home/root/chatter`).
## 2. Input devices
Pen and finger are **separate evdev devices** — finger-vs-stylus discrimination
is free, exactly what Chatter's gesture design needs.
| Node | Name | Role | Notes |
|---|---|---|---|
| `event0` | `bbnsm:pwrkey` | Power button | |
| `event1` | Hall effect sensors | Folio open/close | switch events |
| **`event2`** | **Elan marker input** | **Stylus / Marker** | on SPI |
| **`event3`** | **Elan touch input** | **Capacitive multitouch (finger)** | `INPUT_PROP_DIRECT` |
**Pen (`event2`)** — digitizer space **6760 × 11960**:
- Buttons: `BTN_TOOL_PEN`, **`BTN_TOOL_RUBBER`** (Marker Plus eraser end —
flip-to-erase is detectable), `BTN_TOUCH`, `BTN_STYLUS`, `BTN_STYLUS2`.
- `ABS_PRESSURE` 04096, `ABS_DISTANCE` (hover) 065535, `ABS_TILT_X/Y` ±9000.
**Touch (`event3`)** — grid **1248 × 2208**:
- Up to **10 contacts** (`ABS_MT_SLOT` 09) with `ABS_MT_POSITION_X/Y`,
`ABS_MT_PRESSURE` (0255), `ABS_MT_TRACKING_ID`, `ABS_MT_TOOL_TYPE`.
All three coordinate spaces share the screen's portrait aspect (~0.5625):
panel 954×1696, pen 6760×11960, touch 1248×2208.
## 3. Display pipeline
- **DRM/KMS only — there is NO `/dev/fb*`** and `/sys/class/graphics` is empty.
Driver is **`imx-drm`**; device `/dev/dri/card0`; connector
**`card0-LVDS-1`** ("connected", "disabled" at rest — normal for e-ink, which
holds its image without continuous scanout).
- The connector advertises a **packed `365×1700` mode** (hardware buffer for the
E Ink Gallery 3 color subpixel layout); the logical screen is 954×1696. The
mapping is handled by the epaper plugin (below) — we don't touch it directly.
- **Implication:** the `mmap /dev/fb0` approach used by rmkit / libreMarkable on
older grayscale models **does not apply** to this device.
## 4. Graphics / UI stack — the key finding
- The stock app **`xochitl`** is a **Qt 6.8.2 / Qt Quick (QML)** application.
- It renders through a **custom Qt platform (QPA) plugin: `epaper`**
(`/usr/lib/plugins/platforms/libepaper.so`, links `libdrm`). Available QPA
plugins on-device: **`epaper`**, `minimal`, `offscreen`, `vnc`.
- Qt 6.8.2 runtime libraries and QML modules (`QtQuick`, `QtQuickControls2`,
etc.) are all present under `/usr/lib` and `/usr/lib/qml`. No dev headers
on-device (expected — we cross-build).
**This means the native path is wide open:** build Chatter as a **Qt 6 app** and
run it with **`-platform epaper`** to inherit working e-ink display + refresh,
instead of reverse-engineering DRM/KMS and waveform handling. This resolves the
project's highest-risk unknown in our favor.
## 5. Stock app & services
- `xochitl.service` — the main UI app (`/usr/bin/xochitl`, pid varies).
- `marker-manager.service` — "Remarkable CSL Marker Manager" (pen support).
- `rm-sync.service` — document sync to the reMarkable cloud.
- Plus metrics / MDM / crash-uploader services.
**Coexistence / toggle implication:** on a DRM/KMS device only one process owns
the display (DRM master) at a time, and xochitl holds it (and likely grabs the
input devices) while running. So the Chatter ↔ standard-GUI **toggle is a
hand-off** (stop or pause `xochitl` ↔ run Chatter, and a return path), **not an
overlay**. The exact mechanism (systemctl stop/start vs. SIGSTOP/SIGCONT) is to
be validated in the Phase 2 spike.
## 6. Document store (for the Save phase)
Location: **`/home/root/.local/share/remarkable/xochitl/`**. Per document:
- `UUID.metadata` — JSON: `visibleName`, `parent` (empty = top level; a folder
is a `CollectionType` document whose UUID is used as children's `parent`),
`type` (`DocumentType`), timestamps, `pinned`, etc.
- `UUID.content` — JSON: page list under `cPages.pages[]` (each page has an `id`,
ordering `idx`, `template`, scroll position, CRDT-style `timestamp` fields).
- `UUID/` — directory of per-page **`<pageUUID>.rm`** files.
- `UUID.thumbnails/` — page thumbnails.
- Store-root extras (Codex additions): `.tree` (binary "rM sync tree" index) and
`rm-search-index.db` (SQLite **search index**, not the canonical store).
**`.rm` page format:** header confirmed as **`reMarkable .lines file,
version=6`** — the v6 binary scene-tree format (documented by the community,
e.g. `rmscene`). Authoring valid v6 is possible but non-trivial.
**Save options (decide in Phase 5):**
1. **PDF/PNG-backed document** — render Chatter's canvas to PDF/PNG and create a
document that references it (xochitl already supports PDF documents). Far
simpler and robust; still a real, renamable/syncable library item.
2. **Native v6 `.rm`** — author the binary page format so the transcript is an
editable notebook. More work; revisit only if option 1 proves insufficient.
Either way, transcripts go under a **`Chatter`** `CollectionType` folder, with
filenames derived from date/time.
---
## 7. Decisions supported by Phase 1
1. **Stack: C++ / Qt 6.8.2**, rendered via the on-device **`epaper` QPA plugin**.
Cross-build with a Yocto **scarthgap** aarch64 SDK matching Qt 6.8.2 / the
device glibc.
2. **Input:** pen from `event2` (including `BTN_TOOL_RUBBER` for flip-to-erase),
finger from `event3` (10-pt). Confirm in Phase 2 whether Qt+epaper already
delivers these or we read evdev directly for custom gestures.
3. **Toggle = display/input hand-off** with xochitl, not an overlay.
4. **Save = PDF-backed document** (leaning), in a `Chatter` folder.
5. **Deploy under `/home`,** never the rootfs.
## 8. Open items for the Phase 2 spike
- Stand up the cross-SDK and build a trivial Qt app; run it with
`-platform epaper` **after stopping xochitl**; confirm it draws and refreshes.
- Verify how input arrives in a Qt app under epaper (Qt event stream vs. raw
evdev) and how reliably finger and pen separate at the Qt layer.
- Validate the toggle hand-off (stop/start vs. stop/cont) and a return path.