New New native page templates for reMarkable. Explore all 87 templates.

The .rmtemplate File Format (v1)

This page specifies the .rmtemplate package format, for template designers and tools that want to produce files Klass-RM Uploader can upload. For how to upload one, see Custom Templates.

.rmtemplate is a Klass Concepts packaging format. It is not a reMarkable format, and reMarkable does not read .rmtemplate files directly. Klass-RM Uploader unpacks the package and sends its template to your reMarkable account as a native cloud template.


Container

A .rmtemplate file is a standard ZIP archive with the file extension .rmtemplate.

  • Entries may be stored (method 0) or DEFLATE-compressed (method 8). Other compression methods and encrypted entries are not supported.
  • Each entry may be at most 256 MB uncompressed.
  • Member names are matched exactly and are case-sensitive. Both members below must be at the archive root, not inside a folder. Zipping a folder with Finder puts the files one level down, which makes the package invalid.
  • Any other members are ignored.
Member Required Contents
template.json Yes The reMarkable template itself, in reMarkable's JSON template format.
manifest.json No Package information: a display name and a stable package identifier.

There is no separate icon or thumbnail file. The template picker icon is carried inside template.json (see below).


template.json

template.json is a reMarkable vector template (formatVersion 1), the same JSON format the tablet uses for its own templates. Its bytes are sent to your reMarkable account exactly as they appear in the package; Klass-RM Uploader never rewrites or reformats them.

Klass-RM Uploader checks only the following before uploading. Anything beyond this is up to the tablet.

  • The file must be valid JSON, and its top level must be an object.
  • name must be present and must be a string.
  • items must be present. This is the template's drawing content.

A package that fails these checks is rejected with an error rather than uploaded. Fields worth getting right for the tablet:

  • categories - a list of template picker tabs. Include at least one (for example "All"). A template with an empty list syncs to the account but does not appear in any picker tab.
  • iconData - the picker icon, as a base64-encoded SVG.
  • orientation - "portrait" or "landscape".
  • formatVersion (write 1), author, and labels (a list, may be empty).

template.json authoring basics

reMarkable has not published a specification for its template format. This section is a practical introduction based on our own testing on reMarkable tablets. It covers enough to build useful templates, and it may not match every firmware version. When in doubt, test on your device.

Top-level fields

Field Type Notes
formatVersionnumberAlways 1.
namestringPicker name (unless manifest.json overrides it).
authorstringYour name or company.
templateVersionstringYour own version number, such as "1.0.0".
orientationstring"portrait" or "landscape".
categorieslist of stringsPicker tabs. Use at least one; "All" is a safe choice.
labelslist of stringsOptional tags. May be empty.
iconDatastringBase64-encoded SVG shown in the picker. Use a 150 x 200 canvas for portrait, 200 x 150 for landscape. Simple black-and-white line art reads best.
constantslistOptional named values. See below.
itemslistWhat gets drawn. See below.

Coordinates and page size

The origin is the top-left corner of the page, and y increases downward. Units are page pixels. Instead of hard-coding a page size, use the variables templateWidth and templateHeight, which the tablet fills in when it draws the page. Portrait sizes we have seen:

  • reMarkable 2: 1404 x 1872
  • reMarkable Paper Pro: 1620 x 2160
  • reMarkable Paper Pro Move: 820 x 1458

A template written against templateWidth and templateHeight adapts to every device. One built from fixed numbers for a reMarkable 2 will look wrong on the others.

Numbers and expressions

Any coordinate, size, repeat count, or visible value can be a plain number or a string containing an expression:

  • Arithmetic with + - * / and parentheses: "templateWidth - margin * 2"
  • Comparisons, &&, ||, and the conditional condition ? a : b: "templateWidth > 1000 ? 120 : 60"
  • Names: the page variables above, your constants, and inside a group, parentWidth and parentHeight

Constants

constants is a list of objects with one key each, not a single object. Each one can use the page variables and any constant defined above it:

"constants": [
  { "margin": 100 },
  { "lineSpacing": 64 },
  { "contentWidth": "templateWidth - margin * 2" }
]

Items

There are three item types: group, path, and text. Any item can have an id (a label for your own reference) and a visible value; an expression that evaluates to 0 hides the item.

group positions and repeats other items.

  • boundingBox: { "x", "y", "width", "height" }. Children are positioned relative to the box's top-left corner, and can use parentWidth/parentHeight for its size.
  • children: a list of items, including other groups.
  • repeat (optional): { "rows": ..., "columns": ... }, either or both. A number repeats that many times. "down" (rows) or "infinite" (rows or columns) repeats until the page, or the enclosing group, is filled. Each row steps down by the box's height; each column steps right by its width.

path draws lines and shapes.

  • data: a flat list of commands and coordinates, like SVG path data split into list entries: "M", x, y (move), "L", x, y (line), "C", x1, y1, x2, y2, x, y (curve), and "Z" (close the shape). Coordinates may be expressions.
  • strokeWidth: line thickness. Leaving it out gives a very fine line; 1 and 2 are typical.
  • strokeColor and fillColor: "#RRGGBB". Colors show in color on color devices and as gray on the reMarkable 2. A closed path with a fillColor draws a filled shape.

text draws a single line of text.

  • text: the string. fontSize: size in page pixels (reMarkable's own templates use 22). bold and italic: optional true.
  • position: { "x", "y" }, relative to the enclosing group. y is the text baseline.
  • In position.x, textWidth is the width of the text itself, which is how you align it: "parentWidth - textWidth" right-aligns, "(parentWidth - textWidth) / 2" centers.

Tips

  • Go heavier than looks right on a monitor. E-ink washes out thin lines and light grays. Use strokeWidth 2 for anything that should stand out, and dark colors.
  • Rotation is not supported. Draw angled lines with explicit coordinates.
  • Supporting the Paper Pro Move. Its page is much narrower. Either build everything from templateWidth, or define a constant such as { "compact": "templateWidth < 1000 ? 1 : 0" } and use visible to switch between two layouts.
  • Draw a checkbox as a closed path: ["M",0,0,"L",24,0,"L",24,24,"L",0,24,"Z"].

Complete example: a lined notes page

A bold heading, a date label, a heavy rule under them, and ruled lines to the bottom of the page. It adapts to each device's page width.

{
  "formatVersion": 1,
  "name": "Lined Notes",
  "author": "Example Co.",
  "templateVersion": "1.0.0",
  "orientation": "portrait",
  "categories": ["All"],
  "labels": [],
  "iconData": "PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNTAiIGhlaWdodD0iMjAwIiB2aWV3Qm94PSIwIDAgMTUwIDIwMCI+PHJlY3QgeD0iMSIgeT0iMSIgd2lkdGg9IjE0OCIgaGVpZ2h0PSIxOTgiIGZpbGw9IndoaXRlIiBzdHJva2U9ImJsYWNrIiBzdHJva2Utd2lkdGg9IjIiLz48cGF0aCBkPSJNMjAgMzBIOTBNMjAgNTBIMTMwTTIwIDcwSDEzME0yMCA5MEgxMzBNMjAgMTEwSDEzME0yMCAxMzBIMTMwTTIwIDE1MEgxMzBNMjAgMTcwSDEzMCIgc3Ryb2tlPSJibGFjayIgc3Ryb2tlLXdpZHRoPSIzIi8+PC9zdmc+Cg==",
  "constants": [
    { "margin": 100 },
    { "lineSpacing": 64 },
    { "contentWidth": "templateWidth - margin * 2" }
  ],
  "items": [
    {
      "id": "title",
      "type": "text",
      "text": "Notes",
      "fontSize": 22,
      "bold": true,
      "position": { "x": "margin", "y": 150 }
    },
    {
      "id": "date",
      "type": "text",
      "text": "Date:",
      "fontSize": 22,
      "position": { "x": "templateWidth - margin - 240", "y": 150 }
    },
    {
      "id": "header-rule",
      "type": "path",
      "strokeWidth": 2,
      "data": ["M", "margin", 180, "L", "templateWidth - margin", 180]
    },
    {
      "id": "lines",
      "type": "group",
      "boundingBox": {
        "x": "margin",
        "y": "180 + lineSpacing",
        "width": "contentWidth",
        "height": "lineSpacing"
      },
      "repeat": { "rows": "down" },
      "children": [
        {
          "type": "path",
          "strokeWidth": 1,
          "data": ["M", 0, 0, "L", "parentWidth", 0]
        }
      ]
    }
  ]
}

manifest.json

manifest.json is optional, and reading it never fails an upload. If it is missing, is not valid JSON, or lacks a field, that field is simply treated as absent. Unknown fields are ignored, so tools may add their own.

Field Type Meaning
name string The name shown in the tablet's template picker. Overrides template.json's name.
packageId string A stable identifier for this template across revisions. See "Updating a template" below.
packageVersion number The package format version. Write 1. Currently informational.

Display name

The name shown on the tablet is the first non-blank value of, in order: manifest.json name, template.json name, the uploaded file's name without its extension, and finally Custom Template. Leading and trailing whitespace is trimmed.

Updating a template (packageId)

Without a packageId, every upload creates a new template, so uploading a revised file puts a second entry with the same name in the picker.

With a packageId, the template's identity on the reMarkable account is derived from it, so uploading a later revision with the same packageId replaces the earlier one in place.

  • The value is trimmed and lowercased before use, so " Acme-Dot-Grid " and "acme-dot-grid" identify the same package.
  • Choose something globally unique and permanent, such as a reverse-domain name: com.example.dot-grid. Two different templates that share a packageId will overwrite each other.
  • An empty or non-string value is treated as absent.

Example

Archive layout:

dot-grid.rmtemplate
  template.json
  manifest.json

manifest.json:

{
  "packageVersion": 1,
  "packageId": "com.example.dot-grid",
  "name": "Dot Grid"
}

Building the archive from a terminal, from inside the folder that holds the two files (so they land at the archive root):

zip -X dot-grid.rmtemplate template.json manifest.json

What happens on upload

Klass-RM Uploader creates a template document on your reMarkable account containing the package's template.json and the display name. The tablet downloads it on its next sync. For it to be selectable, the account needs reMarkable Connect with Methods, and the tablet needs reMarkable software 3.17 or newer. See Custom Templates for details.