tileflow 0.1.0-alpha.1 → 0.1.0-alpha.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,205 +1,110 @@
1
1
  # tileflow
2
2
 
3
- CLI-only tools for Tileflow config, preview, validation, capture, and hosted deploy. The package
4
- requires Node.js 22 or newer and intentionally exposes only the `tileflow` binary; importing
5
- `tileflow` as a JavaScript library is not a supported surface.
3
+ The Tileflow command-line interface: author, validate, preview, build, capture, and deploy maps.
4
+ This package exposes the `tileflow` executable only. Do not import `tileflow` as a JavaScript library;
5
+ use `@tileflow/core` or the relevant integration package instead.
6
6
 
7
- Local config, validation, build, preview, and hosted-compatibility checks require
8
- no Tileflow account or API key:
7
+ > Related packages and guides: [documentation index](https://raw.githubusercontent.com/tileflow/tileflow-sdk/main/llms.txt).
8
+
9
+ ## Install
10
+
11
+ Use Node.js 22 or newer. Install the CLI in your project and commit the lockfile:
9
12
 
10
13
  ```sh
11
14
  npm install @tileflow/core@alpha @tileflow/maps@alpha
12
15
  npm install --save-dev --save-exact tileflow@alpha
13
16
  npx tileflow init
14
17
  npx tileflow validate
15
- npx tileflow validate --target hosted
16
- npx tileflow build
17
18
  npx tileflow preview
18
19
  ```
19
20
 
20
- The generated config imports `streets`, extends it, materializes a custom dark theme from
21
- `streetsThemes.dark`, and declares the starter's theme family, modules, and view. Streets already
22
- owns its complete icon and glyph providers, so the leaf does not repeat font stacks or know a
23
- delivery URL.
24
-
25
- Install the exact project dependency first; then `npx tileflow` runs its local executable. Other
26
- package managers work; use the equivalent command for the lockfile already owned by the project.
27
-
28
- `tileflow preview` previews the map exported by `tileflow.config.ts` and uses its configured `view`.
29
- Select one of that map's committed standalone scenes explicitly:
30
-
31
- ```sh
32
- npx tileflow preview --scene madrid-mobile
33
- ```
34
-
35
- To work on another map, point `--config` at another singular config. Multi-map catalogs are internal
36
- orchestration used by this repository's workbench and are not a second public config shape.
37
-
38
- `tileflow dev` remains a compatibility alias. The `preview` name distinguishes this SDK preview
39
- server from an application's own `npm run dev` process.
21
+ Run these commands from the project directory. After installation, `npx tileflow` uses the local
22
+ executable. With another package manager, use its local-execution command and the existing lockfile;
23
+ do not add a second lockfile or rely on a globally installed CLI.
40
24
 
41
- `--api-base-url` selects the origin used by official World, Bathymetry vector, Bathymetry DEM,
42
- Nautical, and terrain TileJSON sources in the generated preview style. In particular, a hybrid
43
- Bathymetry map resolves `/tiles/bathymetry/tiles.json` and `/tiles/bathymetry/dem/tiles.json` from
44
- that one origin. `TILEFLOW_API_URL` supplies the same value when the flag is omitted, which lets a
45
- local tiles stack serve all sidecars without changing map authoring.
25
+ `init` creates a singular `tileflow.config.ts` extending the official Streets map. `preview` serves
26
+ the exported map using its configured view; it does not replace an application's normal development
27
+ server.
46
28
 
47
- The preview binds only `127.0.0.1` by default. Network exposure is never implicit. To bind another
48
- interface, pass one explicit IP literal (or `localhost`) with `--host`, for example
49
- `tileflow preview --host 192.0.2.10`. URL-, path-, and hostname-shaped values are rejected.
29
+ Local validation, compilation, and asset preparation require no account or API key. Preview and
30
+ capture may fetch configured remote tiles and fonts. Config files are executable trusted code,
31
+ not a sandbox; review their imports before running them.
50
32
 
51
- A map preview accepts `--theme <concrete-name>`; omission selects its declared default. A scene
52
- preview applies its committed concrete theme, camera, and CSS viewport dimensions. Capture remains the
53
- authority for exact DPR and pixels. Scenes whose target is an application must be viewed through
54
- that application's normal development server.
55
-
56
- ## Build artifacts
57
-
58
- `tileflow build` resolves the exported map lineage, validates executable config and MapLibre
59
- semantics, compiles its ordered package/local icon directories and selected text provider, and
60
- writes `manifest.json`, one `styles/<map>/<theme>.json` per concrete appearance, and every referenced
61
- sprite/font asset. The manifest records `defaultTheme`, optional `systemThemes`, and the exact theme
62
- catalog; it never flattens a default into a second style alias. A
63
- map with text has exactly one provider: local/package `fonts` directories or a `glyphs` descriptor
64
- whose `fontStacks` are explicit. The default output is `dist/tileflow`; choose another directory
65
- explicitly with `--out`:
33
+ ## Validate and build
66
34
 
67
35
  ```sh
36
+ npx tileflow validate --json
37
+ npx tileflow validate --target hosted --json
68
38
  npx tileflow build --out public/tileflow
69
39
  ```
70
40
 
71
- Named hosted sources with `local` archives are for account-free validation, development, preview,
72
- and capture. `tileflow build` rejects them instead of copying, publishing, or taking ownership of
73
- user data. For production, either publish managed data explicitly with `tileset publish` or serve
74
- it from infrastructure owned by the application. A local declaration never selects either path
75
- implicitly.
41
+ The default build directory is `dist/tileflow`. A build writes a runtime manifest, concrete-theme
42
+ styles, and referenced prepared sprite/font assets. Serve the complete output, not just a style
43
+ file. A framework component defaults to `/tileflow/manifest.json`; set its `manifestUrl` explicitly
44
+ when your application's public path differs.
76
45
 
77
- Preview, capture, and the React/Vue/Svelte adapters register Tileflow's local PMTiles protocol
78
- before MapLibre reads the compiled Style. Its URL is stable by logical tileset ID; physical local
79
- snapshot generations do not change Style identity. Standalone Capture retains one snapshot for the
80
- render. Application Capture uses the application's server; Tileflow's local handler provides
81
- immutable, ETag-guarded PMTiles reads, but does not freeze every local dataset for the complete
82
- screenshot window.
46
+ `build` is local. Hosted compatibility is a separate preflight: hosted deployment requires Tileflow
47
+ World and currently rejects local/package font bundles. Production builds reject unresolved local
48
+ PMTiles inputs rather than silently copying or publishing user datasets. Publish managed data
49
+ explicitly or supply an application-owned production source.
83
50
 
84
- Build is local and credential-free. Hosted compatibility is a separate
85
- `tileflow validate --target hosted` preflight. Primary map data must remain Tileflow World; named
86
- Team sources are validated and resolved independently.
51
+ To work on another map, use `--config <path>`. An ordinary config exports one map. Multi-map
52
+ workspaces are advanced repository orchestration, not a second application authoring model.
87
53
 
88
- ## Deterministic agent diagnostics
54
+ ## Discover the language and inspect a change
89
55
 
90
- Use JSON mode when an agent or CI job needs to validate or reason about the resolved config:
56
+ Agents should read generated contracts instead of guessing property names, expression syntax, or
57
+ compiler-generated layer IDs:
91
58
 
92
59
  ```sh
93
- npx tileflow validate --json
94
- npx tileflow inspect --json
95
- npx tileflow inspect --map madrid --json
96
60
  npx tileflow language manifest --json
97
61
  npx tileflow language schema --json
98
- npx tileflow explain --map madrid --theme dark --json
62
+ npx tileflow inspect --json
63
+ npx tileflow explain --theme dark --json
99
64
  npx tileflow semantic-diff --from-config before/tileflow.config.ts --to-config after/tileflow.config.ts --json
100
- npx tileflow semantic-diff --config maps.workspace.ts --from before --to after --json
101
- ```
102
-
103
- `validate`, `inspect`, `explain`, and `semantic-diff` success writes exactly one
104
- schema-version-1 command envelope to stdout. The two discovery commands intentionally return their
105
- contracts raw instead of wrapping them: `language manifest --json` emits authoring-manifest version
106
- 2 and `language schema --json` emits config-reference version 4. Every JSON-mode failure, including
107
- failure to load either raw discovery contract, leaves stdout empty and writes one schema-version-1
108
- command failure to stderr. Command summaries and every failure diagnostic contain `phase`, `code`,
109
- `path`, `severity`, `message`, and a bounded safe `suggestion`; diagnostics are sorted and
110
- deduplicated deterministically.
111
-
112
- Config inspection returns the resolved map, parent-to-leaf lineage, declared paths, leaf-level merge
113
- provenance, and an explicit `themeContract`: default/system selection, shared token schema,
114
- concrete values, typography, lighting, differences from the default, and stable audit diagnostics.
115
- It omits the executable input-file graph and sanitizes credentials, URL queries,
116
- secret-shaped values, data URLs, and absolute filesystem paths. The generated
117
- [`modules-api-reference.json`](../../docs/modules-api-reference.json) is the machine-readable
118
- map/module schema; its default `authoring` entrypoint tells an agent how to write the singular
119
- config with `extends` and `scenes`, while its named `resolved` entrypoint matches inspection and
120
- compiler input. Both are produced from executable core schemas rather than a handwritten parallel
121
- API list.
122
-
123
- `tileflow language manifest --json` discovers the complete closed semantic language without loading
124
- a project: compiler identity, domains and their dependencies, public operations, expression-builder
125
- signatures and limits, render selectors, semantic fields/features, diagnostics, reports, commands,
126
- and schema references. `tileflow language schema --json` returns the packaged generated JSON Schema
127
- that those references address. Together they are the canonical bootstrap surface for an authoring
128
- agent; neither command writes files or accesses the network.
129
-
130
- Each manifest command entry declares its `outputKind`, `outputVersion`, and stable
131
- `outputSchemaRef`. `raw-authoring-manifest` and `raw-config-reference` identify the two bootstrap
132
- documents above; `command-envelope` identifies the ordinary version-1 CLI contract.
133
-
134
- `tileflow explain` compiles exactly one map/theme selection through `createStyleResult()` and emits
135
- its structured `report` and safe compiler `diagnostics`; it deliberately omits the usually large
136
- MapLibre `style`. In a singular config, `--map` is optional; a multi-map workbench requires it.
137
- `--theme` defaults to that map's declared default. `--inspection` adds opt-in, read-only
138
- physical-output provenance to the report. Its physical layer IDs and indexes are diagnostic
139
- observations only: they are not stable application or authoring targets, and no semantic operation
140
- accepts them. The JSON document has this stable projection:
141
-
142
- ```json
143
- {
144
- "schemaVersion": 1,
145
- "command": "explain",
146
- "ok": true,
147
- "selection": {"map": "madrid", "theme": "dark"},
148
- "authoringManifestSchemaVersion": 2,
149
- "compilation": {"ok": true, "diagnostics": [], "report": {}},
150
- "diagnostics": []
151
- }
152
65
  ```
153
66
 
154
- `tileflow semantic-diff --from-config <path> --to-config <path>` compares the sole map exported by
155
- each ordinary config, which is the normal agent workflow for reviewing a change across two files or
156
- checkouts. If either endpoint is a multi-map `*.workspace.ts`, select that endpoint explicitly with
157
- `--from-map` or `--to-map`; selectors are rejected for singular configs. The existing
158
- `--config <workspace> --from <map> --to <map>` form remains as the same-workspace shortcut. Paired
159
- config options and workspace options cannot be mixed.
67
+ The language commands need no project and perform no network access. `language manifest` returns
68
+ the raw authoring manifest (schema version 2); `language schema` returns the raw generated config
69
+ reference (version 4). Use their versions and schema references when consuming the output.
160
70
 
161
- The successful document adds `diff`, whose exact core shape is `{schemaVersion, from, to, summary,
162
- changes}`; each change is `add`, `remove`, or `change` at an RFC 6901 JSON Pointer. Differences are
163
- informational, so a non-empty diff still exits successfully. Selection, load, validation, asset, or
164
- compilation failures leave stdout empty and emit one safe structured document on stderr.
71
+ `validate`, `inspect`, `explain`, and `semantic-diff` return one version-1 command envelope on
72
+ stdout. JSON-mode failures leave stdout empty, write one structured failure to stderr, and exit
73
+ nonzero. Diagnostics include `phase`, `code`, `path`, `severity`, `message`, and `suggestion`.
74
+ A non-empty semantic diff is informational, not a command failure.
165
75
 
166
- ## Command families
76
+ Inspection includes resolved inheritance, merge provenance, and the theme contract. `explain`
77
+ returns compilation diagnostics and a report, not the complete Style JSON. Add `--inspection` only
78
+ when physical output provenance is needed; those layer IDs are not stable authoring targets.
167
79
 
168
- | Family | Commands |
169
- | ----------------- | ---------------------------------------------------------------------------------------------- |
170
- | Semantic language | `language manifest`, `language schema` |
171
- | Map authoring | `init`, `validate`, `inspect`, `explain`, `semantic-diff`, `build`, `preview` (`dev` alias) |
172
- | Local evidence | `setup capture`, `capture`, `visual compare`, `visual analyze`, `visual diff`, `visual update` |
173
- | Data and assets | `tileset inspect`, `tileset publish/list/status/purge`, `inspect features`, `icons list/diff` |
174
- | Account | `login`, `logout`, `whoami` |
175
- | Hosted delivery | `deploy`, `status` |
80
+ For a normal config, map selection is implicit. Paired `--from-config` and `--to-config` compare
81
+ two ordinary configs. Workspace comparisons use their documented explicit map selectors; do not
82
+ mix the paired-config and same-workspace forms.
176
83
 
177
- Run `tileflow <command> --help` (or the family help, such as `tileflow icons --help`) for the exact
178
- arguments and bounded JSON modes.
84
+ ## Preview and compare
179
85
 
180
- The CLI retains the hidden `projects` command family as a compatibility and support surface for the
181
- internal application boundary. It is not part of the ordinary workflow or the product catalog.
86
+ `preview` binds to `127.0.0.1` by default. `--host` explicitly accepts an IP literal or `localhost`;
87
+ it does not implicitly expose a public listener. `--theme <name>` selects a concrete theme.
88
+ `--scene <name>` selects a committed standalone scene.
182
89
 
183
- ## Local visual feedback
184
-
185
- Explore with capture itself. The first run may install Playwright's exact pinned Chromium headless
186
- shell into its versioned per-user cache:
90
+ Compare two configs in the live workbench:
187
91
 
188
92
  ```sh
189
- npx tileflow capture \
190
- --map madrid \
191
- --theme dark \
192
- --center=-3.69201,40.40871 \
193
- --zoom=16.15 \
194
- --width=1200 \
195
- --height=1200 \
196
- --json
93
+ npx tileflow preview --config candidate/tileflow.config.ts --against-config reference/tileflow.config.ts
197
94
  ```
198
95
 
199
- The successful entry includes a normalized `definition` with its concrete `theme`, `camera`,
200
- `viewport`, and default map `target`. Copy it under a chosen `scenes.<name>` key; the CLI never rewrites
201
- executable TypeScript config. Then commit the bounded scene so agents and CI render the same map,
202
- camera, and viewport:
96
+ The workbench shares a camera across side-by-side, split, overlay, or blink views. Its inspector
97
+ shows bounded feature and compiler information; invalid edits keep the last valid generation.
98
+ Use headless capture, not the live viewport, when exact dimensions and device-pixel ratio matter.
99
+
100
+ `--api-base-url` or `TILEFLOW_API_URL` changes the API origin used by the official preview sources.
101
+ It does not change the map's authored data ownership or publish any data.
102
+
103
+ ## Capture a reproducible scene
104
+
105
+ Add a concrete-theme scene to `tileflow.config.ts`:
106
+
107
+ <!-- docs:check -->
203
108
 
204
109
  ```ts
205
110
  import {defineMap} from '@tileflow/core';
@@ -207,7 +112,6 @@ import {streets} from '@tileflow/maps';
207
112
 
208
113
  export default defineMap({
209
114
  id: 'madrid',
210
- name: 'Madrid',
211
115
  version: 1,
212
116
  extends: streets,
213
117
  scenes: {
@@ -216,542 +120,185 @@ export default defineMap({
216
120
  camera: {type: 'center', center: [-3.7038, 40.4168], zoom: 12},
217
121
  viewport: {width: 1280, height: 800, dpr: 1},
218
122
  },
219
- 'madrid-product': {
220
- theme: 'dark',
221
- camera: {type: 'center', center: [-3.7038, 40.4168], zoom: 12},
222
- viewport: {width: 390, height: 844, dpr: 2},
223
- target: {
224
- kind: 'application',
225
- path: '/maps/madrid',
226
- captureId: 'product-map',
227
- },
228
- },
229
123
  },
230
124
  });
231
125
  ```
232
126
 
233
- `scenes` is tooling metadata owned by this map. It is not inherited and does not enter the
234
- cartographic compiler; tooling supplies the exported map ID when it normalizes a scene internally.
235
- Every scene stores a concrete theme; omission and browser-only `system` are invalid.
236
-
237
- ### Live comparison workbench
238
-
239
- Use the ordinary preview server with a right-hand selection to compare two maps or themes while
240
- authoring:
241
-
242
- ```sh
243
- # Two maps or themes from one config.
244
- npx tileflow preview \
245
- --map harad --theme light \
246
- --against-map ferraris --against-theme light
247
-
248
- # Or compare against another config.
249
- npx tileflow preview \
250
- --config ./candidate.config.ts --map candidate \
251
- --against-config ./reference.config.ts --against-map reference
252
- ```
253
-
254
- Any `--against-*` option opens the comparison workbench. Both previews remain same-origin and share
255
- one synchronized camera. The toolbar switches between side-by-side, split, opacity overlay, and
256
- blink modes; the selected mode, camera, split, opacity, and active interaction side survive in the
257
- URL. Each config has its own watched, last-known-good session, so an invalid edit shows bounded
258
- diagnostics without discarding the last valid map and recovers automatically after a fix.
259
-
260
- Enable **Inspect** and click a rendered feature to see its bounded feature data, paint/layout values,
261
- zoom-curve samples, and compiler contribution sidecar. The sprite gallery shows the compiled atlas,
262
- not source directories. **Copy scene** produces a concrete-theme scene for the current camera and
263
- viewport; **Copy command** produces the corresponding capture command. The inspector sidecar exists
264
- only in memory in this local workbench and is not emitted by `tileflow build`.
265
-
266
- ### Reproducible two-style review
267
-
268
- For shareable evidence with exact pixels, use headless capture instead of the live preview:
269
-
270
- ```sh
271
- npx tileflow visual compare \
272
- --config ./candidate.config.ts --map candidate --theme light \
273
- --against-config ./reference.config.ts --against-map reference --against-theme light \
274
- --center=-3.7038,40.4168 --zooms=12,14,16 \
275
- --width=1200 --height=800 --dpr=1 --region=0,0,1200,760 \
276
- --diff --open --json
277
- ```
278
-
279
- `--against-config` is explicit and may name the same config. Both sides use one camera, viewport,
280
- DPR, ordered zoom matrix, pinned browser session, and concrete theme. At most 16 zooms and 64 MiB
281
- of aggregate embedded PNG data are accepted; an earlier preflight also caps the matrix at
282
- 67,108,864 aggregate physical pixels. The default transaction writes
283
- `.tileflow/comparisons/compare.html`, a machine-readable sibling JSON document, and PNG/receipt-v4
284
- pairs below `compare.assets`; `--diff` adds a highlighted diff when identities are comparable. The
285
- HTML embeds every image, uses a restrictive CSP, performs no network request, and offers the same
286
- side-by-side, wipe, overlay, and blink review modes.
287
-
288
- `--region=x,y,width,height` selects one shared physical-pixel rectangle for compact appearance
289
- profiles. Review JSON uses the explicit signed direction `rightMinusLeft`; the region does not crop
290
- captures, changed-pixel metrics, or diffs.
291
-
292
- Stdout and the sibling JSON use the same schema-version-1 `visual.compare` document: concrete
293
- left/right selections, shared camera and viewport, zoom-sorted rows with Review v1 documents and
294
- relative artifact paths, report/document paths, and sorted warnings. This document and the watch
295
- NDJSON described below are versioned compatibility boundaries.
296
-
297
- The asset directory also contains a bounded schema-version-1
298
- `.tileflow-visual-compare.json` inventory. It assigns ownership only to the listed sibling assets
299
- and records each exact SHA-256. A later successful transaction removes stale generated rows or
300
- diffs only when that valid prior inventory names them, preserves unrelated files, and refuses a
301
- managed asset that has been modified, replaced by a symlink/non-file, or grown beyond its bound.
302
- `--force` does not weaken those ownership checks. The inventory is capped at 64 KiB and the complete
303
- report, JSON, inventory, PNGs, receipts, stale cleanup, and optional diffs commit or roll back as one
304
- file transaction.
305
-
306
- Different pixels are ordinary review evidence and exit 0. A frame, dimension, runtime, or exact
307
- data mismatch exits 1 and suppresses pixel metrics because the images are not comparable.
308
- `--allow-data-mismatch` keeps a data-mismatch report inspectable with exit 0, but does not invent
309
- pixel metrics. `--watch` observes both configs, cancels stale renders, preserves the last complete
310
- report through invalid edits, and emits deterministic NDJSON with `--json`. An explicit report path
311
- requires `--force` in watch mode; the managed default path is safely replaceable.
312
-
313
- Watch events are `watching`, `building`, `invalid`, `recovered`, `generation-complete`, `failed`,
314
- and `stopped`, with monotonic comparison generations and source-side generations where applicable.
315
- Without `--allow-data-mismatch`, an incompatible generation emits `failed`, does not replace the
316
- last complete report, and remains an unresolved failure; an allowed data mismatch emits
317
- `generation-complete` but still has no pixel metrics. An orderly stop exits 0 only after at least
318
- one complete generation and no unresolved invalid or failed state; otherwise it exits 1.
319
-
320
- Render one checkpoint, or recapture after every edit:
321
-
322
127
  ```sh
323
128
  npx tileflow capture madrid-desktop --json
324
- npx tileflow capture --all --json
325
- npx tileflow capture madrid-desktop --watch --json
326
- ```
327
-
328
- Use the first command when you want a single image and the last command while refining a map. Watch
329
- mode stays open, follows changes to the config, its local imports, and its effective icons and fonts,
330
- and writes a new PNG after each valid edit. Keeping the browser ready makes repeated renders faster.
331
- If an edit is invalid, the last good image remains in place and capture resumes automatically after
332
- the fix. Stop watch mode with `Ctrl+C`. It accepts named committed scenes or `--all`, not exploratory
333
- camera options.
334
-
335
- Standalone scenes need no app server, account, API key, MCP service, system Chrome, or visible
336
- window. The first command—or the first capture—may provision Playwright's pinned Chromium headless
337
- shell in its versioned per-user cache. `--no-browser-install` makes a prepared/offline environment
338
- strict. Tileflow never falls back to a system browser or packages the browser in npm.
339
-
340
- For prepared or offline CI, install ahead of time with
341
- `npx tileflow setup capture --json`. Use `setup capture --no-browser-install` or
342
- `capture --no-browser-install` as an enforcement check that the exact shell is already cached.
343
-
344
- For an application scene, its route and component props must render the committed camera. Tileflow
345
- uses the camera in scene identity but does not mutate arbitrary application map state.
346
-
347
- One-shot success JSON is one deterministic schema-version-1 document plus one newline. It contains
348
- sorted scene/map/theme/target entries, relative output and receipt paths, image hash/dimensions/DPR,
349
- renderer identity, remote-dependency state, and warnings; it contains no image bytes, credential,
350
- origin, absolute path, user, or timestamp. Managed output is an atomic pair under
351
- `.tileflow/captures/<scene>.png` and `<scene>.receipt.json`. `tileflow init` ignores managed captures
352
- and `.tileflow/diffs` when creating a new `.gitignore`. Explicit output replacement requires
353
- `--force`; symlinks and path escapes fail closed.
354
-
355
- Each written receipt uses capture schema v4 and records the concrete theme. A Tileflow World
356
- capture resolves its TileJSON once for
357
- the whole capture session and records the exact `world-v1` release plus descriptor, archive, data
358
- contract, and product-contract hashes. All selected scenes and retries therefore use one immutable
359
- World release even if `current` moves while the command is running.
360
-
361
- One-shot `--json` failures leave stdout empty and write exactly one deterministic failure document
362
- to stderr with `code`, `phase`, bounded diagnostics, and optional origin-only resource metadata.
363
-
364
- Watch JSON is NDJSON with monotonic `building`, `invalid`, `recovered`, `captured`, `failed`, and
365
- `stopped` generation events. It watches config, transitive local imports, and effective icon/font
366
- files, preserves the last good capture through invalid edits, cancels stale work, and reuses one
367
- headless Browser. An orderly stop exits 0 only after a successful capture with no unresolved
368
- terminal failure.
369
-
370
- ### Capture through the real application
371
-
372
- Application scenes use the app's existing Vite, Next.js, Webpack, or custom loopback server. Start
373
- only that normal server; Tileflow does not run a package script, scan ports, or start
374
- `tileflow preview`:
375
-
376
- ```sh
377
- npm run dev
378
- TILEFLOW_APP_ORIGIN=http://127.0.0.1:3000 \
379
- npx tileflow capture madrid-product --json
380
129
  ```
381
130
 
382
- The React, Vue, and Svelte wrappers expose `data-tileflow-map`, the resolved concrete
383
- `data-tileflow-theme`, optional `data-tileflow-capture-id`, and
384
- `data-tileflow-state="loading|idle|error"`. The headless client selects exactly one target, verifies
385
- the theme, and waits for idle. Use `--url` for one explicit full loopback URL, `--selector` to
386
- override target selection, and `--frame map|viewport` to override framing. Origins and URLs must be
387
- credential-free loopback HTTP(S) without fragments. Each navigation uses a fresh context without a
388
- reused profile, cookies, local storage, or service workers.
131
+ The first capture may install Playwright's exact pinned Chromium headless shell. `tileflow setup
132
+ capture` provisions it ahead of time; a system Chrome installation is not a substitute. Scenes
133
+ belong to their map and do not inherit. `system` and an omitted scene theme are invalid.
134
+ Coordinates are `[longitude, latitude]`; viewport dimensions are CSS pixels and `dpr` determines
135
+ physical image size.
389
136
 
390
- ### Match a reference and protect the result
137
+ One-off capture accepts camera, size, and theme flags and returns a normalized scene definition.
138
+ Commit that definition deliberately; the CLI does not rewrite executable config. Capture receipts
139
+ record runtime and data identity. Remote dependencies can change, so a successful render is not a
140
+ promise of identical pixels on every platform or future run.
391
141
 
392
- While refining a style, compare the current scene with any reference screenshot:
142
+ For application capture, define an application target with its route and optional `captureId` in
143
+ the scene. Start the application's normal server in one terminal. In another terminal, run:
393
144
 
394
145
  ```sh
395
- npx tileflow visual analyze madrid-desktop \
396
- --reference ./design-reference.png --region=0,0,1200,760 --json
397
- ```
398
-
399
- `visual analyze` renders exactly one committed scene and writes the current image and a JSON report
400
- under `.tileflow/analysis` by default. The report includes both images' dimensions and dominant
401
- colors. When their physical dimensions match, it also includes exact and perceptual pixel metrics,
402
- mean channel difference, a high-contrast `.diff.png`, and signed
403
- `appearance.actualMinusReference` luminance, OKLab, edge-density, and local-contrast evidence. The
404
- optional region affects only those appearance metrics. The reference PNG is never modified or
405
- treated as a baseline.
406
-
407
- Once the map is approved, save it as the expected baseline and use that image to catch later
408
- regressions:
409
-
410
- ```sh
411
- # Save the reviewed current render as the expected baseline.
412
- npx tileflow visual update madrid-desktop \
413
- --baseline-dir test/visual-baselines --json
414
-
415
- # Compare a fresh render without changing the baseline.
416
- npx tileflow visual diff madrid-desktop \
417
- --baseline-dir test/visual-baselines --json
418
-
419
- # Or apply the operation to every committed scene.
420
- npx tileflow visual diff --all \
421
- --baseline-dir test/visual-baselines --json
422
-
423
- # In CI, return exit 2 when the pixels have changed.
424
- npx tileflow visual diff madrid-desktop \
425
- --baseline-dir test/visual-baselines --fail-on changed --json
146
+ npx tileflow capture madrid-product --url http://127.0.0.1:3000/maps/madrid --json
426
147
  ```
427
148
 
428
- `visual diff` and `visual update` require either one or more positional scene names or `--all`;
429
- those forms are mutually exclusive. `visual analyze` always accepts exactly one scene.
149
+ This command assumes a committed `madrid-product` application scene and a matching Tileflow component
150
+ on that route. Capture does not start the server or discover ports. It accepts loopback HTTP(S),
151
+ selects exactly one target, verifies the concrete theme, and waits for the component's idle marker.
152
+ Do not run a separate `tileflow preview` server beside the application.
430
153
 
431
- The baseline directory holds the reviewed expected PNG and its receipt. The files generated by a
432
- comparison are working evidence: the current `.actual.png`, a transparent high-contrast
433
- `.diff.png` when comparable, and a `.visual.json` report under `.tileflow/diffs` by default.
434
- `visual diff` may replace those working files on each run, but it never changes the baseline. This
435
- separation prevents a check from silently accepting the change it was meant to reveal.
154
+ ## Review pixels without accepting changes
436
155
 
437
- Before comparing, `visual diff` validates the baseline PNG and receipt, including their hashes,
438
- dimensions, runtime, and scene identity, without executing or fetching baseline metadata.
439
- Statuses are `unchanged`, `changed`, `missing-baseline`, `scene-mismatch`, and `runtime-mismatch`.
440
- Same-size images report exact RGBA changed pixels and an informational fixed-threshold perceptual
441
- metric; exact inequality determines changed.
442
-
443
- Changed pixels exit 0 by default so a person or agent can inspect the working files.
444
- `--fail-on changed` exits 2 for CI; missing or incompatible baselines and operational failures exit
445
-
446
- 1. Run `visual update` again only after reviewing and accepting the new render. It is the only
447
- command that creates or changes baseline pairs, and it never stages, commits, or pushes. Remote
448
- tiles, glyphs, and sprites are reported because their pixels can change independently of the style.
449
-
450
- ## Inspect vector features
451
-
452
- See which bounded source features the exported map sees near a camera before tuning taxonomy,
453
- density, or labels:
156
+ After reviewing a render, create its baseline. Compare subsequent renders separately:
454
157
 
455
158
  ```sh
456
- npx tileflow inspect features \
457
- --center=-3.6927512,40.4086555 --zoom=16 \
458
- --layers=poi --properties=name,category,type,icon,filter_rank,size_rank --json
159
+ npx tileflow visual update madrid-desktop --baseline-dir test/visual-baselines --json
160
+ npx tileflow visual diff madrid-desktop --baseline-dir test/visual-baselines --fail-on changed --json
459
161
  ```
460
162
 
461
- The command supports HTTP(S) TileJSON/vector sources and returns only requested properties plus
462
- geometry summaries in stable order. Viewport, tiles, bytes, scanned/returned features, names, and
463
- timeouts are bounded. Safe provenance includes origins, a query-free TileJSON path, and configured
464
- source revision or `null`; credentials, URL queries, hidden properties, response bodies, and
465
- absolute paths are omitted. It is read-only apart from executable config's own possible side
466
- effects and removes `TILEFLOW_API_KEY` before loading config.
163
+ Only `visual update` changes baseline PNG/receipt pairs. `visual diff` writes working evidence, not
164
+ approval. Changed pixels normally exit 0; `--fail-on changed` exits 2. Missing or incompatible
165
+ baselines and operational failures exit 1. Never run `visual update` automatically to make CI pass.
467
166
 
468
- ## Hosted authentication and deploy
167
+ Use `visual analyze <scene> --reference <png>` for an external screenshot without a Tileflow
168
+ receipt. Use `visual compare` for an authenticated two-style review with matched camera, viewport,
169
+ renderer, and data identity. Neither operation approves a baseline. Capture watch mode emits NDJSON
170
+ generation events rather than a single JSON document.
469
171
 
470
- Hosted writes have two independent authorization paths:
172
+ The [capture contract](https://github.com/tileflow/tileflow-sdk/blob/main/docs/contracts/local-visual-capture.md)
173
+ documents readiness, receipts, comparison limits, and CLI output formats.
471
174
 
472
- - Personal developer session: run `npx tileflow login` once for a
473
- Tileflow API origin. Login authenticates the account and selects no Map.
474
- Map commands exchange it for a brief Map capability; tileset commands use a separate Team data
475
- capability.
476
- - CI key: create a dashboard `CI deploy` key, store it as
477
- `TILEFLOW_API_KEY`, and let the repository workflow deploy without a local login. The server
478
- binds that key to exactly one Map.
175
+ ## Publish data and deploy a map
479
176
 
480
- Hosted control-plane requests stay pinned to the configured HTTP(S) origin, apply a hard bounded
481
- timeout, and stream at most 1 MiB of response data. CLI diagnostics never echo an untrusted remote
482
- response body or bearer credential.
483
-
484
- Inspect the account, then target the Map shown in the dashboard:
177
+ Hosted writes require authorization. For local development, `login` stores a personal session;
178
+ for CI, provide an appropriately scoped key through the secret environment variable
179
+ `TILEFLOW_API_KEY`. CI does not fall back to a saved personal login. Never put a key in a config,
180
+ browser bundle, copied prompt, or command-line argument.
485
181
 
486
182
  ```sh
183
+ npx tileflow login
487
184
  npx tileflow whoami --json
488
185
  npx tileflow deploy --map-id map_AbCdEfGhIjKlMnOp
489
186
  npx tileflow status --map-id map_AbCdEfGhIjKlMnOp
490
- npx tileflow logout
491
187
  ```
492
188
 
493
- The dashboard creates the Map and browser-access policy before repository setup. Keep that exact
494
- Map ID in the deploy action. If the config contains several maps, select the authored map explicitly:
495
-
496
- ```sh
497
- npx tileflow deploy \
498
- --map-id map_AbCdEfGhIjKlMnOp \
499
- --map store-locator
500
- ```
189
+ Replace the example Map ID with the destination created in Tileflow. It is a public identifier,
190
+ not a credential or the portable `id` in your config. A CI deploy key must authorize that destination.
191
+ `logout` removes the saved personal session.
501
192
 
502
- The Map ID is a public destination, not a credential. A successful server-confirmed deploy keeps
503
- unrelated manifest entries and records that Map's stable ID, hosted theme URLs, World `v1`
504
- generation, and fixed session usage mode. Browser access remains server-owned and is never read
505
- from or written to repository configuration. Do not add an API key or payment authority to a copied
506
- prompt.
193
+ Deploy publishes the compiled concrete-theme family and managed icon assets; it does not ask the
194
+ server to compile TypeScript. Repeating an unchanged deployment reuses its version. Build writers
195
+ refuse to overwrite hosted manifests by default, and deploy refuses to replace a self-hosted
196
+ manifest without explicit authorization. Keep separate outputs, or use the documented overwrite
197
+ option only for an intentional migration.
507
198
 
508
- Team tileset commands exchange the same account session for a separate Team-scoped data capability;
509
- it carries no Map authority. Inspect and preview remain account-free:
199
+ Data publication is separate from map deployment:
510
200
 
511
201
  ```sh
512
202
  npx tileflow tileset inspect ./data/stores.pmtiles --json
513
- npx tileflow tileset inspect ./data/stores.pmtiles \
514
- --include-values category,status --json
515
- npx tileflow tileset publish ./data/stores.pmtiles \
516
- --id stores --team @acme --attribution 'Store data © Example' --json
517
- npx tileflow tileset list --team @acme --json
203
+ npx tileflow tileset publish ./data/stores.pmtiles --id stores --team @acme --attribution 'Store data © Example' --json
518
204
  npx tileflow tileset status stores --team @acme --json
519
205
  ```
520
206
 
521
- Inspection schema 1 separates authoritative PMTiles/TileJSON declarations from bounded MVT
522
- observations. Sampled fields report present/missing feature counts, observed distinct-value counts,
523
- numeric min/max, and truncation. Raw primitive values remain absent unless `--include-values`
524
- explicitly selects their comma-separated field names; the command emits at most 16 values per field,
525
- 32 selected fields, and 256 characters per string. `--no-sample` returns only authoritative metadata
526
- and cannot be combined with value inspection. Directory traversal recomputes addressed-tile and
527
- tile-entry counts; the header's tile-content count is reported only as a nullable declaration and is
528
- not treated as authority.
529
-
530
- `publish --id` names a Team-local logical resource; Tileflow owns its opaque delivery ID. The
531
- command validates the archive locally before authentication, hashes it in fixed 16 MiB parts, then
532
- uploads at most four parts concurrently without buffering the complete file. Interrupted sessions
533
- remain resumable for 24 hours: rerunning the same command reconciles server receipts and transfers
534
- only missing parts. Normal Queue initialization is polled for at most two minutes before the command
535
- returns a resumable availability error. Retryable transfer failures receive fresh short-lived authorization; a changed
536
- local file stops before completion. Free accepts versions through exactly 2,000,000,000 bytes and
537
- Starter through exactly 4,000,000,000 bytes, subject to the Team's hosted-storage capacity.
538
-
539
- Publication completes only after server-side integrity and PMTiles validation. A compatible new
540
- version becomes current at the same stable TileJSON and tile URLs, so newly resolved browser
541
- requests see it without creating a Map deployment. Purge requires `--confirm <exact-id>` and fails
542
- with bounded dependency context while any retained Map deployment uses the resource. Automation may set a Team data
543
- `TILEFLOW_API_KEY`; that key selects its Team, so commands omit `--team` and never load account
544
- state.
545
-
546
- `tileset publish --json` emits schema version 2 with the Team selector when known, logical and
547
- opaque tileset identities, immutable version ID and number, exact byte count, content-hash
548
- algorithm/hash, final state, and `changed` or `unchanged` publication result. It never emits the
549
- local path, upload session, storage key, signed URL, ETag, credential, or retry details.
550
-
551
- An explicit key or `TILEFLOW_API_KEY` never uses the saved account session. The deploy API rejects a
552
- `--map-id` that does not match the key. Read-only hosted icon comparison validates the same binding
553
- before loading its baseline.
554
-
555
- The CI key grants only `styles:write` and `status:read`. It cannot upload
556
- datasets or render images. Give it an expiration, rotate the repository secret
557
- before it expires, and avoid non-expiring CI keys.
558
-
559
- Detected CI never falls back to the credential saved by `tileflow login`: if
560
- `TILEFLOW_API_KEY` is absent, deploy stops before loading config or making a
561
- request. Once captured, the key is hidden from `process.env` and `--api-key` is removed from the
562
- temporary `process.argv` view before the CLI imports executable `tileflow.config.ts`; both process
563
- surfaces are restored after the protected operation. Every config-aware command uses the same
564
- scope, including validate, build, dev/watch, capture, visual, inspect, icon inspection, and deploy.
565
- This is defense in depth, not a sandbox; deploy only reviewed repository code on a trusted runner,
566
- and do not pass keys through the `--api-key` command line in CI.
567
-
568
- The [deploy documentation](https://tileflow.dev/docs/deploy) contains copyable
569
- GitHub Actions and GitLab CI workflows. Both use `npm ci`, the committed
570
- lockfile, and the repository-local CLI. GitHub exposes the key only to its deploy
571
- step. GitLab variables are job-scoped, so its example validates in a keyless job
572
- and deploys in a protected `production` job; the locked install and runner are
573
- part of that trusted job boundary. Both serialize publications and intentionally
574
- omit path filters because `tileflow.config.ts` can import arbitrary repository
575
- files.
576
-
577
- The CLI records bounded private provenance for GitHub Actions, GitLab CI,
578
- generic CI, and local runs. These provider fields are descriptive client
579
- reports, not OIDC attestations. Provider values can be overridden with:
580
-
581
- ```txt
582
- TILEFLOW_DEPLOY_REPOSITORY
583
- TILEFLOW_DEPLOY_REVISION
584
- TILEFLOW_DEPLOY_REF
585
- TILEFLOW_DEPLOY_RUN_ID
586
- TILEFLOW_DEPLOY_RUN_URL
587
- ```
207
+ Use your own file, Team selector, and attribution. Inspection is account-free. Publication validates
208
+ and uploads a managed dataset using Team data authority, not a map-only deploy key. Interrupted
209
+ uploads are resumable; a completed version becomes current at stable delivery URLs. Purge is
210
+ explicit, requires confirmation, and can be blocked by retained deployment dependencies.
588
211
 
589
- Invalid explicit values fail before a network write. Provider metadata that is
590
- missing, malformed, or too long is omitted. Secrets and the complete
591
- environment are never logged.
592
-
593
- A separate app-build step is absent from the minimal workflows. Self-hosted build and deploy emit the same
594
- runtime manifest version 1 shape; Hosted fields are optional identity metadata on its map/theme
595
- entries. Filesystem build writers refuse to replace a manifest carrying Hosted metadata by default,
596
- and deploy refuses to replace a purely local manifest. Prefer `emitBuildArtifacts: false` or
597
- separate output paths when the app deliberately packages a deploy manifest. The explicit
598
- `overwriteHostedManifest: true` build option and
599
- `tileflow deploy --overwrite-self-hosted-manifest` flag authorize that destination replacement. A
600
- retry of the same compiled theme family reuses its deployment version and prints `Unchanged`;
601
- changed cartography prints `Published` with a new version. Allowed websites is managed separately
602
- in Tileflow and is never read from repository config. The
603
- fingerprint binds resource references, not the changing bytes behind referenced
604
- glyph or sprite URLs. Every theme of one logical map publishes atomically; separate maps can still
605
- partially succeed when no remote batch release is used.
606
-
607
- All config, theme-style, icon, and compatibility preflight happens before the first style write. After
608
- that boundary the current Hosted API has no batch commit across repository-internal orchestration:
609
- one singular config can publish before a later config fails. The orchestrator then leaves the
610
- previous local manifest untouched, reports which publications succeeded, and tells the operator to
611
- retry; idempotent publication converges on that retry. The local manifest
612
- writer uses a durable same-directory temporary followed by direct rename and directory sync, so
613
- readers see either the previous or next complete manifest. Multi-file artifact writers remain
614
- rollback-capable sets. Neither mechanism is a remote transaction or can make several API writes
615
- all-or-none.
616
-
617
- Deploy treats the locally compiled MapLibre Style family as one logical-map artifact. The request
618
- contains an exact `styles[theme]` collection, per-theme canonical SHA-256 identities in the build
619
- manifest, only bounded hosting policy that does not belong in MapLibre itself, and the exact managed
620
- icon-package identity when the family has one. Delivery
621
- policy is not inherited with cartographic fields. Deploy does not serialize the module
622
- configuration, send a public `tileset` selector, or ask the hosted API to compile the map again.
623
- Hosted publication currently requires Tileflow World; `vectorTiles()` remains available for local
624
- builds and previews but fails deploy before any remote write. The API binds recognized
625
- Tileflow-owned world and terrain URLs to its generated map ID. A successful response must return
626
- exactly the submitted theme names and a hosted Style URL for each. Deploy writes strict runtime
627
- manifest version 1 with stable theme URLs, `colorScheme`, content revision, optional font faces and
628
- style IDs, rather than duplicating dataset configuration. No older manifest is normalized.
629
-
630
- For a map with `icons: ['./icons']`, hosted validation compiles the local SVG/PNG/JPEG/WebP files
631
- without a key. Ordered directories apply left to right and later exact IDs replace earlier files.
632
- Deploy uploads the four generated sprite files before its first style write and reuses
633
- byte-identical packages by content hash. Source icons and absolute paths remain local; generated
634
- atlas bytes and sorted icon names are public. Each hosted package is limited to 256 icons and 8 MiB
635
- generated bytes as a processing envelope. There is no package-count quota; physically retained
636
- generated packages share the organization's 5/10-GB hosted-storage pool with retained PMTiles,
637
- remain protected by deployment/library references, and otherwise enter the technical orphan grace
638
- before deletion. Upload success must confirm the submitted `contentHash`, exact icon count, exact
639
- generated byte total, one opaque `icp_<id>`, and the corresponding query-free
640
- `/sprites/<id>/sprite` URL. The CLI rejects any missing or divergent field before using that URL.
641
-
642
- Hosted deploy currently rejects local or package-owned web fonts before authentication or remote
643
- writes. Use self-hosted delivery or an explicit public glyph provider. Enabling managed font bundles
644
- requires a separately deployed ownership, quota, retention, and immutable-delivery contract.
645
-
646
- For both managed resource kinds, `assetSetSha256` remains a separate per-map output identity. It
647
- hashes each generated file's exact portable name, media type, byte count, and SHA-256 using Core's
648
- asset-set v1 contract; it does not hash only the icon-package manifest. Hosted must
649
- confirm the immutable resource bytes, reconstruct those same per-file identities (including the
650
- `icons/<mapId>/` prefix), and reject the Style when the submitted build-manifest hash diverges.
651
-
652
- ## Agent icon composition
653
-
654
- List the effective local catalog used by the exported map:
212
+ `inspect features` samples bounded vector-source features. `icons list` and `icons diff` inspect
213
+ prepared icon identities; they do not turn package directories into a separate hosted library.
214
+ Use the installed command's help for exact arguments and supported JSON output.
655
215
 
656
- ```sh
657
- npx tileflow icons list --json
658
- ```
216
+ ## Team Icon Sets and repository locks
659
217
 
660
- The successful stdout contract is one deterministic JSON document followed by exactly one newline.
661
- Its top-level fields, in order, are `schemaVersion: 2`, `pathBase: "cwd"`, and `maps`.
662
- Schema version 2 is a compatibility boundary: removing or renaming a field or changing an enum's
663
- meaning requires a new schema version. Additive optional fields require corresponding documentation
664
- and tests.
665
-
666
- Each sorted map entry has one `id` and an `icons` value. `icons.kind` is `none` for `icons: []`, or
667
- `directories` for a prepared ordered composition. A directory entry contains:
668
-
669
- - `directories`, in the exact left-to-right authoring order, using config-relative paths or safe
670
- `npm:<package>/<path>` descriptors;
671
- - `finalIds`, the sorted canonical lower-kebab IDs in the resulting sprite;
672
- - `replacements`, with the replaced path and winning path for every later exact-ID replacement;
673
- - `sources`, with the winning ID, cwd-relative path, format, byte length, and intrinsic dimensions;
674
- - `insideWorkingTree`; and
675
- - the deterministic generated `packageHash`.
676
-
677
- There is deliberately no parallel catalog registry, provider kind, semantic mapping, external
678
- sprite branch, or arbitrary source-to-runtime renaming. `<id>.<ext>` publishes `<id>` and the
679
- reserved pattern form `<id>.pattern.<ext>` also publishes `<id>`. This lets an
680
- agent answer “which directory wins this icon?” directly from one map record without reconstructing
681
- hidden provider state. Use `--map <id>` to select one exact map when internal orchestration supplies
682
- more than one.
683
-
684
- All reported paths are relative to the invocation working directory. A source outside that tree
685
- uses `../` and `insideWorkingTree: false`; no absolute path is emitted. Listing follows local
686
- authoring semantics. Run `npx tileflow validate --target hosted` separately before a
687
- hosted deploy to check containment, portable IDs, SVG safety, and hosted limits.
688
-
689
- The Tileflow command performs no authentication, network request, browser/server launch, or file
690
- write. It removes an ambient `TILEFLOW_API_KEY` before importing config. As with every config-aware
691
- command, loading `tileflow.config.ts` executes repository code and is not a sandbox; side effects in
692
- that code remain the repository's responsibility. Success emits no ANSI or progress prose. Usage,
693
- config, source, decode, and render failures exit 1, write diagnostics to stderr, and leave stdout
694
- empty.
695
-
696
- The output contains no source contents or source hash, rendered cells, atlas coordinates,
697
- image/base64 payload, credential, timestamp, random value, or absolute path. Open a reported local
698
- source path with normal repository tools only when the pixels themselves are needed.
699
-
700
- ## Read-only icon comparison
701
-
702
- Compare the exported map with its active hosted revision before deciding whether to deploy:
218
+ Two intentionally separate families cover shared icons. `icon-set` manages the remote Team catalog
219
+ with Team authority; `icons install|update|pin` maintain the repository's exact
220
+ `tileflow.icons.lock.json` beside the selected config.
703
221
 
704
222
  ```sh
705
- npx tileflow icons diff --map-id map_AbCdEfGhIjKlMnOp --against production
706
- npx tileflow icons diff --map-id map_AbCdEfGhIjKlMnOp --against production --json
707
- npx tileflow icons diff --map-id map_AbCdEfGhIjKlMnOp --against production --report ./icon-diff.html
708
- ```
709
-
710
- The command compiles only the exported map, performs authenticated read-only control-plane
711
- requests, and never uploads a package, creates a deployment, or writes the frontend manifest.
712
- Plain and JSON modes create no files. A requested HTML report adds reads of the baseline's four
713
- public sprite files and
714
- embeds verified old/new images in one self-contained file. The report groups exact-cell icon
715
- previews under `Added`, `Modified`, and `Removed`. Added and removed cards show only the affected
716
- icon; modified cards compare `Before` with `Next`. A script-free 1x/2x selector defaults to 2x,
717
- switches the embedded density, and renders 1x at half the 2x preview size inside a stable frame so
718
- the selected state is immediately visible. Package hashes, generated sizes, and icon counts stay in
719
- collapsed `Details`. A map badge is shown only for a map-scoped report. It exposes no atlas
720
- implementation UI and contains no API key, remote runtime dependency, original icon source, or
721
- local source path. Use `--force` to replace different existing report bytes and `--open` only
722
- together with `--report`.
723
-
724
- Visual modification means that normalized rendered RGBA pixels changed at 1x or 2x. Fully
725
- transparent RGB is ignored. The manifest also hashes the four encoded artifacts, so an artifact can
726
- change while its per-icon pixel list remains unchanged. The report and digest analysis operate on
727
- generated sprite data; SVG, raster source files, and absolute paths stay on the local machine.
728
-
729
- `--json` writes exactly one deterministic schema-version-1 document plus a trailing newline. Its
730
- stable top-level fields, in order, are:
731
-
732
- ```json
733
- {
734
- "schemaVersion": 1,
735
- "environment": "production",
736
- "baseline": {"deploymentId": "dep_...", "package": null, "version": 7},
737
- "proposed": {"package": null},
738
- "icons": {"added": [], "removed": [], "modified": [], "unchangedCount": 0},
739
- "generatedBytes": {"before": 0, "after": 0, "delta": 0},
740
- "artifacts": {"report": null},
741
- "hasChanges": false
742
- }
223
+ npx tileflow icon-set publish ./icons --id brand --team @acme --idempotency-key brand-2026-09-14 --json
224
+ npx tileflow icon-set versions brand --team @acme --json
225
+ npx tileflow icons install --team @acme --json
226
+ npx tileflow icons pin @acme/brand --version 3 --team @acme --json
743
227
  ```
744
228
 
745
- Package summaries, when present, contain `contentHash`, `iconCount`, `label`, and `totalBytes`.
746
- A missing hosted baseline is an initial comparison against an empty package. The command compares
747
- only delivered icon pixels, canonical package manifests, and generated bytes; config-directory
748
- provenance and style-reference analysis belong to `icons list` and final style validation.
749
-
750
- Normal differences exit 0. Config, compilation, credential, network, response, and report errors
751
- exit 1.
752
-
753
- This workflow does not provide OIDC, automatic secret installation, an official
754
- GitHub Action, an atomic multi-map deploy set, or a Tileflow-hosted remote
755
- builder.
756
-
757
- Docs: https://tileflow.dev/docs/deploy
229
+ Use your own directory, Team selector, and retry key. `publish` compiles one local directory into
230
+ the four generated sprite files and creates an immutable integer revision; republishing identical
231
+ bytes reports `unchanged` and reuses the same revision. `list`, `status`, `versions` and `uses` are
232
+ bounded Team reads. `archive` and `unarchive` change only catalog state and never remove retained
233
+ revisions. `purge <slug> --version <n>` additionally requires `--idempotency-key`, an exact
234
+ `--confirm @team/set@version`, and `--acknowledge-unknown-locks`, because repository locks that were
235
+ never deployed are not discoverable and already-downloaded public bytes cannot be revoked.
236
+
237
+ The lock commands inspect the `iconSet()` references your config declares. They are the only
238
+ commands that resolve `latest`, and the only ones that write the lock. `install` fills in declared
239
+ references that have no pin, `update` moves selected references to their current latest revision,
240
+ and `pin` selects one exact revision. Every requested reference is resolved before a single
241
+ compare-and-swap write of the whole snapshot, so a concurrent writer fails the command instead of
242
+ losing its pins. No lock command rewrites `tileflow.config.ts`.
243
+
244
+ `validate`, `build`, `preview`, `deploy`, `icons list` and `icons diff` read the lock and never
245
+ resolve a catalog head. `--cache-dir` chooses the verified artifact cache root and `--offline` fails
246
+ a cache miss instead of hydrating it. Publishing a newer revision changes nothing in a repository
247
+ until `install`, `update` or `pin` changes its exact pin.
248
+
249
+ These commands require an account session or a Team data key carrying `icons:read` for reads and
250
+ `icons:write` for publication, archive state and purge. A Map-scoped deploy key never gains catalog
251
+ authority. Availability depends on your deployment; check the installed command's help and your
252
+ Team's enabled features.
253
+
254
+ ## Local coordinate commands
255
+
256
+ `setup coordinates` and `coordinates search|describe|operations|transform` require a compatible,
257
+ explicitly provided native distribution. Installing this CLI does not provide native engine,
258
+ catalog, or grid assets, and no public native runtime download is currently offered. There is no
259
+ hosted fallback. See the
260
+ [local runtime guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/coordinates-runtime/README.md)
261
+ for the verified platform, setup, and development-artifact restrictions.
262
+
263
+ ## Reference and troubleshooting
264
+
265
+ Run `npx tileflow --help` or `npx tileflow <command> --help` for the installed command surface.
266
+ The families cover map authoring, semantic language discovery, local visual evidence, datasets and
267
+ icons, account sessions, coordinates, and hosted delivery. Hidden support commands are not a
268
+ recommended application workflow.
269
+
270
+ A manifest 404 usually means assets were not built/served at the component's configured URL.
271
+ Missing fonts or sprites require the complete prepared output. Hosted compatibility failures should
272
+ be fixed before authentication or upload, not bypassed with repeated deployment attempts.
273
+
274
+ See [deployment documentation](https://tileflow.dev/docs/deploy),
275
+ [SDK responsibility boundaries](https://github.com/tileflow/tileflow-sdk/blob/main/docs/contracts/sdk-responsibilities.md),
276
+ and [issues](https://github.com/tileflow/tileflow-sdk/issues). Source `main` may be newer than npm;
277
+ use the installed CLI's help and generated contracts for that release.
278
+
279
+ ## Detailed guides
280
+
281
+ These guides are also included in the installed package under `docs/`. They describe this source
282
+ revision; prefer the installed copy when working with an older release.
283
+
284
+ - [CLI setup and defaults](https://github.com/tileflow/tileflow-sdk/blob/main/packages/cli/docs/cli-setup-and-defaults.md)
285
+ - [Build artifacts](https://github.com/tileflow/tileflow-sdk/blob/main/packages/cli/docs/build-artifacts.md)
286
+ - [Deterministic agent diagnostics](https://github.com/tileflow/tileflow-sdk/blob/main/packages/cli/docs/deterministic-agent-diagnostics.md)
287
+ - [Coordinates](https://github.com/tileflow/tileflow-sdk/blob/main/packages/cli/docs/coordinates.md)
288
+ - [Command families](https://github.com/tileflow/tileflow-sdk/blob/main/packages/cli/docs/command-families.md)
289
+ - [Local visual feedback](https://github.com/tileflow/tileflow-sdk/blob/main/packages/cli/docs/local-visual-feedback.md)
290
+ - [Inspect vector features](https://github.com/tileflow/tileflow-sdk/blob/main/packages/cli/docs/inspect-vector-features.md)
291
+ - [Hosted authentication and deploy](https://github.com/tileflow/tileflow-sdk/blob/main/packages/cli/docs/hosted-authentication-and-deploy.md)
292
+ - [Agent icon composition](https://github.com/tileflow/tileflow-sdk/blob/main/packages/cli/docs/agent-icon-composition.md)
293
+ - [Read-only icon comparison](https://github.com/tileflow/tileflow-sdk/blob/main/packages/cli/docs/read-only-icon-comparison.md)
294
+
295
+ ## Validate icon representations
296
+
297
+ `tileflow validate`, development and build resolve icon capabilities before returning a map.
298
+ `TF_ICON_REPRESENTATION_MIXED` means a layer can select SDF and RGBA icons, including a fallback or
299
+ local override. Keep that selection homogeneous or use an explicit bounded mapping. Development
300
+ reports the invalid generation while retaining its last valid artifact.
301
+
302
+ Declare defaults in `tileflow.icons.json`; inspect effective appearances and text-fitting layouts with
303
+ `tileflow icons list --json`. Diff reports detect default-only changes and show rendered previews.
304
+ See [Author recolorable and adaptable icons](https://github.com/tileflow/tileflow-sdk/blob/main/packages/dev/docs/native-icons.md) for the source profile and halo bounds.