Skip to content

Container

A .hoop file is a standard ZIP archive (PKZIP). No custom header, no wrapper, no magic bytes beyond ZIP’s own. Any ZIP tool can list and extract one; renaming a .hoop to .zip is a supported way to look inside.

Writers:

  • MUST use only compression method 0 (stored) or 8 (deflate).
  • MUST NOT use encryption, spanning or multi-disk archives, or ZIP64. Project files stay well below 4 GB; a writer that would need ZIP64 has a bug upstream of the container.
  • SHOULD write manifest.json as the first entry, so a reader can decide whether it understands the file before inflating anything else.
  • SHOULD deflate JSON entries and store already-compressed payloads (JPEG, PNG, HEIC). Deflating a JPEG costs time and gains nothing.

Readers MUST reject archives using any other method or feature rather than attempting a partial read. See Reader requirements for the limits that go with this.

Design.hoop
├── manifest.json REQUIRED format version, checksums, entry roles
├── document.json REQUIRED the editable project (source of truth)
├── plan.json optional derived stitch list
├── preview.png optional 512 px render of the design
└── references/ optional original trace-image bytes
└── <uuid>.<jpg|png|heic|img>

Only manifest.json and document.json are required. Everything else may be absent, and a reader MUST cope with its absence rather than assuming a default file.

Format version, provenance, and one record per entry with a SHA-256 checksum. Described in full under manifest.json.

The editable project: hoop size, palette, objects in stitch order, per-object parameters, settings. The single source of truth — see document.json.

The derived stitch list in millimetres, machine-neutral. Present in exported files; commonly absent in an application’s own library saves, which carry the document and preview only. See plan.json.

A rendered image of the design, nominally 512 px on its long edge, with transparency where there are no stitches. Intended for galleries and file pickers so they can show a project without inflating or interpreting anything else. It is derived and disposable.

The original bytes of trace images the design was drawn over, one entry per image, named by the image’s UUID with its original extension. The metadata for each image — placement, scale, opacity — lives in document.json; this directory holds only the pixels.

Writers match a metadata record to its bytes by the lowercased UUID prefix of the entry name. A reader that finds metadata without matching bytes SHOULD keep the project and drop the image, not fail the load.

Entry names are UTF-8, use / as the separator, and are relative. Readers MUST reject any archive containing an entry whose name:

  • contains a .. path component,
  • begins with / or a drive letter,
  • contains a NUL byte.

This applies to files your own application wrote. A .hoop arriving from a share sheet, a download or a sync folder is untrusted input in every case.

There is no compression of the archive as a whole, no delta encoding between saves, and no index beyond ZIP’s own central directory. A .hoop file is meant to be openable in twenty years by someone with a ZIP library and this page.