TickMark

Folder ZIP metadata

A whole folder, ready to travel.

A TickMark folder export is an ordinary ZIP: a small JSON manifest describes the tree, and each climb is a viewable PNG that keeps its editable data. The same format works in TickMark and TickMark Lite.

folder ZIP v1compatible ≥ v1UTF-8 JSONZIP · PNG

Overview

The root file tickmark-folder.json is the archive contract. It lists folders, including empty ones, and photos using archive-local IDs and paths. Grade, hold rules and outlines stay with each photo, rather than being duplicated in the folder manifest.

There are two separate public formats: photo route data v3 inside each PNG, and tickmark-folder v1 for the ZIP structure. Their version numbers are independent of each other and of the app release.

ZIP layout

tickmark-folder.json
North wall/
North wall/Projects/
North wall/Blue traverse.png

The writer puts the manifest first, then emits directory entries and PNGs. An importer reads the ZIP central directory rather than relying on entry order. Directory entries preserve empty folders when the ZIP is opened with other tools; TickMark reconstructs folders from the manifest even when those directory entries are absent.

TickMark writes stored (method 0) entries because PNGs are already compressed. Its reader also accepts deflate (method 8). Names are UTF-8. It does not support ZIP64, multipart ZIPs or encryption.

Example manifest

Here, Projects is an empty folder and Blue traverse is a climb in North wall. Download the example JSON. This JSON alone is not an importable archive: the listed PNG must also be present with its editable project package.

{
  "format": "tickmark-folder",
  "version": 1,
  "compatible": 1,
  "app": "TickMark",
  "folders": [
    {
      "id": "f1",
      "parentId": null,
      "name": "North wall",
      "path": "North wall/"
    },
    {
      "id": "f2",
      "parentId": "f1",
      "name": "Projects",
      "path": "North wall/Projects/"
    }
  ],
  "photos": [
    {
      "id": "p3",
      "parentId": "f1",
      "name": "Blue traverse",
      "path": "North wall/Blue traverse.png"
    }
  ]
}

Inspect an export

unzip -p 'North wall.zip' tickmark-folder.json | jq .

This command inspects the manifest only. It does not validate the whole archive or make an untrusted ZIP safe to extract.

Manifest fields

FieldType and meaning
formatRequired string, exactly tickmark-folder.
versionRequired positive integer. The current writer emits 1.
compatiblePositive integer: oldest reader version that can import it. Current writer emits 1; readers use version if omitted.
appInformational string, emitted as TickMark by both variants. Not a product restriction; missing or non-string values fall back to TickMark.
foldersRequired array of folder records. May be empty.
photosRequired array of photo records. May be empty. At least one folder or photo is required overall.

Unknown extra fields are ignored. IDs and paths, not array indices, define relationships. IDs are unique across both arrays; an ID is not a stable identifier across exports or imports.

Folders and photos

Both record types have the same four required fields:

FieldType and meaning
idString of 1–32 ASCII letters, digits, underscores or hyphens. The writer uses f1, p2, etc.; readers do not require those prefixes.
parentIdA folder ID, or null for the archive root. It cannot reference a photo.
nameOriginal gallery display name, 1–80 characters after trimming, with no control characters. It may differ from the filesystem name.
pathRelative ZIP path. Folders end in /; photos end in .png (case-insensitive on import). Each item sits exactly one level below its parent's path.

For example, a photo under f1 with path North wall/ must have a path such as North wall/Blue traverse.png. Parent IDs must exist, the tree must be acyclic, and paths must be unique under case-insensitive NFC comparison.

Photo metadata and re-editing

Each photo is freshly rendered from its editable project. A PNG contains three layers of information:

LayerPurpose
Rendered pixelsA marked-up climb any image viewer can display.
tickmark:Data XMPThe public photo route schema: name, grade, styles, rules, hold outlines and markers.
tkPj PNG chunkTickMark's private editable project package (tickmark-project, currently version 1 / compatible 1): clean source photo, masks and editable state.
Keep the original PNG bytesTickMark requires a valid editable project package to import a photo from a folder ZIP. A plain PNG, even one containing route XMP, is not enough. Re-encoding the image may strip the package; readers that only inspect the archive should preserve it unchanged. The private package is separate from the public route API.

Names and paths

The writer normalises path names to NFC, replaces control and filesystem-reserved characters with underscores, collapses whitespace, trims trailing dots and spaces, and limits each segment to 80 Unicode characters. Empty names become Untitled; Windows device names get an underscore. Sibling collisions receive (2), (3) and so on, before a photo's .png suffix. The original display name remains in name.

Never extract paths blindly. TickMark rejects absolute paths, drive letters, backslashes, control characters, empty segments, . and .., and paths that disagree with their parent folder.

Versioning

Use format to identify the data family. version identifies the writer's schema; compatible is the minimum reader version. A reader supporting v1 accepts an archive whose compatible is at most 1, even if the writer's version is higher. If compatible is absent, use version.

Import behaviour

Add → From Files imports the archive under the current gallery folder. TickMark validates and stages everything before committing a single gallery change. An error or cancellation adds nothing. The final atomic commit cannot be cancelled.

Every imported item gets a fresh gallery ID. Existing names are kept, with (2) suffixes on collisions rather than overwriting anything. Photo-library asset IDs are never transferred; the next Done creates a new library copy. A ZIP without the TickMark manifest is refused with instructions to unzip it and choose the photos instead.

Limits and validation

These are current TickMark import limits, not guarantees of what every ZIP reader supports.

LimitValue
Archive / total unpacked bytes2,000,000,000 / 3,000,000,000
One unpacked entry96 MiB (100,663,296 bytes)
ZIP entries2,100
Folders / photos1,000 each
Folder depth32
Manifest2 MiB (2,097,152 bytes)
ZIP entry path1,024 UTF-8 bytes
Decoded image dimensionsAt most 8,192 per axis and 16,777,216 pixels
Editable areas per photo300

The reader checks central-directory and local-header consistency, CRC-32, declared decompressed sizes, and data bounds. It rejects duplicate normalised paths, unlisted files or directory entries, symlinks, special files, unsupported compression, corrupt packages and unsafe geometry. __MACOSX/ entries and files named .DS_Store are ignored. Every listed photo must exist; empty folders need no photo. Free-space checks reserve about twice the unpacked bytes plus 200 MB.

Changelog

VersionChanges
v1Initial folder manifest: nested and empty folders, archive-local IDs, editable PNG photos, and explicit compatibility.

Questions about reading TickMark data? support@baguette-studios.dev