An experiment with the line files for the remarkable tablet. The
stretch goal is to be able to convert a .SVG
file to a .rm
file. Preferably also with the ability to insert it into the tablets
file system.
This project explores AI-assisted development for working with the ReMarkable format. Earlier iterations used Claude 3 and GPT-4; it is now maintained with Codex CLI.
- Runtime deps: installed from
requirements.txt
(kept lean; excludesmanim
). - QA deps (CI/locals): installed from
requirements-qa.txt
and invoked viamake qa
. - Optional dev extras:
requirements-dev.txt
includesmanim
and other extras for local-only workflows. CI does not install these to avoid system packages.
Typical workflows:
- Quick tests:
make test-quick
- Full QA:
make qa
(lint, type-check, tests with coverage, security) - CI pipeline: runs
make ci
(nomanim
)
- Install dev extras:
source .venv/bin/activate && pip install -r requirements-dev.txt
- You may need system packages for Pango/Cairo bindings:
- macOS (Homebrew):
brew install cairo pango
- Ubuntu/Debian:
sudo apt-get update && sudo apt-get install -y libpangocairo-1.0-0 libcairo2-dev libpango1.0-dev
- macOS (Homebrew):
Note: CI intentionally avoids installing manim
(and pangocairo
) to
keep the pipeline fast and portable. Use local installs when you
experiment with scene.py
or any rendering tasks.
This repo includes a small CLI used for future notebook read/write workflows.
- Install locally (editable):
pip install -e
. - Run:
rmfiles --help
.
- Run via module (no install needed from repo root):
python -m rmfiles --help
- Or ensure the console script is installed into your venv and visible on PATH:
source .venv/bin/activate && pip install -e
which rmfiles
should point inside.venv/bin/rmfiles
- If your shell caches commands, refresh:
hash -r
(bash) or restart the shell
Examples:
- Create a simple triangle notebook:
rmfiles new --out output.rm --label "Triangle Layer" --center-x 200 --center-y 200 --size 150
- Inspect a file (basic header + optional block counts if
rmscene
is installed):rmfiles inspect output.rm
- Convert an existing
.rm
drawing to SVG:rmfiles svg fixtures/extracted_rm_file.rm --out output.svg
Generate a simple .rm
file with a visible rectangle using the
rmscene-backed helpers in rmfiles.generate
:
# Create and write a rectangle .rm
from rmfiles.generate import create_rectangle_rm
create_rectangle_rm("output/rect.rm", x=100, y=120, width=300, height=200)
# Or build the blocks then write
from rmfiles.generate import build_rectangle_blocks, write_rm
blocks, author_uuid = build_rectangle_blocks(x=120, y=140, width=160, height=100)
write_rm("output/rect2.rm", blocks, version="3.1")
To inspect or transform existing notebooks, you can load them into the high-level turtle API:
from rmfiles import RemarkableNotebook, scene_to_svg
nb = RemarkableNotebook.from_file("fixtures/extracted_rm_file.rm")
scene_to_svg(nb, "from-existing.svg")
Filled primitives support tweaks for coverage. For example, a denser rectangle fill with a cross-hatch pass:
nb = RemarkableNotebook(deg=True)
nb.layer("Sketch").tool(pen=SAMPLE_TOOL, width=SAMPLE_LINE_WIDTH)
nb.filled_rect(60, 320, 180, 110, spacing_factor=0.25, cross_hatch=True)
Polygons can also be filled with the scanline approach:
nb.filled_polygon(
[
(80, 320),
(200, 300),
(240, 360),
(200, 420),
(80, 400),
],
spacing_factor=0.25,
cross_hatch=True,
edge_outline=True,
)
These helpers assemble a minimal, device-like block sequence (author IDs,
migration and page info, scene tree, layer + stroke) using rmscene
and write
with a compatible version string. Coordinates are in pixels (typical page
dimensions 1404×1872). For visibility, strokes use a marker tool and thicker
width than the default.
Note: writing relies on the rmscene
package (installed via setup.py
). If it’s
not available, rmfiles new
will fail with a clear message.
- See the org-mode quickstart: docs/quickstart.org
- Run the primitives + transforms demo:
python examples/primitives_demo.py --out output/primitives_demo.rm
For quick spelunking into the raw rmscene
structures, use the
lab_rm_reader.py
script. It loads sample-files/Extracted_RM_file.rm
into a SceneTree
and prints a readable tree that highlights groups,
CRDT sequence items, and stroke points. Activate the local virtualenv
first to ensure the rmscene
dependency is available:
source .venv/bin/activate && python lab_rm_reader.py
This is a diagnostic helper only; it lives outside the packaged API to keep experimentation frictionless.
The packaged API also exposes rmfiles.scene_to_json()
, a helper that
emits a JSON representation of any SceneTree
or rmscene
object. It is
useful when you need structured data for logging, snapshotting, or quick
diffs without relying on the ad-hoc text walker.
Use rmfiles.scene_to_svg()
to turn notebook structures into SVG files.
It accepts a RemarkableNotebook
, a block list, a SceneTree
, or a path
to a .rm
file. Layers are mapped to <g>
groups, strokes become SVG
paths, and text highlights render as translucent rectangles.
from rmfiles import RemarkableNotebook, scene_to_svg
nb = RemarkableNotebook(deg=True)
nb.layer("Sketch").line(0, 0, 150, 80)
scene_to_svg(nb, "out.svg", background="#ffffff")
Hidden layers are skipped by default; pass
include_hidden_layers=True
to keep them in the output (they are tagged
with display:none
so they remain hidden until toggled by a viewer).
Share screenshots or exported artifacts in the git-ignored tmp/
directory
so they stay out of commits (see ADR 0008).