@tileflow/dev 0.1.0-alpha.37 → 0.1.0-alpha.39
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 +11 -21
- package/dist/artifacts.js +4 -4
- package/dist/{chunk-UKWAQKLH.js → chunk-AVJMTXW5.js} +57 -22
- package/dist/{chunk-5RT4CHSK.js → chunk-C4VPHZ3F.js} +1109 -305
- package/dist/{chunk-UTRO4IBQ.js → chunk-FOMTSCOP.js} +1 -1
- package/dist/{chunk-7C4F6GAX.js → chunk-RTU7TD4M.js} +4 -2
- package/dist/fonts.js +2 -2
- package/dist/icons.js +2 -2
- package/dist/preview.js +4 -2
- package/dist/server.js +4 -4
- package/package.json +4 -5
- package/docs/artifact-lifecycle.md +0 -152
- package/docs/beacon-map-audits.md +0 -145
- package/docs/bounded-pmtiles-resource-inspection.md +0 -21
- package/docs/bounded-vector-feature-inspection.md +0 -99
- package/docs/building-models.md +0 -179
- package/docs/layers-inspection.md +0 -92
- package/docs/local-comparison-workbench-and-compiler-inspection.md +0 -130
- package/docs/map-design-diagnostics.md +0 -76
- package/docs/native-artifacts.md +0 -287
- package/docs/native-icons.md +0 -129
- package/docs/structured-config-inspection-and-diagnostics.md +0 -39
|
@@ -71,7 +71,9 @@ async function resolveTileflowAssetDirectories(directories, options) {
|
|
|
71
71
|
let packageRoot;
|
|
72
72
|
try {
|
|
73
73
|
validatePackageDirectory(directory);
|
|
74
|
-
const requireFromProject = createRequire(
|
|
74
|
+
const requireFromProject = createRequire(
|
|
75
|
+
resolve(realBaseDirectory, "__tileflow_config__.cjs")
|
|
76
|
+
);
|
|
75
77
|
let packageJson;
|
|
76
78
|
try {
|
|
77
79
|
packageJson = requireFromProject.resolve(`${directory.package}/package.json`);
|
|
@@ -120,7 +122,7 @@ async function resolveTileflowAssetDirectories(directories, options) {
|
|
|
120
122
|
containmentRoot,
|
|
121
123
|
packageOwned,
|
|
122
124
|
realPath: realCandidate,
|
|
123
|
-
watch: !packageOwned
|
|
125
|
+
watch: !packageOwned || isPathInside(realCwd, realCandidate) && !realCandidate.split(/[\\/]/u).includes("node_modules")
|
|
124
126
|
});
|
|
125
127
|
} catch (error) {
|
|
126
128
|
issues.push({
|
package/dist/fonts.js
CHANGED
|
@@ -4,8 +4,8 @@ import {
|
|
|
4
4
|
getTileflowFontWatchPaths,
|
|
5
5
|
prepareTileflowStyleFonts,
|
|
6
6
|
replaceTileflowStyleFontSources
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-FOMTSCOP.js";
|
|
8
|
+
import "./chunk-RTU7TD4M.js";
|
|
9
9
|
import "./chunk-D4OE4ITL.js";
|
|
10
10
|
export {
|
|
11
11
|
TileflowFontCompilationError,
|
package/dist/icons.js
CHANGED
|
@@ -17,8 +17,8 @@ import {
|
|
|
17
17
|
storeTileflowIconSetArtifact,
|
|
18
18
|
verifyTileflowIconArtifact,
|
|
19
19
|
writeTileflowIconsLockfile
|
|
20
|
-
} from "./chunk-
|
|
21
|
-
import "./chunk-
|
|
20
|
+
} from "./chunk-C4VPHZ3F.js";
|
|
21
|
+
import "./chunk-RTU7TD4M.js";
|
|
22
22
|
export {
|
|
23
23
|
TileflowIconCompilationError,
|
|
24
24
|
compileTileflowIconPackages,
|
package/dist/preview.js
CHANGED
|
@@ -272,8 +272,8 @@ function renderTileflowPreviewHtml(preview, basePath, initialStatus, isSemanticP
|
|
|
272
272
|
import * as maplibregl from "${basePath}/__runtime/maplibre-gl.mjs";
|
|
273
273
|
import {createPreviewObserver} from "${basePath}/__runtime/inspector-observer.js";
|
|
274
274
|
import {loadTileflowStyleFonts} from "${basePath}/__runtime/tileflow-browser.js";
|
|
275
|
-
import {attachTileflowLabelPlacement} from "${basePath}/__runtime/tileflow-browser.js";
|
|
276
|
-
import {registerTileflowContourProtocol} from "${basePath}/__runtime/tileflow-browser.js";
|
|
275
|
+
import {attachTileflowHorizonQueries, attachTileflowLabelPlacement} from "${basePath}/__runtime/tileflow-browser.js";
|
|
276
|
+
import {registerTileflowContourProtocol, registerTileflowPathGroundProtocol} from "${basePath}/__runtime/tileflow-browser.js";
|
|
277
277
|
import {registerTileflowPmtilesProtocol} from "${basePath}/__runtime/tileflow-browser.js";
|
|
278
278
|
import {attachTileflowNauticalLights, attachTileflowNotices} from "${basePath}/__runtime/tileflow-browser.js";
|
|
279
279
|
import {attachTileflowAtmosphere, tileflowMaxPitch} from "${basePath}/__runtime/tileflow-browser.js";
|
|
@@ -1674,6 +1674,7 @@ function renderTileflowPreviewHtml(preview, basePath, initialStatus, isSemanticP
|
|
|
1674
1674
|
maplibregl.setWorkerCount?.(mapWorkerCount);
|
|
1675
1675
|
await loadTileflowStyleFonts(styleUrl, {fontFaces: previewFontFaces});
|
|
1676
1676
|
registerTileflowContourProtocol({addProtocol: maplibregl.addProtocol});
|
|
1677
|
+
registerTileflowPathGroundProtocol({addProtocol: maplibregl.addProtocol});
|
|
1677
1678
|
registerTileflowPmtilesProtocol({addProtocol: maplibregl.addProtocol});
|
|
1678
1679
|
const map = new maplibregl.Map({
|
|
1679
1680
|
canvasContextAttributes: tileflowCanvasContextAttributes({antialias: mapAntialias}),
|
|
@@ -1689,6 +1690,7 @@ function renderTileflowPreviewHtml(preview, basePath, initialStatus, isSemanticP
|
|
|
1689
1690
|
attachTileflowNauticalLights(map);
|
|
1690
1691
|
attachTileflowAtmosphere(map);
|
|
1691
1692
|
attachTileflowLabelPlacement(map);
|
|
1693
|
+
attachTileflowHorizonQueries(map);
|
|
1692
1694
|
inspectorObserver?.attach(map);
|
|
1693
1695
|
installMapBenchmark(map);
|
|
1694
1696
|
if (window.parent === window) map.addControl(new maplibregl.NavigationControl(), "top-right");
|
package/dist/server.js
CHANGED
|
@@ -5,16 +5,16 @@ import {
|
|
|
5
5
|
parseTileflowLineBackgroundGlyphPath,
|
|
6
6
|
tileflowArtifactSessionSchemaVersion,
|
|
7
7
|
tileflowLineBackgroundGlyphRoute
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-AVJMTXW5.js";
|
|
9
9
|
import {
|
|
10
10
|
getTileflowAssetBasePath,
|
|
11
11
|
getTileflowAssetFileName,
|
|
12
12
|
joinTileflowPublicUrl,
|
|
13
13
|
normalizeTileflowBasePath,
|
|
14
14
|
resolveTileflowArtifactPublicUrls
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
15
|
+
} from "./chunk-FOMTSCOP.js";
|
|
16
|
+
import "./chunk-C4VPHZ3F.js";
|
|
17
|
+
import "./chunk-RTU7TD4M.js";
|
|
18
18
|
import {
|
|
19
19
|
TileflowStyleValidationError
|
|
20
20
|
} from "./chunk-KDFTE4Q5.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tileflow/dev",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.39",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Node development utilities for Tileflow configs and builds.",
|
|
6
6
|
"type": "module",
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
"files": [
|
|
28
28
|
"dist",
|
|
29
29
|
"ui-fonts",
|
|
30
|
-
"docs",
|
|
31
30
|
"THIRD_PARTY_NOTICES.md",
|
|
32
31
|
"LICENSE"
|
|
33
32
|
],
|
|
@@ -84,8 +83,8 @@
|
|
|
84
83
|
"dependencies": {
|
|
85
84
|
"@mapbox/vector-tile": "3.0.0",
|
|
86
85
|
"@maplibre/maplibre-gl-style-spec": "26.4.4",
|
|
87
|
-
"@tileflow/core": ">=0.1.0-alpha.
|
|
88
|
-
"chokidar": "
|
|
86
|
+
"@tileflow/core": ">=0.1.0-alpha.43 <0.1.0-beta.0",
|
|
87
|
+
"chokidar": "6.0.0",
|
|
89
88
|
"fontkit": "2.0.4",
|
|
90
89
|
"jiti": "^2.7.0",
|
|
91
90
|
"maplibre-gl": "6.13.0",
|
|
@@ -96,7 +95,7 @@
|
|
|
96
95
|
"three": "0.185.1"
|
|
97
96
|
},
|
|
98
97
|
"devDependencies": {
|
|
99
|
-
"@tileflow/maps": "0.1.0-alpha.
|
|
98
|
+
"@tileflow/maps": "0.1.0-alpha.17"
|
|
100
99
|
},
|
|
101
100
|
"optionalDependencies": {
|
|
102
101
|
"sharp": "0.35.5"
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
# Artifact lifecycle
|
|
2
|
-
|
|
3
|
-
Start with the [@tileflow/dev guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/dev/README.md) for installation and a complete first example.
|
|
4
|
-
|
|
5
|
-
Node utilities used by the Tileflow CLI and build integrations.
|
|
6
|
-
|
|
7
|
-
Most apps should use `tileflow`, `@tileflow/vite`, or `@tileflow/next` directly. Use this
|
|
8
|
-
package when you are building a custom dev server, bundler plugin, or deployment adapter that needs
|
|
9
|
-
to load and compile the single map exported by `tileflow.config.ts`.
|
|
10
|
-
|
|
11
|
-
```ts
|
|
12
|
-
import {createTileflowBuildArtifacts} from '@tileflow/dev/artifacts';
|
|
13
|
-
|
|
14
|
-
const artifacts = await createTileflowBuildArtifacts({
|
|
15
|
-
config: 'tileflow.config.ts',
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
// Serve, capture, or write this exact generation.
|
|
20
|
-
} finally {
|
|
21
|
-
await artifacts.dispose?.();
|
|
22
|
-
}
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
The integration surfaces are deliberately split: use `@tileflow/dev/artifacts` for source
|
|
26
|
-
preparation and production outputs, `@tileflow/dev/server` for HTTP development handling,
|
|
27
|
-
`@tileflow/dev/icons` for icon compilation, `@tileflow/dev/inspect` for safe resolved-config and
|
|
28
|
-
bounded feature inspection, `@tileflow/dev/validation` for structured diagnostics, and
|
|
29
|
-
`@tileflow/dev/preview` only for the local preview contract. The package has no root entry point.
|
|
30
|
-
|
|
31
|
-
Artifact construction is an explicit `source map → resolved map → prepared map → ArtifactPlan`
|
|
32
|
-
pipeline. Map inheritance resolves before its ordered local/package icon and font directories are
|
|
33
|
-
prepared, and before the result reaches the core style compiler. The Node layer may normalize
|
|
34
|
-
the map into an internal build catalog, but that catalog is orchestration state rather than another
|
|
35
|
-
public authoring model. The plan exposes its complete files and observed input graph, so build
|
|
36
|
-
adapters emit and watch the same generation instead of reconstructing either list themselves. Production manifests
|
|
37
|
-
point to content-addressed `generations/<sha256>/...` theme styles and sprites; those immutable files are
|
|
38
|
-
installed before the manifest pointer changes. Stable style paths are
|
|
39
|
-
`styles/<map>/<theme>.json`; every manifest lookup resolves a concrete theme. The disk writer also stages the complete plan,
|
|
40
|
-
records a managed-file inventory, rolls back caught filesystem failures, and removes only stale
|
|
41
|
-
files named by its previous valid inventory. Stable `styles/` and `icons/` paths remain available,
|
|
42
|
-
but generation-consistent consumers resolve maps through `manifest.json`.
|
|
43
|
-
|
|
44
|
-
A local `hostedTileset()` path remains user-owned input. Dev performs bounded header, root-directory,
|
|
45
|
-
and metadata checks, then creates an opaque immutable snapshot under
|
|
46
|
-
`.tileflow/cache/pmtiles-snapshots/v1/`, using copy-on-write cloning when available and a safe copy
|
|
47
|
-
otherwise. It does not hash the complete archive or traverse every leaf directory. Dev and Capture
|
|
48
|
-
read only that snapshot. The current generation and already-started acquisitions retain references;
|
|
49
|
-
a replaced generation accepts no new acquisitions and is collected after its last acquisition.
|
|
50
|
-
The Style-facing path remains `tilesets/<logical-id>.pmtiles` across generations; physical snapshot
|
|
51
|
-
identity stays out of Style JSON. Standalone Capture retains one generation for the complete render.
|
|
52
|
-
Application Capture delegates PMTiles reads to the application's development server, where each
|
|
53
|
-
range request retains its generation until that response is prepared; it does not lease one
|
|
54
|
-
generation for the complete capture. Strong generation ETags make a cached PMTiles read restart if
|
|
55
|
-
current changes between its ranges. Invalid edits keep the prior valid generation.
|
|
56
|
-
|
|
57
|
-
Production writers reject unresolved local PMTiles instead of copying, content-addressing,
|
|
58
|
-
deduplicating, retaining, or publishing them. Production data therefore requires an explicit
|
|
59
|
-
`tileset publish` operation or an application-owned PMTiles location. Managed publication owns its
|
|
60
|
-
separate exhaustive validation and version lifecycle. Startup removes snapshot generations owned
|
|
61
|
-
by dead processes, and symlinked snapshot-store boundaries are rejected.
|
|
62
|
-
|
|
63
|
-
Every plan also emits canonical `build-manifest.json` (schema version 1). For each map it records
|
|
64
|
-
the leaf `mapVersion`, resolved lineage, effective icon/font source identities, semantic compiler ABI, and
|
|
65
|
-
one entry per concrete theme with `colorScheme`, identity, inferred legacy `dataRequirements`,
|
|
66
|
-
multi-source `sourceRequirements`, and `styleSha256`. The multi-source contract records each
|
|
67
|
-
referenced vector source independently and records raster DEM source ID, encoding, and tile size;
|
|
68
|
-
it therefore distinguishes Bathymetry vector bands from optional relief without inventing vector
|
|
69
|
-
fields. `mapRevisionSha256` identifies the effective cartographic definition after `extends`;
|
|
70
|
-
`assetSetSha256` for that map's generated runtime resources. Data requirements are derived from the
|
|
71
|
-
final Style layers and fields rather than copied from a manually maintained allowlist, so disabled
|
|
72
|
-
or overridden modules do not claim data they no longer use. Maps use the single implicit semantic
|
|
73
|
-
compiler; its ABI remains a separate `semanticCompiler: {name, version}` build-manifest axis.
|
|
74
|
-
|
|
75
|
-
The map revision is versioned and domain-separated. It contains the resolved cartographic design,
|
|
76
|
-
semantic language version, effective public module/render-stack design, and effective icon/font
|
|
77
|
-
identities. Map `id`, `name`, editorial `mapVersion`, default `view`, capture `scenes`, package
|
|
78
|
-
SemVer, compiler ABI, local paths, timestamps, generated sprite/font output, and a
|
|
79
|
-
concrete resolution of a floating World selector are deliberately outside it. Changing a shadowed
|
|
80
|
-
ancestor does not change the revision; changing an effective cartographic override or source asset
|
|
81
|
-
does. Lineage and the leaf `mapVersion` remain beside the hash for traceability, and Style JSON owns
|
|
82
|
-
its compiled-output identity. Hosted browser policy is managed outside repository artifacts. The
|
|
83
|
-
top-level `provenance` block records the exact participating Tileflow package versions and the
|
|
84
|
-
nearest package-manager lockfile's format and content hash, without embedding its local path;
|
|
85
|
-
provenance remains outside every map revision. The same portable block is available to Hosted
|
|
86
|
-
adapters through
|
|
87
|
-
`createTileflowBuildProvenance(cwd)`. The dev server exposes the complete document at
|
|
88
|
-
`/build-manifest.json`.
|
|
89
|
-
|
|
90
|
-
`createTileflowStyle`, `createTileflowStyles`, and artifact construction all enforce the same
|
|
91
|
-
recursive JSON-value invariant and MapLibre style-spec semantics without fetching remote resources.
|
|
92
|
-
The family API returns `styles[map][theme]`; it never flattens a default theme into a map alias.
|
|
93
|
-
Invalid output throws `TileflowStyleValidationError` with at most 32 deterministic
|
|
94
|
-
`map`/`path`/`message` issues; layer indexes are projected to stable layer IDs.
|
|
95
|
-
|
|
96
|
-
For a watched, last-known-good integration, use one artifact session rather than recompiling each
|
|
97
|
-
request independently:
|
|
98
|
-
|
|
99
|
-
```ts
|
|
100
|
-
import {createTileflowArtifactSession} from '@tileflow/dev/artifacts';
|
|
101
|
-
|
|
102
|
-
const session = await createTileflowArtifactSession({
|
|
103
|
-
config: 'tileflow.config.ts',
|
|
104
|
-
watch: true,
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
const unsubscribe = session.subscribe((state) => {
|
|
108
|
-
// building -> ready, or invalid while getLastGoodArtifacts() remains available
|
|
109
|
-
console.log(state.status, state.generation);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
unsubscribe();
|
|
113
|
-
await session.close();
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
`getState()` and `getLastGoodArtifacts()` are borrowed synchronous views. Before starting async
|
|
117
|
-
work, call `session.acquireArtifacts(generation?)` and release the returned acquisition in `finally`.
|
|
118
|
-
A replacement stops new acquisitions of the old generation and deletes its snapshot after the last
|
|
119
|
-
release. `close()` waits for outstanding acquisitions.
|
|
120
|
-
|
|
121
|
-
The bounded watcher follows the config, transitive local TypeScript/JavaScript/JSON imports, and
|
|
122
|
-
effective local icon/font directory inputs. Generations are monotonic, overlapping refreshes are latest-wins, invalid
|
|
123
|
-
edits retain the last good snapshot, and caller-supplied output directories can be ignored to avoid
|
|
124
|
-
feedback loops. `tileflow preview`, `capture --watch`, and
|
|
125
|
-
framework adapters use this shared status
|
|
126
|
-
vocabulary. The built-in preview reloads after its live event stream reconnects following a server
|
|
127
|
-
restart, even when the replacement process begins again at generation 1.
|
|
128
|
-
|
|
129
|
-
Custom preview servers use the exported map or one of its standalone scenes:
|
|
130
|
-
|
|
131
|
-
```ts
|
|
132
|
-
import {createTileflowDevRequestHandler} from '@tileflow/dev/server';
|
|
133
|
-
|
|
134
|
-
const fetch = createTileflowDevRequestHandler({
|
|
135
|
-
config: 'tileflow.config.ts',
|
|
136
|
-
scene: 'madrid-mobile',
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
// On server shutdown:
|
|
140
|
-
await fetch.close();
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
The handler does not close a caller-owned session.
|
|
144
|
-
|
|
145
|
-
Map preview uses the exported map's `view` and accepts one concrete `theme`; scene preview uses its
|
|
146
|
-
committed concrete theme, camera, and CSS viewport metadata from that same map. A scene does not
|
|
147
|
-
repeat the map ID because its owner is implicit.
|
|
148
|
-
`resolveTileflowPreview()` exposes the validated selection for custom integrations.
|
|
149
|
-
Application-target scenes remain the responsibility of the application's development server. The
|
|
150
|
-
built-in preview records longitude, latitude, zoom, bearing, and pitch in the current URL, so browser
|
|
151
|
-
refreshes and config-triggered reloads return to the same view. Removing those query parameters
|
|
152
|
-
restores the configured camera.
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
# Beacon map audits (legacy)
|
|
2
|
-
|
|
3
|
-
The Beacon scoring and tour interface has been replaced by **Diagnostics**. See
|
|
4
|
-
[Map design diagnostics](./map-design-diagnostics.md) for the current workflow. This document
|
|
5
|
-
describes historical audit reports; its scores are not comparable with Diagnostics findings.
|
|
6
|
-
|
|
7
|
-
Open `tileflow preview`, select **Beacon**, choose **Desktop** or **Mobile** and
|
|
8
|
-
**Active tour** (default), **Quick check** or **All zooms**, then **Run audit**. The report includes 48 checks grouped into Rendering (9), Loading
|
|
9
|
-
(8), Legibility (8), Accessibility (8), Cartography (7) and Integrity (8). Expand a result for its
|
|
10
|
-
measured value, target, evidence and suggested fix. Findings open Layers, Tiles or Debug. **Copy
|
|
11
|
-
context for agent** copies the bounded report; it does not upload it.
|
|
12
|
-
|
|
13
|
-
## Scope and restoration
|
|
14
|
-
|
|
15
|
-
Active tour follows a deterministic route through the current view, London, New York, Tokyo,
|
|
16
|
-
Nairobi and São Paulo. Each location has an overview and a detailed view, with zoom, bearing and
|
|
17
|
-
pitch changes within the map's camera limits. Destinations outside explicit map bounds are skipped
|
|
18
|
-
and listed in coverage. The current theme stays active; this route does not cover every theme.
|
|
19
|
-
|
|
20
|
-
The tour has a 60-second budget: up to 55 seconds for navigation and sampling, with the remainder
|
|
21
|
-
reserved for diagnostics. Each stop measures a 1.2-second flight, waits up to two seconds for tiles,
|
|
22
|
-
then samples up to 2.4 seconds of continuous settled repaints. On a responsive map the run usually
|
|
23
|
-
takes 45–60 seconds. Slow loading can exhaust the budget: remaining views are explicitly unmeasured,
|
|
24
|
-
not passed. Synchronous analysis and restoration may add a small overhead. Reduced-motion settings
|
|
25
|
-
replace flights with jumps; the report does not claim an animated navigation measurement then.
|
|
26
|
-
|
|
27
|
-
**Tour measurements** lists the actual camera, moving/settled p95 frame intervals, sample counts,
|
|
28
|
-
remaining tile wait after navigation, and total readiness including navigation for each view.
|
|
29
|
-
Loading scores use the remaining wait, excluding scripted animation; any timed-out view fails
|
|
30
|
-
readiness. A p95 requires at least 30 intervals; coverage flags fewer than 60 settled
|
|
31
|
-
intervals. A view that did not finish loading before sampling receives no settled performance score.
|
|
32
|
-
The rendering check uses the worst qualifying per-view p95, so a slow location is not hidden by an
|
|
33
|
-
average across fast locations. Long stalls are retained. These measurements include browser
|
|
34
|
-
scheduling and other work on the machine, rather than isolated GPU execution time.
|
|
35
|
-
|
|
36
|
-
Quick check samples the current camera and concrete theme for about three seconds. It is useful
|
|
37
|
-
for static style checks and a short settled rendering sample. All zooms visits each integer zoom
|
|
38
|
-
from 0 through 22 within map limits at the same geographic centre, for every registered theme and
|
|
39
|
-
time-of-day variant. It waits up to five seconds for readiness and samples 150 ms per view. This
|
|
40
|
-
exhaustive scope can take several minutes; it is not the one-minute navigation benchmark. Use
|
|
41
|
-
**New audit** from a result to change scope or viewport.
|
|
42
|
-
|
|
43
|
-
Desktop uses an actual 1280×800 CSS iframe viewport; Mobile uses 390×844. The iframe is scaled to
|
|
44
|
-
fit the workspace. CPU, GPU and network are those of the current computer: this is not phone
|
|
45
|
-
hardware emulation. No cache clearing, network throttling or cold navigation occurs.
|
|
46
|
-
|
|
47
|
-
Camera, viewport, pixel ratio, overlays and scene are restored after completion or cancellation.
|
|
48
|
-
Moving the map interrupts the audit and keeps the user's camera. Leaving Beacon cancels the run.
|
|
49
|
-
A map replacement invalidates the run. Reports and preview changes stay local and in memory.
|
|
50
|
-
|
|
51
|
-
## Measurements and limits
|
|
52
|
-
|
|
53
|
-
- **Rendering:** inter-render p95 during continuous repaints (moving and settled windows for Active tour), native overdraw samples (saturating at
|
|
54
|
-
8 passes), eligible layer count, intercepted WebGL draw calls, CPU placement time, data-driven
|
|
55
|
-
paint-rule count, custom-renderer CPU submission time, and an observable GPU allocation estimate.
|
|
56
|
-
CPU submission is not GPU execution time. Readbacks and feature inspection are outside the frame
|
|
57
|
-
sample. GPU memory excludes inaccessible allocations; a low estimate is informational.
|
|
58
|
-
- **Loading:** unused source-layer MVT message bytes, original map-load event time, individual tile
|
|
59
|
-
sizes when exposed, view readiness, per-view transfer and request counts, compression and cache
|
|
60
|
-
observations. PMTiles archive ranges are not individual tile sizes. Resource Timing cannot prove
|
|
61
|
-
Cache-Control policy. Cached audit views are not a fresh visitor estimate.
|
|
62
|
-
- **Legibility:** observed text-placement rejections, line-label candidates, nearby repeated label
|
|
63
|
-
anchors, a scored text-size budget, approximate density, halos, configured line curvature and
|
|
64
|
-
requested language-field coverage. Rejections can result from collisions, offscreen placement or
|
|
65
|
-
line fit; the report does not pretend to know the renderer's exact rejection cause.
|
|
66
|
-
- **Accessibility:** sampled text contrast in current/night/other themes, color-vision simulation
|
|
67
|
-
heuristics, static non-text contrast, categorical color-only rules, the system motion preference,
|
|
68
|
-
and sampled label retention after temporarily setting the real canvas ratio to 3×. Contrast uses
|
|
69
|
-
evaluated colors and supported flat fill/halo backgrounds. Raster, 3D and unresolved backgrounds
|
|
70
|
-
are excluded. This is diagnostic evidence, not accessibility certification.
|
|
71
|
-
- **Cartography:** enabled zoom-range gaps, potential abrupt layer entry, road and place hierarchy
|
|
72
|
-
heuristics, scored size-rule continuity, unchanged eligible-layer counts and sampled fill coverage.
|
|
73
|
-
Naming-based hierarchy checks explicitly identify their inferred roles and exclude unmatched IDs.
|
|
74
|
-
- **Integrity:** missing icon references, actual theme coverage, hidden-layer source residency,
|
|
75
|
-
cached missing glyphs, unresolved expressions, locally unmatched filters, style-spec validation
|
|
76
|
-
and retained runtime/resource errors. Resident data is bounded; zero local matches does not mean
|
|
77
|
-
a filter never matches globally.
|
|
78
|
-
|
|
79
|
-
Samples are bounded to 4,000 rendered query results, 100 labels and 64 resident vector tiles per
|
|
80
|
-
view; feature expression checks use up to 24 candidates spread across the bounded source sample per
|
|
81
|
-
layer. Filter evidence counts only the candidates actually evaluated. Geometry is discarded after
|
|
82
|
-
observation. All-zoom style snapshots are shared per theme. Custom renderer and private MapLibre
|
|
83
|
-
observations are version-isolated and can be unavailable on unsupported renderers.
|
|
84
|
-
|
|
85
|
-
## Scores and useful comparisons
|
|
86
|
-
|
|
87
|
-
Category scores average checks with a measured score. Overall score averages measured categories.
|
|
88
|
-
Informational and unavailable checks are excluded. Legibility and Cartography show a numeric score
|
|
89
|
-
when eligible samples exist, together with the specific score basis and sample count. Each currently
|
|
90
|
-
has one scored benchmark; its other checks remain diagnostic. Their scores do not assess the entire
|
|
91
|
-
visual quality of a map.
|
|
92
|
-
A category with no measurable scores shows **—**. For numeric
|
|
93
|
-
budgets, meeting the displayed target scores 100; exceeding it by up to 1.5× scores 70, by up to 2×
|
|
94
|
-
scores 45, and beyond that scores 0. Minimum targets invert the ratio. Structural counts and cartographic heuristics are explicitly marked **Diagnostic · not scored**.
|
|
95
|
-
These include expression counts, rejected candidates, localized name fields, halos, fill coverage
|
|
96
|
-
and locally unmatched filters. They remain visible as evidence without asserting a defect.
|
|
97
|
-
Error scoring includes only resources and runtime errors observed during the audit, not prior session failures. A high score does not establish global map quality.
|
|
98
|
-
|
|
99
|
-
The two quality benchmarks use an explicit percentage, rather than the generic budget tiers:
|
|
100
|
-
|
|
101
|
-
- **Legibility / Text-size budget:** percentage of sampled labels whose evaluated `text-size` is
|
|
102
|
-
at least 10 CSS px. The threshold is a design budget, not an accessibility standard.
|
|
103
|
-
The bounded sample rotates between rendered symbol layers so dense POI layers do not monopolize it.
|
|
104
|
-
Font metrics, formatted section scaling, script, perspective and final glyph rasterization are not measured.
|
|
105
|
-
Unresolved expressions are excluded; their renderer fallback does not count as a passing size.
|
|
106
|
-
- **Cartography / Size-rule continuity:** percentage of sampled layer/view size rules without a
|
|
107
|
-
jump exceeding both 1 px and 25% of the smaller size (with a 1 px denominator floor). For line
|
|
108
|
-
width, text size and circle radius, evaluate immediately around the actual zoom stops at
|
|
109
|
-
`stop ± 0.0001`, within the layer and camera zoom bounds. Continuous interpolation and physical
|
|
110
|
-
width scaling pass, even when sizes double between integer zooms. Changes at layer entry/exit,
|
|
111
|
-
filtered-out features and stops with opacity at or below 1% on either side are excluded.
|
|
112
|
-
Each ready view checks up to 128 visible layers, four feature contexts per layer and 128 stops
|
|
113
|
-
per rule. Missing or oversized evaluations are excluded. This measures authored rule continuity,
|
|
114
|
-
not final GPU pixels, label placement or transition animations. Intentional steps can exceed
|
|
115
|
-
the budget and should be reviewed before changing them.
|
|
116
|
-
|
|
117
|
-
Only views that finished loading contribute to these scores. Each check exports `sample` with
|
|
118
|
-
`passed`, `total`, `skipped` and `unit`; category `scoreBasis` identifies what its number represents.
|
|
119
|
-
An observed outlier remains a warning even when rounding produces a high percentage. Findings
|
|
120
|
-
include the layer and camera, with the exact zoom stop for a size jump. No eligible samples means
|
|
121
|
-
unavailable, never an automatic 100. Repeated features in different views are separate observations.
|
|
122
|
-
|
|
123
|
-
Repeat with the same view, scope, device, cache conditions and browser load when comparing changes.
|
|
124
|
-
Review the evidence before acting on a warning. Copying findings supplies an agent with concrete
|
|
125
|
-
layer IDs, camera context, measured values, coverage limits and suggested investigation steps.
|
|
126
|
-
|
|
127
|
-
## Reproducible reports and future automation
|
|
128
|
-
|
|
129
|
-
Reports use `version: 4`, `scoring: "measured-evidence-v3"` and identify the deterministic tour as `protocol: "active-tour-v1"`.
|
|
130
|
-
Scenarios carry stable IDs, location, actual camera, theme, frame sample counts, p95, long-frame
|
|
131
|
-
fraction, maximum frame interval, `tileWaitMs` after navigation, end-to-end `readyMs` and observed
|
|
132
|
-
network transfer. Policy v2 excludes scripted camera time from loading scores; v1 included it.
|
|
133
|
-
Policy v3 adds the sampled text-size and rule-continuity benchmarks described above; v2 left both
|
|
134
|
-
categories entirely diagnostic. Old reports retain their original scores and must be rerun to use v3.
|
|
135
|
-
`plannedViews` and
|
|
136
|
-
`budgetExhausted` distinguish completed coverage from a partial run. Camera, viewport, DPR, duration
|
|
137
|
-
and warnings accompany the scores. Change the protocol identifier when its itinerary or sampling
|
|
138
|
-
rules change. The scoring policy is versioned separately: do not compare aggregate scores across
|
|
139
|
-
policies. The original Active tour itinerary, timing windows and thresholds for measured frame
|
|
140
|
-
performance are unchanged. There is no CI runner or GitHub integration in this feature.
|
|
141
|
-
|
|
142
|
-
For future comparisons, keep protocol, map revision, initial view, browser/device, viewport, theme,
|
|
143
|
-
DPR and cache conditions fixed. A single one-minute run is a diagnostic sample; repeated runs on a
|
|
144
|
-
controlled worker are needed before setting regression gates. The tour does not clear caches,
|
|
145
|
-
emulate mobile hardware, or prove worldwide coverage from six locations.
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# Bounded PMTiles resource inspection
|
|
2
|
-
|
|
3
|
-
Start with the [@tileflow/dev guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/dev/README.md) for installation and a complete first example.
|
|
4
|
-
|
|
5
|
-
Node tooling can inspect one local PMTiles archive without reading it completely:
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
import {inspectTileflowPmtiles} from '@tileflow/dev/tilesets';
|
|
9
|
-
|
|
10
|
-
const inspection = await inspectTileflowPmtiles('./data/stores.pmtiles', {
|
|
11
|
-
includeValues: ['category', 'status'],
|
|
12
|
-
});
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
Inspection schema 1 separates the authoritative PMTiles header and TileJSON `vector_layers` metadata
|
|
16
|
-
from deterministic bounded MVT observations. Each sampled field reports present/missing feature
|
|
17
|
-
counts, observed primitive types, capped distinct-value cardinality, numeric min/max, and explicit
|
|
18
|
-
truncation. Values are returned only for requested portable field names, with at most 32 requested
|
|
19
|
-
fields, 16 values per field, and 256 characters per string. Sampling reads at most eight tiles,
|
|
20
|
-
20,000 features, or 24 MB of tile data; `sample: false` returns only authoritative metadata and does
|
|
21
|
-
not accept `includeValues`.
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
# Bounded vector-feature inspection
|
|
2
|
-
|
|
3
|
-
Start with the [@tileflow/dev guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/dev/README.md) for installation and a complete first example.
|
|
4
|
-
|
|
5
|
-
Custom Node tooling can inspect only the features visible near a configured camera without opening
|
|
6
|
-
a browser:
|
|
7
|
-
|
|
8
|
-
```ts
|
|
9
|
-
import {inspectTileflowFeatures} from '@tileflow/dev/inspect';
|
|
10
|
-
|
|
11
|
-
const internalCatalog = artifacts.project;
|
|
12
|
-
const inspection = await inspectTileflowFeatures(internalCatalog, 'madrid', {
|
|
13
|
-
center: [-3.6927512, 40.4086555],
|
|
14
|
-
zoom: 16,
|
|
15
|
-
sourceLayers: ['poi'],
|
|
16
|
-
properties: ['name', 'category', 'type', 'icon', 'filter_rank', 'size_rank'],
|
|
17
|
-
width: 512,
|
|
18
|
-
height: 512,
|
|
19
|
-
limit: 100,
|
|
20
|
-
});
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
The inspector supports ordinary HTTP(S) vector sources and TileJSON. It bounds viewport, tile
|
|
24
|
-
count, individual/total bytes, scanned and returned features, property count/string lengths, and
|
|
25
|
-
request time; results are deduplicated and sorted deterministically. Output contains projected
|
|
26
|
-
properties, geometry summaries, safe origin/path metadata, and the configured source revision or
|
|
27
|
-
`null`. It never emits URL queries, credentials, hidden properties, response bodies, or absolute
|
|
28
|
-
paths. PMTiles and authenticated provider adapters are not currently supported by this primitive.
|
|
29
|
-
|
|
30
|
-
Deployment adapters can compile the same sources without writing them to disk:
|
|
31
|
-
|
|
32
|
-
```ts
|
|
33
|
-
import {compileTileflowIconPackages} from '@tileflow/dev/icons';
|
|
34
|
-
|
|
35
|
-
const internalCatalog = artifacts.project;
|
|
36
|
-
const result = await compileTileflowIconPackages(internalCatalog, {
|
|
37
|
-
cwd: process.cwd(),
|
|
38
|
-
target: 'hosted',
|
|
39
|
-
});
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
Streets declares `[streetsIcons]` and keeps light/dark image-token targets in that one closure.
|
|
43
|
-
Baedeker, Cívica, 1777, Siegfried, Soundings, and Blueprint declare only
|
|
44
|
-
`[baedekerIcons]`, `[civicaIcons]`, `[map1777Icons]`, `[siegfriedIcons]`,
|
|
45
|
-
`[soundingsIcons]`, and `[blueprintIcons]`, respectively. No official root composes another map's assets even though all
|
|
46
|
-
use the semantic compiler ABI. Baedeker's directory contains eight original travel-atlas patterns;
|
|
47
|
-
its browser-derived Mapterhorn contours use runtime terrain tiles and are not part of the icon
|
|
48
|
-
package. Soundings owns twenty-seven original nautical symbols and
|
|
49
|
-
patterns. Blueprint owns four technical blueprint patterns and one schematic POI node; its
|
|
50
|
-
unbundled Mapterhorn contours remain runtime terrain, and its text uses the canonical Noto Sans
|
|
51
|
-
glyph provider. An application map may inherit a root's exact array, replace it, clear it with `[]`,
|
|
52
|
-
or compose it explicitly with a spread.
|
|
53
|
-
`modules.poi.icons: false` or a disabled POI module suppresses POI icon layers without moving asset
|
|
54
|
-
ownership into dev. POI density is the numeric producer threshold 1–5; it is not an asset-provider
|
|
55
|
-
preset.
|
|
56
|
-
|
|
57
|
-
The hosted target enforces repository containment, portable icon IDs, safe SVG
|
|
58
|
-
references, deterministic ordering, and the public package limits. Package-owned directories are
|
|
59
|
-
trusted only inside their declared owning package and are exempt from config working-tree
|
|
60
|
-
containment. It returns deduplicated generated files plus a canonical manifest/content hash. Upload
|
|
61
|
-
only those generated files: source icons and absolute paths remain local.
|
|
62
|
-
|
|
63
|
-
The version-1 manifest includes `renderedIcons` in the exact sorted `iconNames` order. Each entry
|
|
64
|
-
contains SHA-256 digests for the normalized 1x and 2x RGBA cell. The digest framing includes its
|
|
65
|
-
density and dimensions, zeroes RGB only where alpha is zero, and excludes filenames/source bytes.
|
|
66
|
-
The package content hash still covers the complete canonical manifest, including all four encoded
|
|
67
|
-
file hashes. Consumers can therefore distinguish a visible per-icon change from an atlas-layout or
|
|
68
|
-
encoding-only package change without receiving the original SVG/raster file.
|
|
69
|
-
|
|
70
|
-
`compileTileflowIconPackages` retains the exact RGBA cells used to assemble each atlas, so its
|
|
71
|
-
pixel digests describe delivered pixels rather than a second render. Hosted upload services must
|
|
72
|
-
decode the submitted PNGs and reconstruct those digests independently; client-authored manifest
|
|
73
|
-
analysis is not authoritative.
|
|
74
|
-
|
|
75
|
-
Custom Node tooling can inspect the same local pipeline without walking or decoding source files a
|
|
76
|
-
second time:
|
|
77
|
-
|
|
78
|
-
```ts
|
|
79
|
-
import {inspectTileflowIconCatalogs} from '@tileflow/dev/icons';
|
|
80
|
-
|
|
81
|
-
const internalCatalog = artifacts.project;
|
|
82
|
-
const inspection = await inspectTileflowIconCatalogs(internalCatalog, {
|
|
83
|
-
cwd: process.cwd(),
|
|
84
|
-
mapNames: ['madrid'],
|
|
85
|
-
});
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
The result keeps one catalog per distinct ordered directory composition, the exact winning source
|
|
89
|
-
for every final ID, explicit same-ID replacements, config-relative source metadata, exact atlas rectangles,
|
|
90
|
-
both manifest pixel digests, and the shared compiled package. `icons: []` is represented as an
|
|
91
|
-
absent catalog. This is a local-authoring integration surface: use the hosted compilation target
|
|
92
|
-
separately for deployment compatibility, and project only the metadata needed by an external
|
|
93
|
-
protocol rather than serializing generated byte arrays accidentally.
|
|
94
|
-
|
|
95
|
-
This package is public, but it is an integration layer. Styling primitives live in
|
|
96
|
-
`@tileflow/core`, official maps and their source assets live in `@tileflow/maps`, and React
|
|
97
|
-
rendering lives in `@tileflow/react`.
|
|
98
|
-
|
|
99
|
-
Docs: https://tileflow.dev/docs
|