@tileflow/dev 0.1.0-alpha.32 → 0.1.0-alpha.34

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.
@@ -1,4 +1,8 @@
1
- # Beacon map audits
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.
2
6
 
3
7
  Open `tileflow preview`, select **Beacon**, choose **Desktop** or **Mobile** and
4
8
  **Active tour** (default), **Quick check** or **All zooms**, then **Run audit**. The report includes 48 checks grouped into Rendering (9), Loading
@@ -20,8 +24,10 @@ takes 45–60 seconds. Slow loading can exhaust the budget: remaining views are
20
24
  not passed. Synchronous analysis and restoration may add a small overhead. Reduced-motion settings
21
25
  replace flights with jumps; the report does not claim an animated navigation measurement then.
22
26
 
23
- **Tour measurements** lists the actual camera, moving/settled p95 frame intervals, sample counts and
24
- readiness for each view. A p95 requires at least 30 intervals; coverage flags fewer than 60 settled
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
25
31
  intervals. A view that did not finish loading before sampling receives no settled performance score.
26
32
  The rendering check uses the worst qualifying per-view p95, so a slow location is not hidden by an
27
33
  average across fast locations. Long stalls are retained. These measurements include browser
@@ -29,7 +35,7 @@ scheduling and other work on the machine, rather than isolated GPU execution tim
29
35
 
30
36
  Quick check samples the current camera and concrete theme for about three seconds. It is useful
31
37
  for static style checks and a short settled rendering sample. All zooms visits each integer zoom
32
- from 0 through 22 within map limits at the same geographic centre, for every registered palette and
38
+ from 0 through 22 within map limits at the same geographic centre, for every registered theme and
33
39
  time-of-day variant. It waits up to five seconds for readiness and samples 150 ms per view. This
34
40
  exhaustive scope can take several minutes; it is not the one-minute navigation benchmark. Use
35
41
  **New audit** from a result to change scope or viewport.
@@ -54,7 +60,7 @@ A map replacement invalidates the run. Reports and preview changes stay local an
54
60
  observations. PMTiles archive ranges are not individual tile sizes. Resource Timing cannot prove
55
61
  Cache-Control policy. Cached audit views are not a fresh visitor estimate.
56
62
  - **Legibility:** observed text-placement rejections, line-label candidates, nearby repeated label
57
- anchors, minimum evaluated size, approximate density, halos, configured line curvature and
63
+ anchors, a scored text-size budget, approximate density, halos, configured line curvature and
58
64
  requested language-field coverage. Rejections can result from collisions, offscreen placement or
59
65
  line fit; the report does not pretend to know the renderer's exact rejection cause.
60
66
  - **Accessibility:** sampled text contrast in current/night/other themes, color-vision simulation
@@ -63,7 +69,7 @@ A map replacement invalidates the run. Reports and preview changes stay local an
63
69
  evaluated colors and supported flat fill/halo backgrounds. Raster, 3D and unresolved backgrounds
64
70
  are excluded. This is diagnostic evidence, not accessibility certification.
65
71
  - **Cartography:** enabled zoom-range gaps, potential abrupt layer entry, road and place hierarchy
66
- heuristics, adjacent-zoom size changes, unchanged eligible-layer counts and sampled fill coverage.
72
+ heuristics, scored size-rule continuity, unchanged eligible-layer counts and sampled fill coverage.
67
73
  Naming-based hierarchy checks explicitly identify their inferred roles and exclude unmatched IDs.
68
74
  - **Integrity:** missing icon references, actual theme coverage, hidden-layer source residency,
69
75
  cached missing glyphs, unresolved expressions, locally unmatched filters, style-spec validation
@@ -71,17 +77,48 @@ A map replacement invalidates the run. Reports and preview changes stay local an
71
77
  a filter never matches globally.
72
78
 
73
79
  Samples are bounded to 4,000 rendered query results, 100 labels and 64 resident vector tiles per
74
- view; feature expression checks use up to 24 candidates per layer. Geometry is discarded after
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
75
82
  observation. All-zoom style snapshots are shared per theme. Custom renderer and private MapLibre
76
83
  observations are version-isolated and can be unavailable on unsupported renderers.
77
84
 
78
85
  ## Scores and useful comparisons
79
86
 
80
87
  Category scores average checks with a measured score. Overall score averages measured categories.
81
- Informational and unavailable checks are excluded; an unmeasured category shows **—**. For numeric
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
82
93
  budgets, meeting the displayed target scores 100; exceeding it by up to 1.5× scores 70, by up to 2×
83
- scores 45, and beyond that scores 0. Minimum targets invert the ratio. Diagnostic findings may use
84
- review scores rather than numeric budgets. A high score does not establish global map quality.
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.
85
122
 
86
123
  Repeat with the same view, scope, device, cache conditions and browser load when comparing changes.
87
124
  Review the evidence before acting on a warning. Copying findings supplies an agent with concrete
@@ -89,12 +126,18 @@ layer IDs, camera context, measured values, coverage limits and suggested invest
89
126
 
90
127
  ## Reproducible reports and future automation
91
128
 
92
- Reports use `version: 3` and identify the deterministic tour as `protocol: "active-tour-v1"`.
129
+ Reports use `version: 4`, `scoring: "measured-evidence-v3"` and identify the deterministic tour as `protocol: "active-tour-v1"`.
93
130
  Scenarios carry stable IDs, location, actual camera, theme, frame sample counts, p95, long-frame
94
- fraction, maximum frame interval, readiness and observed network transfer. `plannedViews` and
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
95
136
  `budgetExhausted` distinguish completed coverage from a partial run. Camera, viewport, DPR, duration
96
137
  and warnings accompany the scores. Change the protocol identifier when its itinerary or sampling
97
- rules change. There is no CI runner or GitHub integration in this feature.
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.
98
141
 
99
142
  For future comparisons, keep protocol, map revision, initial view, browser/device, viewport, theme,
100
143
  DPR and cache conditions fixed. A single one-minute run is a diagnostic sample; repeated runs on a
@@ -40,13 +40,12 @@ const result = await compileTileflowIconPackages(internalCatalog, {
40
40
  ```
41
41
 
42
42
  Streets declares `[streetsIcons]` and keeps light/dark image-token targets in that one closure.
43
- Baedeker, Cívica, Ferraris, Härad, Siegfried, Soundings, and Blueprint declare only
44
- `[baedekerIcons]`, `[civicaIcons]`, `[ferrarisIcons]`, `[haradIcons]`, `[siegfriedIcons]`,
43
+ Baedeker, Cívica, 1777, Siegfried, Soundings, and Blueprint declare only
44
+ `[baedekerIcons]`, `[civicaIcons]`, `[map1777Icons]`, `[siegfriedIcons]`,
45
45
  `[soundingsIcons]`, and `[blueprintIcons]`, respectively. No official root composes another map's assets even though all
46
46
  use the semantic compiler ABI. Baedeker's directory contains eight original travel-atlas patterns;
47
47
  its browser-derived Mapterhorn contours use runtime terrain tiles and are not part of the icon
48
- package. Härad's directory contains nine original Tileflow patterns inspired by Lantmäteriet's CC0
49
- Häradsekonomiska kartan series from 1859–1934. Soundings owns ten original nautical symbols and
48
+ package. Soundings owns eleven original nautical symbols and
50
49
  patterns. Blueprint owns four technical blueprint patterns and one schematic POI node; its
51
50
  unbundled Mapterhorn contours remain runtime terrain, and its text uses the canonical Noto Sans
52
51
  glyph provider. An application map may inherit a root's exact array, replace it, clear it with `[]`,
@@ -0,0 +1,179 @@
1
+ # Prepare recolorable building models
2
+
3
+ Custom buildings and landmarks use the same preparation path. Export uncompressed glTF 2.0
4
+ binaries in metres, Y up, with the origin on the ground. The default scene's triangles and node
5
+ transforms are read. Building preparation retains physical materials and embedded PNG/JPEG
6
+ textures. Animations, skins and morph targets are not evaluated; export their static geometry.
7
+
8
+ ## Separate colour from architectural role
9
+
10
+ Material names select a palette slot: `surface`, `secondary`, `glass`, `accent` or `roof`.
11
+ The optional `material.extras.tileflow.lightingRole` selects lighting independently:
12
+
13
+ ```json
14
+ {
15
+ "name": "accent",
16
+ "extras": {
17
+ "tileflow": {
18
+ "lightingRole": "door"
19
+ }
20
+ },
21
+ "pbrMetallicRoughness": {
22
+ "baseColorFactor": [0.8, 0.8, 0.8, 1]
23
+ }
24
+ }
25
+ ```
26
+
27
+ This door can take the map's `accent` colour while receiving its `door` lighting profile. Accepted
28
+ roles are `unclassified`, `wall`, `door`, `roof`, `window`, `lamp` and `logo`. A role describes
29
+ geometry; it does not turn on light by itself. The map supplies emission through
30
+ `buildings.threeDimensional.modelLighting`.
31
+
32
+ Legacy models without an explicit role use these defaults:
33
+
34
+ | Palette slot | Lighting role |
35
+ | -------------------------------- | ------------- |
36
+ | `surface`, `secondary`, `accent` | `wall` |
37
+ | `glass` | `window` |
38
+ | `roof` | `roof` |
39
+
40
+ Doors, lamps and logos require an explicit role. Use `unclassified` for a part that must not inherit
41
+ a role. Invalid role names fail preparation. An exporter's numeric material suffix, such as
42
+ `surface.001`, is ignored.
43
+
44
+ Keep a stone relief in a wall role when it should receive the wall's lighting. A separate colour
45
+ slot can distinguish its stone without creating a separate light source. Mark roof geometry as
46
+ roof even when it shares a colour with a facade.
47
+
48
+ ## Physical materials
49
+
50
+ The importer retains these glTF 2.0 channels independently of palette and role:
51
+
52
+ | Channel | Inputs |
53
+ | ------------------ | --------------------------------------------------------------------------------- |
54
+ | Base colour | Linear `baseColorFactor`, linear `COLOR_0` RGB/RGBA, sRGB base-colour texture |
55
+ | Reflection | `metallicFactor`, `roughnessFactor`, texture blue/green channels |
56
+ | Surface normal | Tangent-space normal texture and `scale`; tangent basis from geometry and UVs |
57
+ | Ambient visibility | Occlusion texture red channel and `strength`, multiplied by geometric visibility |
58
+ | Emission | Linear `emissiveFactor`, sRGB emissive texture, `KHR_materials_emissive_strength` |
59
+ | Coverage | `OPAQUE`, `MASK` with `alphaCutoff`, or `BLEND`; `doubleSided` |
60
+ | Unlit | `KHR_materials_unlit` |
61
+
62
+ `TEXCOORD_0`, `TEXCOORD_1`, glTF sampler wrapping/filtering and `KHR_texture_transform` are retained.
63
+ Every referenced channel must have its declared UV set. UV and colour seams survive welding.
64
+ Colour textures and lit output use the scene's gamma-2.2 transfer approximation.
65
+ Role emission mixes the complete material radiance toward its target, including authored emission.
66
+ Images must be embedded in buffer views or PNG/JPEG data URIs; preparation never fetches external
67
+ images. Other image formats and physical-material extensions are not supported.
68
+
69
+ Each level accepts at most 256 distinct materials, 32 textures, 4096 pixels per image dimension
70
+ and 16,777,216 decoded image pixels in total. The complete prepared file remains limited to 16 MiB.
71
+ Invalid references, missing UVs and image headers that disagree with their dimensions fail preparation.
72
+
73
+ Without overrides, a physical model retains its authored material. `modelLighting` can tint and
74
+ override roughness/metallicity by role. Explicit `modelColors` take precedence over role tints;
75
+ textures and vertex colours still modulate the chosen colour. Keep vertex colours neutral when
76
+ they should not affect recolouring.
77
+
78
+ Colour and normal textures, metallic reflection and alpha coverage use the browser's physical
79
+ model path. Ambient visibility never attenuates solar light or emission. Masked pixels also leave
80
+ holes in dynamic solar shadows; blended surfaces cast an alpha-tested shadow at 0.5. Transparent
81
+ material ranges draw back to front after opaque surfaces; intersecting transparent triangles are
82
+ not sorted individually.
83
+
84
+ ## Explicit area emitters
85
+
86
+ A `door` role lights the surface. To project its spill, declare a rectangle in
87
+ `node.extras.tileflow.emitters`. This glTF fragment uses node-local metres and Y up:
88
+
89
+ ```json
90
+ {
91
+ "extras": {
92
+ "tileflow": {
93
+ "emitters": [
94
+ {
95
+ "start": [-1, 0, 0],
96
+ "end": [1, 0, 0],
97
+ "height": 3,
98
+ "depth": 0.2,
99
+ "role": "door",
100
+ "part": "accent"
101
+ }
102
+ ]
103
+ }
104
+ }
105
+ }
106
+ ```
107
+
108
+ `start` and `end` form the horizontal lower edge. The spill faces the right of that edge when
109
+ viewed from above. `height` sets the rectangle's height; optional `depth` narrows the spill around
110
+ recessed jambs. Node transforms apply to the emitter. Its role supplies emission and its part
111
+ supplies the fallback palette colour. No emitter is inferred from material colour or geometry.
112
+
113
+ Each level accepts 128 emitters. Each projects a four-triangle, depth-tested spill with reach
114
+ `clamp(1.3 * height, 4, 10)` metres. This authored effect does not cast a new light or shadow onto
115
+ other meshes. It follows the model's visibility and theme; zero emission removes it.
116
+
117
+ ## Ambient visibility
118
+
119
+ Preparation estimates each vertex's local ambient visibility using 48 deterministic,
120
+ cosine-weighted hemisphere samples, a two-metre reach and a two-millimetre origin bias. A spatial
121
+ hierarchy limits intersection work; repeated positions and normals share samples. Nearby
122
+ occluders contribute more than distant ones. Each level is prepared independently, including
123
+ occlusion between its distinct primitives. Footprint meshes do not occlude.
124
+
125
+ The result travels independently of colour. Do not bake ambient occlusion into `COLOR_0`: colour
126
+ also affects direct sunlight and emission. The runtime applies prepared visibility only to the
127
+ ambient contribution; solar visibility still comes from the dynamic shadow map.
128
+
129
+ `threeDimensional.modelOcclusion` controls strength from zero to one and defaults to `0.75`.
130
+ `threeDimensional.occlusion: false` also disables model ambient occlusion. Changing these
131
+ runtime controls does not prepare the geometry again.
132
+
133
+ Preparation cost grows with unique vertices, samples and nearby geometry. It is paid when a raw
134
+ model is prepared, never per frame. Runtime occlusion adds no draw pass or texture and uses the
135
+ existing visibility byte. It describes opaque geometry at rest; it does not follow moving parts,
136
+ other models, the ground or surrounding buildings.
137
+
138
+ ## Files and compatibility
139
+
140
+ Use `<id>.glb`, optionally `<id>.mid.glb` and `<id>.far.glb`. A mesh whose material is `footprint`
141
+ defines the area replaced by the model and is not drawn. Otherwise preparation derives a footprint.
142
+ See the [Core building guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/docs/buildings-3d.md)
143
+ for placement and limits.
144
+
145
+ Prepared files retain a 16-byte vertex:
146
+
147
+ | Bytes | Content |
148
+ | ----- | -------------------------------- |
149
+ | 0–5 | Quantized position |
150
+ | 6–7 | Padding |
151
+ | 8–10 | Normal |
152
+ | 11 | Padding |
153
+ | 12 | Palette slot |
154
+ | 13 | Shade within that slot |
155
+ | 14 | Ambient visibility, 0–255 |
156
+ | 15 | Architectural lighting role, 0–6 |
157
+
158
+ The model root's `extras.tileflow.lightingRoles: 1` declares the last byte. Older files without
159
+ that marker use the legacy palette mapping. Existing fully exposed visibility values stay fully
160
+ exposed; reprepare the original GLBs to obtain geometric occlusion. Geometry, normals and palette
161
+ slots are not modified by the visibility calculation.
162
+
163
+ Roles and visibility survive meshoptimizer compression. The existing `_PAINT` accessor and vertex
164
+ stride are retained; the role occupies previously unused padding. Prepared files are an SDK
165
+ transport format, while material extras are the authoring interface.
166
+
167
+ Physical data is optional `extras.tileflow.surface` metadata on each level, with `version: 1`.
168
+ Two VEC4 accessors address a separate 32-byte stream: UV0/UV1 followed by linear vertex RGBA.
169
+ The metadata also holds material draw ranges, channel references, embedded images and emitters.
170
+ Ranges preserve each source mesh's vertical emission bounds independently of its material.
171
+ The original primitive layout remains unchanged. Older readers draw its legacy geometry and
172
+ palette; they ignore the optional physical data. New readers preserve the legacy shading path
173
+ when physical data is absent. Reprepare source GLBs to obtain the new channels.
174
+
175
+ The auxiliary stream costs 32 bytes per retained vertex on the GPU. Each resident texture uses
176
+ four bytes per pixel, plus about one third for mipmaps when enabled. Decoded images stay available
177
+ for context restoration until the model is evicted. Physical materials add one draw per material
178
+ range per colour/shadow pass; explicit emitters add one four-triangle draw each. No environment
179
+ cube map or screen-space effect is required.
@@ -26,6 +26,11 @@ returns. The Layers tab remains in the existing `tab=layers` parameter.
26
26
 
27
27
  ## Read the evidence
28
28
 
29
+ Open **Diagnosis** in the selected layer's detail tabs. With a picked feature or a
30
+ Data sample, it explains the filter result and any evaluated zero-size or zero-opacity components.
31
+ A zero component is not proof that the whole layer is invisible. Diagnostics findings can open a
32
+ specific paint, layout or filter declaration directly in Rules, highlighting its row.
33
+
29
34
  - **Diagnosis** reports presence, declared visibility, the inclusive minimum/exclusive maximum zoom
30
35
  range, source loading, shared source tiles and viewport-query observations. Pixel visibility,
31
36
  occlusion, transparency and depth are explicitly unmeasured. Later draw calls do not necessarily
@@ -68,7 +73,7 @@ change original paint, layout, source data or feature state. A highlight outline
68
73
  it is not a reconstruction of glyphs, symbols or 3D meshes. Hidden, out-of-zoom, custom and raster
69
74
  layers without queryable rendered geometry report that limitation instead of moving the camera.
70
75
 
71
- **Source tiles** opens Network filtered by source. Tile costs belong to the shared source, not to a
76
+ **Tiles** inspects tiles grouped by source. Tile costs belong to the shared source, not to a
72
77
  single style layer. Sprite and font links in Rules open Assets. Other inspection tabs remain usable
73
78
  while compilation or tile loading continues; obsolete scheduled measurements are discarded.
74
79
 
@@ -3,7 +3,7 @@
3
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
4
 
5
5
  The CLI opens Map DevTools through `tileflow preview`. It uses one map and one watched artifact
6
- session by default. A developer-tools panel groups Map, Layers, Tiles, Assets, Debug and Beacon. Camera controls
6
+ session by default. A developer-tools panel groups Map, Layers, Tiles, Assets, Debug and Diagnostics. Camera controls
7
7
  occupy a separate row below the navigation. Use the three-dot menu to dock left, right or below
8
8
  the map and choose System, Light or Dark appearance. Drag the divider to resize it; focused dividers
9
9
  also support arrow keys. Dock position and dimensions persist locally. Layer observations and highlights stay local to the preview. The map fills the remaining
@@ -41,7 +41,7 @@ the fixed scene viewport by default.
41
41
  Each side handler retains ownership of its styles, fonts, sprites, events, diagnostics, and
42
42
  last-known-good artifact generation. The comparison router owns the shell, its bundled UI fonts and
43
43
  strict dispatch to disjoint same-origin route prefixes. An optional `workbench: {url, handle}`
44
- adapter enables palette selection and browser context. Existing CLI capture-record and comparison
44
+ adapter enables theme selection and browser context. Existing CLI capture-record and comparison
45
45
  APIs remain separate from this interface. Custom servers that omit the adapter retain inspection,
46
46
  zoom-curve sampling and the sprite atlas. Explicit two-map server configurations retain synchronized
47
47
  cameras and URL-driven side-by-side/split/overlay/blink layouts without comparison controls.
@@ -116,7 +116,7 @@ traffic or other HTTP resources. Sprite and font sources remain in **Assets**.
116
116
  ### Assets and debug overlays
117
117
 
118
118
  **Assets** separates Icons, 3D models and Fonts. Icons lists registered images, including runtime
119
- additions, with lazy thumbnails and searchable IDs. Palette and time filters load the actual
119
+ additions, with lazy thumbnails and searchable IDs. Theme and time-of-day filters load the actual
120
120
  registered theme atlases; the selected icon's sidebar compares its day/night variants and links to
121
121
  consuming layers. Missing variants are marked, never synthesized from a naming convention.
122
122
 
@@ -127,4 +127,4 @@ provider and shows observed glyph ranges and consuming layers. Pending requests
127
127
  when leaving the panel; unavailable sources do not silently use a fallback font.
128
128
 
129
129
  **Debug** offers collision boxes, overdraw with a color legend, tile boundaries and real pixel-ratio
130
- controls. **Beacon** provides controlled map audits; see [Beacon map audits](./beacon-map-audits.md).
130
+ controls. **Diagnostics** lists design findings and optional drawing-cost observations; see [Map design diagnostics](./map-design-diagnostics.md).
@@ -0,0 +1,76 @@
1
+ # Map design diagnostics
2
+
3
+ Open **Diagnostics** in Map DevTools to investigate a map's rules, visual resources and current-view
4
+ composition. The list groups findings under **Readability**, **Style**, **Assets** and **Performance**.
5
+ **Problem** means a confirmed configuration or resource failure. **Review** means an observed
6
+ situation may be intentional. Counts refer to grouped findings, not quality scores.
7
+
8
+ ## Check the map
9
+
10
+ Style observations refresh after changes settle. **Check view** explicitly collects samples from
11
+ the current map and briefly profiles drawing work. It does not navigate to other cities, change the
12
+ camera, compile themes or save edits. Changing the map or leaving the panel cancels pending work.
13
+ Expensive renderer observations are not repeated continuously while editing colors or dragging.
14
+
15
+ The initial detectors cover invalid style rules, broken references and zoom ranges, unresolved
16
+ icons, verifiable text contrast, large layer stacks, potentially repeated rules and drawing work.
17
+ Findings group affected layers and keep bounded examples. A missing image must remain unresolved
18
+ after loading; images with a working fallback are not missing resources. An empty viewport or a
19
+ layer outside its zoom range does not by itself create a global problem.
20
+
21
+ Text contrast is checked only where the evaluated text and opaque halo make the color pair
22
+ verifiable. This is not a measurement of all pixels behind a label or certification that a map is
23
+ readable. Unavailable evaluation context does not become a passing observation. Size thresholds,
24
+ absence of halos and ordinary collision rejection do not establish design defects.
25
+
26
+ Performance findings are review indications. A style layer, a queried feature, a draw call and an
27
+ overdraw pass measure different things. Layer stacks are grouped by compiler provenance when it is
28
+ available; unknown ownership is not inferred from names. Equivalent drawing rules may be deliberate
29
+ casings, shadows or blending, so they are never automatically removed. Counts and short CPU samples
30
+ do not attribute GPU cost to an individual layer or establish a universal performance grade.
31
+
32
+ Native overdraw is observed only when the renderer and scene permit a meaningful measurement.
33
+ Custom rendering, terrain, sky, globe projection or active debug modes can make it unavailable. The native sample saturates
34
+ at eight passes, so an eight-pass observation is a lower bound. Sampling temporarily enables the
35
+ native debug rendering and restores it; open **Debug** explicitly to keep an overlay visible.
36
+
37
+ Drawing-work sampling requests repaints for approximately 650 ms and requires at least ten complete
38
+ frames. Compatible native overdraw sampling has a separate two-second limit. A median of at least
39
+ 1,000 draw submissions, or at least 25% of sampled pixels reaching eight passes, creates a review
40
+ finding. These are disclosed review triggers, not universal limits. Label evaluation and retained
41
+ examples are capped; reading the style and querying rendered features still depend on map size.
42
+ Detailed rule checks inspect at most 2,000 non-internal layers, while stack counts include the
43
+ whole style. Contrast sampling retains up to 5,000 symbol candidates, evaluates at most 200 of
44
+ them and keeps up to 40 eligible examples. Coverage limits remain available in the copied report.
45
+
46
+ ## Investigate a finding
47
+
48
+ Expand a row to read its evidence and limitations. **Open rule** selects the layer and focuses the
49
+ related paint, layout or filter declaration. **Show on map** uses the finding's observed context;
50
+ asset and overdraw actions open the corresponding inspection tools. Available actions depend on
51
+ the evidence. Preview changes remain temporary and share Undo/Redo and Reset all changes.
52
+
53
+ Findings retain the map revision and camera in which they were observed. Moving away is not proof
54
+ that a problem was fixed. Old view evidence is marked stale until checked again. Local dismissals
55
+ apply to a case fingerprint; changing the relevant evidence makes it reviewable again. Incomplete
56
+ checks and missing renderer capabilities are included in the copied report.
57
+
58
+ **Copy findings** and each finding's copy action include structured evidence, conditions and
59
+ temporary edits. Context is sanitized, bounded and reports omissions. Nothing is sent to an agent
60
+ automatically. The output is diagnostic evidence, not a benchmark or release certification.
61
+
62
+ ## Explain a layer's visibility
63
+
64
+ Select a layer in **Layers**, then open **Diagnosis**. It shows declared visibility,
65
+ zoom eligibility, source state and viewport-query observations. With an actual selected feature it
66
+ also evaluates its filter and relevant zero-size or zero-opacity rules. A zero component does not
67
+ prove the whole layer is invisible: a circle stroke or another symbol component may still draw.
68
+ Unknown expression context and geometry-dependent filters remain unavailable. Query matches do
69
+ not establish final pixel visibility, depth or occlusion.
70
+
71
+ ## Compatibility
72
+
73
+ The tab persists as `tab=diagnostics`. Previous `tab=beacon` links open the new panel. The former
74
+ Beacon scoring and tour interface is retired; its historical report scores are not comparable to
75
+ Diagnostics findings. Network infrastructure, platform regressions and broad map quality remain
76
+ separate concerns from these author-facing checks.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tileflow/dev",
3
- "version": "0.1.0-alpha.32",
3
+ "version": "0.1.0-alpha.34",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Node development utilities for Tileflow configs and builds.",
6
6
  "type": "module",
@@ -84,7 +84,7 @@
84
84
  "dependencies": {
85
85
  "@mapbox/vector-tile": "3.0.0",
86
86
  "@maplibre/maplibre-gl-style-spec": "26.4.4",
87
- "@tileflow/core": ">=0.1.0-alpha.35 <0.1.0-beta.0",
87
+ "@tileflow/core": ">=0.1.0-alpha.37 <0.1.0-beta.0",
88
88
  "chokidar": "4.0.3",
89
89
  "fflate": "0.8.3",
90
90
  "fontkit": "2.0.4",
@@ -97,7 +97,7 @@
97
97
  "three": "0.185.1"
98
98
  },
99
99
  "devDependencies": {
100
- "@tileflow/maps": "0.1.0-alpha.9"
100
+ "@tileflow/maps": "0.1.0-alpha.11"
101
101
  },
102
102
  "optionalDependencies": {
103
103
  "sharp": "0.35.5"