# Map sub-spec — The tileset container Normative refinement of [SPEC §4](../SPEC.md). Reference: `map-schema::{Directory, DirEntry}`. A **tileset** is one addressable blob on dumb storage (object store, static host, OPFS) — the "it's just a file" deliverable. It has three parts. ## 1. Header A fixed prefix carrying a magic tag, the standard version, the datum, the `AltSchedule`, and the byte offset of the directory. A reader fetches the header (a small fixed range) first. ## 2. Directory An ordered table of `DirEntry { key: CellKey, offset: u64, len: u64, content_id }`. - It **MUST** be sorted by the canonical `CellKey` order (S2/Hilbert first), so the tiles of one viewport occupy a near-contiguous byte range. - A reader computes the cell keys a viewport needs, looks each up (`Directory::locate`, binary search), and coalesces the results into the minimal set of byte ranges (`Directory::ranges_for`) to fetch over HTTP range requests — no server-side logic, no per-request billing. - The Merkle leaf for each entry commits to `(key, content_id)` **only**, not the byte offset. Re-laying-out the file (compaction, re-ordering payloads) therefore does **not** change the directory root the manifest signs (SPEC §5). ## 3. Payloads Content-addressable, independently decodable tile bodies. A reader **MUST** verify that each fetched payload hashes to the `content_id` the directory claims, and **MUST NOT** be required to download the whole tileset to render a viewport. ## Range-request planner `Directory::ranges_for(viewport_cells)` returns coalesced `(start, end)` spans. Because the directory is Hilbert-sorted, a contiguous viewport collapses to one or a few spans rather than one request per tile — the Protomaps insight, preserved. Conformance suite **C2** pins this against the sample tileset in [`../conformance/v1/tileset_vectors.json`](../conformance/v1/tileset_vectors.json).