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.
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
| Field | Type and meaning |
|---|---|
format | Required string, exactly tickmark-folder. |
version | Required positive integer. The current writer emits 1. |
compatible | Positive integer: oldest reader version that can import it. Current writer emits 1; readers use version if omitted. |
app | Informational string, emitted as TickMark by both variants. Not a product restriction; missing or non-string values fall back to TickMark. |
folders | Required array of folder records. May be empty. |
photos | Required 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:
| Field | Type and meaning |
|---|---|
id | String of 1–32 ASCII letters, digits, underscores or hyphens. The writer uses f1, p2, etc.; readers do not require those prefixes. |
parentId | A folder ID, or null for the archive root. It cannot reference a photo. |
name | Original gallery display name, 1–80 characters after trimming, with no control characters. It may differ from the filesystem name. |
path | Relative 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:
| Layer | Purpose |
|---|---|
| Rendered pixels | A marked-up climb any image viewer can display. |
tickmark:Data XMP | The public photo route schema: name, grade, styles, rules, hold outlines and markers. |
tkPj PNG chunk | TickMark's private editable project package (tickmark-project, currently version 1 / compatible 1): clean source photo, masks and editable state. |
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.
- Additive, backward-compatible changes raise
versiononly. - Breaking changes raise
compatibleas well. - A newer compatibility requirement is refused with an update message, rather than partially imported.
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.
| Limit | Value |
|---|---|
| Archive / total unpacked bytes | 2,000,000,000 / 3,000,000,000 |
| One unpacked entry | 96 MiB (100,663,296 bytes) |
| ZIP entries | 2,100 |
| Folders / photos | 1,000 each |
| Folder depth | 32 |
| Manifest | 2 MiB (2,097,152 bytes) |
| ZIP entry path | 1,024 UTF-8 bytes |
| Decoded image dimensions | At most 8,192 per axis and 16,777,216 pixels |
| Editable areas per photo | 300 |
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
| Version | Changes |
|---|---|
| v1 | Initial folder manifest: nested and empty folders, archive-local IDs, editable PNG photos, and explicit compatibility. |
Questions about reading TickMark data? support@baguette-studios.dev