@tileflow/core 0.1.0-alpha.3 → 0.1.0-alpha.31

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.
Files changed (38) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +273 -26
  3. package/THIRD_PARTY_NOTICES.md +327 -0
  4. package/dist/browser.d.ts +962 -0
  5. package/dist/browser.js +6237 -0
  6. package/dist/build.d.ts +574 -0
  7. package/dist/build.js +25423 -0
  8. package/dist/capture-scene-D6soWztE.d.ts +161 -0
  9. package/dist/capture.d.ts +9 -0
  10. package/dist/capture.js +276 -0
  11. package/dist/config-reference.json +32261 -0
  12. package/dist/icon-composition-BiOTwrvD.d.ts +1331 -0
  13. package/dist/index.d.ts +1114 -162
  14. package/dist/index.js +18714 -3479
  15. package/dist/manifest-types-CTT2eLbp.d.ts +790 -0
  16. package/dist/manifest.d.ts +9 -0
  17. package/dist/manifest.js +368 -0
  18. package/dist/native-profile.d.ts +188 -0
  19. package/dist/native-profile.js +9316 -0
  20. package/dist/native.d.ts +355 -0
  21. package/dist/native.js +5552 -0
  22. package/dist/runtime.d.ts +1 -0
  23. package/dist/runtime.js +1317 -0
  24. package/docs/authoring-model.md +241 -0
  25. package/docs/capture-scenes.md +36 -0
  26. package/docs/compiled-style-performance.md +263 -0
  27. package/docs/data-is-separate-from-design.md +345 -0
  28. package/docs/globe-atmosphere.md +83 -0
  29. package/docs/hosted-session-authorization.md +108 -0
  30. package/docs/map-and-terrain-examples.md +149 -0
  31. package/docs/map-emphasis.md +89 -0
  32. package/docs/native-artifact-profile.md +145 -0
  33. package/docs/native-resource-urls.md +367 -0
  34. package/docs/public-api-and-browser-subpath.md +93 -0
  35. package/docs/shared-visual-primitives.md +81 -0
  36. package/docs/theme-transitions-and-blends.md +221 -0
  37. package/docs/themes-and-module-styles.md +83 -0
  38. package/package.json +58 -8
@@ -0,0 +1,149 @@
1
+ # Map and terrain examples
2
+
3
+ Start with the [@tileflow/core guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/README.md) for installation and a complete first example.
4
+
5
+ Typed Tileflow map contracts, semantic modules, and deterministic MapLibre style compilation.
6
+
7
+ Every public `tileflow.config.ts` exports one map. Most maps import an existing map and override only
8
+ the design fields they own:
9
+
10
+ ```ts
11
+ import {
12
+ defineMap,
13
+ defineTheme,
14
+ fixed,
15
+ labels,
16
+ poi,
17
+ roads,
18
+ token,
19
+ water,
20
+ zoom,
21
+ } from '@tileflow/core';
22
+ import {streets, streetsThemes} from '@tileflow/maps';
23
+
24
+ const madridDark = defineTheme(streetsThemes.dark, {
25
+ id: 'madrid-dark',
26
+ version: 1,
27
+ colorScheme: 'dark',
28
+ tokens: {color: {'surface.land': '#0d1320', 'surface.water': '#081e2e'}},
29
+ });
30
+
31
+ export default defineMap({
32
+ id: 'madrid',
33
+ name: 'Madrid',
34
+ version: 1,
35
+ extends: streets,
36
+ themes: {light: streetsThemes.light, dark: madridDark},
37
+ defaultTheme: 'light',
38
+ systemThemes: {light: 'light', dark: 'dark'},
39
+ projection: 'globe',
40
+ modules: {
41
+ water: water({
42
+ bodies: {
43
+ fill: {
44
+ opacity: fixed(0.95, {reason: 'Madrid keeps this water density in every theme'}),
45
+ },
46
+ },
47
+ }),
48
+ roads: roads({
49
+ detail: 'streets',
50
+ hierarchy: 'strong',
51
+ classes: {
52
+ primary: {
53
+ surface: {
54
+ fill: {
55
+ color: fixed('#E4A85B', {reason: 'Madrid brand roads stay warm in every theme'}),
56
+ width: zoom.linear([
57
+ [7, fixed(0.6, {reason: 'Madrid keeps its primary-road hierarchy across themes'})],
58
+ [16, fixed(8, {reason: 'Madrid keeps its primary-road hierarchy across themes'})],
59
+ ]),
60
+ },
61
+ },
62
+ },
63
+ secondary: {surface: {fill: {color: token.color('roads.secondary')}}},
64
+ },
65
+ }),
66
+ labels: labels({
67
+ language: 'local',
68
+ places: 'all',
69
+ roads: 'streets',
70
+ styles: {
71
+ places: {
72
+ city: {
73
+ text: {
74
+ size: fixed(18, {reason: 'Madrid keeps its city-label scale across themes'}),
75
+ haloWidth: fixed(1.5, {reason: 'Madrid keeps its city-label halo across themes'}),
76
+ },
77
+ },
78
+ },
79
+ },
80
+ }),
81
+ poi: poi({categories: ['food-drink', 'arts-entertainment', 'transport'], color: 'category'}),
82
+ },
83
+ view: {center: [-3.7038, 40.4168], pitch: 35, zoom: 12},
84
+ });
85
+ ```
86
+
87
+ Map identity and scenes belong to the leaf and do not inherit. Hosted browser policy is configured
88
+ in Tileflow and does not enter cartographic authoring or compilation.
89
+
90
+ Set `projection: 'globe'` for MapLibre's adaptive globe preset. Global zooms render as a sphere,
91
+ then transition to Mercator between zoom 10 and 12 so detailed streets remain planar. Omit the
92
+ property, or set it to `'mercator'`, for a consistently flat map.
93
+
94
+ Terrain keeps the original `'none' | 'hillshade' | '3d'` shorthand. The object form can style every
95
+ MapLibre hillshade paint control, or generate vector contours in the browser from an explicit DEM
96
+ tile template. Contours require `demUrl`, `demMaxZoom`, and zoom-indexed `[minor, index]`
97
+ `thresholds`; the raster `url` remains the separate TileJSON endpoint. Set `mode: 'none'` to compile
98
+ contours without adding a raster source, hillshade, or 3D terrain:
99
+
100
+ ```ts
101
+ terrain: {
102
+ mode: 'none',
103
+ encoding: 'terrarium',
104
+ contours: {
105
+ demUrl: 'https://terrain.example.test/{z}/{x}/{y}.webp',
106
+ demMaxZoom: 13,
107
+ maxZoom: 15,
108
+ overzoom: 2,
109
+ thresholds: {
110
+ 9: [100, 500],
111
+ 11: [50, 250],
112
+ 13: [20, 100],
113
+ 15: [10, 50],
114
+ },
115
+ minor: {
116
+ color: token.color('terrain.contour.minor'),
117
+ width: token.number('terrain.contour.minor-width'),
118
+ },
119
+ index: {
120
+ color: token.color('terrain.contour.index'),
121
+ width: token.number('terrain.contour.index-width'),
122
+ },
123
+ labels: {
124
+ color: token.color('terrain.contour.label'),
125
+ haloColor: token.color('terrain.contour.halo'),
126
+ },
127
+ },
128
+ }
129
+ ```
130
+
131
+ Declare those `terrain.*` color and number roles with the same keys in every map theme. The
132
+ compiled source is ordinary MapLibre vector data with source layer `contours`; its tile URL
133
+ contains the safely encoded DEM template and complete generation parameters. Register the generic
134
+ protocol before MapLibre reads the style. It lazily initializes the pinned, locally bundled
135
+ `maplibre-contour@0.1.0` browser module on the first contour tile; no public CDN runtime is needed.
136
+ `overzoom` may not exceed the lowest threshold zoom, so generated DEM requests never use a negative
137
+ zoom. Every index interval must be a whole multiple of its minor interval. Contour labels emit the
138
+ scaled numeric elevation without assuming a display unit. Source and layer visibility cannot begin
139
+ before the first configured threshold zoom. To bound main-thread work, effective minor intervals
140
+ must be at least 250 units at z0–4, 100 at z5–7, 50 at z8–10, 20 at z11–12, and 10 from z13 onward.
141
+ Use a trusted, size-bounded DEM tile service; the protocol intentionally accepts author-supplied
142
+ HTTP(S) templates rather than proxying or republishing terrain data.
143
+
144
+ ```ts
145
+ import maplibregl from 'maplibre-gl';
146
+ import {registerTileflowContourProtocol} from '@tileflow/core/browser';
147
+
148
+ registerTileflowContourProtocol({addProtocol: maplibregl.addProtocol});
149
+ ```
@@ -0,0 +1,89 @@
1
+ # Map emphasis
2
+
3
+ Start with the [@tileflow/core guide](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/README.md) for installation and a complete first example.
4
+
5
+ An application that draws its own content over a Tileflow map, such as a route, a selected place, or
6
+ search results, often needs the map to step back so that content reads first. Map emphasis does
7
+ that on the map's own MapLibre instance: chosen modules recede towards the map's ground colour, and
8
+ the map's labels and icons fade, except inside an area the application keeps at full strength. The
9
+ change eases in and out, stays when the theme changes, and follows a theme blend.
10
+
11
+ Emphasis needs a browser document and MapLibre GL JS. It changes only the layers a Tileflow map
12
+ compiled, so an application's own layers, such as the route it draws, keep their appearance.
13
+
14
+ ## Show an emphasis
15
+
16
+ Create the theme controller for the map, then ask for an emphasis. This example assumes an existing
17
+ MapLibre map named `map` that shows the `dark` theme of a published Tileflow map, and a route the
18
+ application has already drawn:
19
+
20
+ ```ts
21
+ import type {Map as MapLibreMap} from 'maplibre-gl';
22
+ import {createTileflowThemeController} from '@tileflow/core/browser';
23
+
24
+ export function focusOnRoute(map: MapLibreMap, styleUrl: string) {
25
+ const controller = createTileflowThemeController({
26
+ initial: {style: styleUrl, theme: 'dark'},
27
+ map,
28
+ });
29
+ void controller.setEmphasis(
30
+ {
31
+ labels: 0.6,
32
+ recede: {boundaries: 0.55, roads: 0.5, transit: 0.5},
33
+ },
34
+ {transition: {duration: 560}},
35
+ );
36
+ return () => controller.setEmphasis(undefined, {transition: {duration: 560}});
37
+ }
38
+ ```
39
+
40
+ Roads, transit, and boundaries move halfway or a little more towards the ground colour, labels and
41
+ icons keep 60 % of their opacity, and the change eases in over 560 milliseconds. Calling
42
+ `setEmphasis(undefined)` eases the map back to its design. Each call supersedes the previous one;
43
+ the promise of a superseded call resolves with `status: 'superseded'`.
44
+
45
+ ## Choose what steps back
46
+
47
+ - `recede` maps module names to an amount from 0 (as designed) to 1 (the ground colour itself). The
48
+ modules are the semantic domains a map compiles, such as `roads`, `transit`, `boundaries`,
49
+ `water`, `land`, `buildings`, and `vegetation`. Every colour of a receding layer moves towards the
50
+ ground colour, including the colours inside zoom curves and data cases. Artwork that cannot be
51
+ recoloured, such as a pattern, fades by the same amount instead.
52
+ - `labels` is the share of their opacity that the map's labels and icons keep, from 0 to 1.
53
+ - `keep` is a GeoJSON `Polygon` or `MultiPolygon`. Labels and icons whose features fall inside it
54
+ keep their full strength. It can hold up to 4,096 positions. A corridor round a route is a
55
+ typical keep area.
56
+
57
+ The ground colour is the map's background colour. During a blend it is the blended background, so
58
+ receding colours follow the hour as the blend moves.
59
+
60
+ ## How it changes over time
61
+
62
+ Values that depend only on the camera, such as a colour or an opacity with a zoom curve, ease every
63
+ frame. A value that MapLibre evaluates per feature, such as a road colour chosen by class or any
64
+ label opacity once a keep area is given, would make MapLibre lay its source out again on every
65
+ change. Such values change once, at the start of the change, under a snapshot of the map that fades
66
+ out as the transition runs. When the browser asks for reduced motion, every change happens at once.
67
+
68
+ An emphasis stays through `setTheme` and `setBlend`: after a new style is applied, the emphasis is
69
+ written again under the same cross-fade, and each blend position recomputes the receded colours.
70
+
71
+ ## How it finds modules
72
+
73
+ Every compiled layer names its semantic module in its metadata:
74
+
75
+ ```json
76
+ {"id": "tileflow-road-major-fill", "metadata": {"tileflow:domain": "roads"}}
77
+ ```
78
+
79
+ Layers that a theme blend splits or copies keep the same entry. Applications can read the key from
80
+ `tileflowLayerDomainMetadataKey` in `@tileflow/core/browser`. Physical layer IDs remain diagnostic;
81
+ use the module name instead. Styles compiled before this metadata existed have no module names, so
82
+ an emphasis leaves them unchanged.
83
+
84
+ ## Cost
85
+
86
+ Each eased frame writes only the values that changed, with `setPaintProperty` and without
87
+ validation. For a detailed city map with roads, transit, and boundaries receding, that is about 150
88
+ values a frame on a desktop computer. Writing values directly is faster than reading a MapLibre
89
+ global state from every value, because a global state change re-evaluates every layer that reads it.
@@ -0,0 +1,145 @@
1
+ # Validate native artifacts
2
+
3
+ `@tileflow/core/native-profile` checks a resolved MapLibre style against the static `native-v1`
4
+ artifact profile. It is a build-time entry point, separate from the dependency-free URL helpers in
5
+ `@tileflow/core/native`. Install Core as described in the [package README](../README.md).
6
+
7
+ This is not a mobile SDK. It does not fetch a manifest, execute a renderer, start a commercial
8
+ session, or qualify Hermes, iOS or Android. A passing result establishes static artifact checks,
9
+ not native pixels, data availability, Hosted access, publication or mobile product availability.
10
+
11
+ ## Check a style
12
+
13
+ <!-- docs:check -->
14
+
15
+ ```ts
16
+ import {validateTileflowNativeStyle} from '@tileflow/core/native-profile';
17
+
18
+ const diagnostics = validateTileflowNativeStyle({
19
+ version: 8,
20
+ sources: {},
21
+ layers: [{id: 'background', type: 'background', paint: {'background-color': '#ffffff'}}],
22
+ });
23
+
24
+ console.log(diagnostics);
25
+ ```
26
+
27
+ The result is an empty array for a style that passes this profile, or bounded structured errors.
28
+ `assertTileflowNativeStyle()` throws `TileflowNativeCompatibilityError` for the same errors.
29
+ Neither function modifies the input. Both enforce the raw input budget, even when given a style
30
+ that was already prepared. Relative resources require the explicit `documentUrl` option
31
+ and resolve against that declaring style; it is not inferred from a browser or Metro address.
32
+
33
+ Use the [Dev artifact pipeline](https://github.com/tileflow/tileflow-sdk/blob/main/packages/dev/docs/native-artifacts.md)
34
+ for authored maps. It resolves inheritance and semantic modules once, prepares icons and fonts,
35
+ checks every theme and returns a complete generation. Do not call a style validator instead of
36
+ preparing the referenced resources.
37
+
38
+ ## Profile and metadata
39
+
40
+ The exported `tileflowNativeProfile` targets MapLibre React Native 11.3.10 with Native Android 13.2.0
41
+ and iOS 6.26.0. These are static compatibility targets, not a supported application dependency matrix.
42
+ The wrapper's Style Spec version is 26.2.1. Tileflow retains its existing compiler and parser at
43
+ 24.8.5: `native-v1` checks that compiler's vocabulary and the intersection of its recorded Android
44
+ and iOS support. It does not expose every feature of Style Spec 26.2.1 or upgrade the web compiler.
45
+
46
+ The checker reads the full `sdk-support` and expression metadata from the pinned Style Spec
47
+ package's `dist/latest.json`. Its minified JavaScript exports omit that information. A missing
48
+ expression-support entry, issue link or required native version newer than either selected engine
49
+ is not evidence of support. The metadata source is the
50
+ [pinned specification](https://github.com/maplibre/maplibre-style-spec/blob/v24.8.5/src/reference/v8.json).
51
+
52
+ `tileflowNativeProfileSchema`, `tileflowNativeDiagnosticSchema`, `tileflowRendererSchema` and
53
+ `tileflowNativeBuildRecordSchema` are strict canonical Zod schemas. The map authoring grammar and
54
+ its generated language JSON are unchanged: renderer selection belongs to build tooling, not maps.
55
+
56
+ ## Included representations and explicit rejections
57
+
58
+ The profile admits fixed Mercator styles, standard vector/raster/GeoJSON/image sources, compatible
59
+ hillshade and building extrusions, one effective sprite, glyph URLs and complete prepared TTF/OTF
60
+ faces. Paint, layout and expression values must also pass the pinned semantic parser and native
61
+ support metadata. Hillshade and building extrusions do not establish 3D terrain support.
62
+
63
+ The raw style validator rejects globe or adaptive projection, terrain displacement, sky and global-state extensions,
64
+ unsupported source/layer/property values, legacy stop-function objects, browser contour and PMTiles protocols, local file URLs,
65
+ multiple sprite providers. The existing portable camera/view bounds are preserved; an artifact
66
+ does not configure a native map instance's camera constraints. It does not silently remove
67
+ an unsupported feature or replace a font. An explicit fixed-Mercator property can be omitted in the
68
+ native representation because Native has no GL JS projection controller; this does not change the
69
+ logical map revision.
70
+
71
+ Dev's `native-lowering-v1` preparation policy explicitly converts a fixed `{type: 'globe'}`
72
+ projection to Native's implicit Mercator before this validator runs. This is a recorded projection
73
+ change, not globe support or visual equivalence. One authored map serves web and native preparation;
74
+ no native-specific Streets definition is used. Preparation adapts only finite `line-cap` and
75
+ `line-dasharray` decisions into constant-property layers. Other unsupported properties have no implicit fallback. The raw validator continues to reject
76
+ unlowered unsupported expressions. See the [preparation contract](https://github.com/tileflow/tileflow-sdk/blob/main/packages/dev/docs/native-artifacts.md)
77
+ for the grammar, expansion limits and pending native visual checks. The lowering checks establish
78
+ per-feature selection and cap/dash values, not global feature draw order. A copied `line-sort-key`
79
+ cannot preserve ordering between simultaneous physical branches; overlapping features may produce
80
+ a different composition even when every property value is retained.
81
+
82
+ `native-build.json` uses strict schema version 2 and `preparationVersion: 'native-lowering-v1'`.
83
+ Its `transformations` array is ordered by map/theme and binds the input/lowered style hashes,
84
+ projection policy and physical layer spans. The runtime manifest remains version 1. An old v1
85
+ build-record decoder must reject v2 rather than silently ignore the preparation evidence.
86
+
87
+ Text must use a valid glyph template containing `{fontstack}` and `{range}`, or a complete static
88
+ font stack backed by prepared faces. Native preparation maps each exact OpenType full name to its
89
+ verified TTF/OTF URL. WOFF2 conversion, Unicode-range split providers, dynamic font-stack closure and
90
+ implicit system-font fallback are outside this artifact profile. A fallback name without a prepared
91
+ face fails instead of being silently substituted. The existing font pipeline still owns parsing,
92
+ font selection, content hashes and required licenses.
93
+
94
+ The `deferFontClosure` option is only for compiler preflight before font preparation. It deliberately
95
+ does not prove text-provider closure. The Dev pipeline always performs the final full validation
96
+ after preparation; external callers must not present a preflight result as a complete artifact check.
97
+
98
+ ## Input and prepared-style budgets
99
+
100
+ `tileflowNativeProfileLimits` and `validateTileflowNativeStyle()` keep untrusted compiler input at
101
+ **160,000 visited JSON nodes**. Dev applies this gate before lowering. The raw validator has no
102
+ option to borrow the output allowance, and preparation never retries rejected input with a larger
103
+ budget. Exceeding the input bound remains `NATIVE_UNSUPPORTED_STYLE` at the root style pointer.
104
+
105
+ `tileflowNativePreparedStyleLimits` and `validateTileflowNativePreparedStyle()` use a separate fixed
106
+ ceiling of **540,000 nodes** for the expanded representation. The latter performs the same semantic,
107
+ source, font and URL checks; it does not lower a style, relax unsupported properties or establish
108
+ that the input came from a trusted build. Use it to check prepared artifact JSON, not as the entry
109
+ gate for authoring. Dev uses it after lowering, after font preparation and after generation URL
110
+ retargeting, before writing the output generation.
111
+
112
+ Both stages use the same traversal. Each object key or array index and each value counts as a
113
+ node. Both retain **8 MiB of serialized UTF-8, depth 64, 128 sources, 4,096 layers, 16 prepared font
114
+ faces and 32 returned errors**. Cycles, getters, sparse arrays, non-JSON values and `toJSON` hooks
115
+ remain invalid. The prepared budget changes only the node allowance; per-decision and per-layer
116
+ expansion limits also remain mandatory.
117
+
118
+ The measured full Streets family expands from 122,253 to 513,321 nodes for dark and from 122,163 to
119
+ 513,231 for light. The 540,000-node ceiling leaves 26,679/26,769 nodes (about 5.2%) of headroom rather
120
+ than multiplying the raw allowance arbitrarily. This accommodates the bounded prepared
121
+ representation, not unbounded growth of custom styles. Prepared font bytes retain the existing
122
+ 1 MiB per-face bound; URL, icon and sprite limits retain their owning pipelines' bounds. These are
123
+ validation-work limits, not download, GPU-memory or billing limits.
124
+
125
+ Allowing the larger prepared representation increases the maximum traversal and parser workload.
126
+ The byte, depth, layer and decision bounds still apply; there is no caller-selected unlimited
127
+ mode. The node traversal stops at its ceiling before JSON serialization and semantic parsing.
128
+ These finite limits are not a latency guarantee for every machine or a substitute for admission
129
+ controls in an application accepting arbitrary artifacts.
130
+
131
+ ## Read diagnostics
132
+
133
+ Every native diagnostic has `code`, `phase`, `severity`, `path`, `renderer`, `profile`, `message`
134
+ and `suggestion`. `path` is a JSON Pointer into the style; artifact preparation prefixes it with the
135
+ map and theme. Error messages do not include rejected URLs, parser details or credentials. Unsafe
136
+ object-key text is represented by its ancestor pointer.
137
+
138
+ - `NATIVE_UNSUPPORTED_STYLE`: incompatible style semantics or artifact shape.
139
+ - `NATIVE_UNSUPPORTED_SOURCE`: incompatible source, URL or browser protocol.
140
+ - `NATIVE_FONT_UNAVAILABLE`: missing or incompatible native text-provider closure.
141
+ - `NATIVE_MANIFEST_REQUIRED`: no declaring document URL for relative resources.
142
+ - `NATIVE_RENDERER_UNSUPPORTED`: unavailable renderer/profile or native delivery target.
143
+
144
+ Dev sessions and CLI commands retain their existing diagnostic envelopes and add the native
145
+ `renderer`/`profile` context. Unchanged web calls do not gain extra diagnostic fields.