@tileflow/core 0.1.0-alpha.4 → 0.1.0-alpha.41
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/LICENSE +201 -0
- package/README.md +318 -26
- package/THIRD_PARTY_NOTICES.md +444 -0
- package/dist/3d-CzLTD0RK.d.ts +1092 -0
- package/dist/3d.d.ts +1 -0
- package/dist/3d.js +12660 -0
- package/dist/browser.d.ts +2278 -0
- package/dist/browser.js +21826 -0
- package/dist/build.d.ts +595 -0
- package/dist/build.js +29737 -0
- package/dist/capture-shot-ChPQvPyi.d.ts +291 -0
- package/dist/capture.d.ts +9 -0
- package/dist/capture.js +510 -0
- package/dist/config-reference.json +40527 -0
- package/dist/icon-composition-HUh_Lj8Z.d.ts +2516 -0
- package/dist/index.d.ts +1805 -162
- package/dist/index.js +26400 -3488
- package/dist/manifest-types-DnhSJjCM.d.ts +902 -0
- package/dist/manifest.d.ts +9 -0
- package/dist/manifest.js +449 -0
- package/dist/native-profile.d.ts +206 -0
- package/dist/native-profile.js +9339 -0
- package/dist/native.d.ts +365 -0
- package/dist/native.js +5970 -0
- package/dist/runtime.d.ts +1 -0
- package/dist/runtime.js +1445 -0
- package/dist/worker/camera-tile-worker.global.js +20 -0
- package/docs/application-tile-reading.md +86 -0
- package/docs/authoring-model.md +269 -0
- package/docs/boundary-areas-and-choropleths.md +217 -0
- package/docs/buildings-3d.md +608 -0
- package/docs/camera-moves-and-tile-cache.md +112 -0
- package/docs/capture-scenes.md +40 -0
- package/docs/capture-shots.md +173 -0
- package/docs/cartographic-defaults.md +210 -0
- package/docs/compiled-style-performance.md +286 -0
- package/docs/data-is-separate-from-design.md +610 -0
- package/docs/depth-markers.md +65 -0
- package/docs/dynamic-style-images.md +100 -0
- package/docs/globe-atmosphere.md +113 -0
- package/docs/hosted-session-authorization.md +106 -0
- package/docs/map-and-terrain-examples.md +156 -0
- package/docs/map-emphasis.md +89 -0
- package/docs/native-artifact-profile.md +152 -0
- package/docs/native-resource-urls.md +369 -0
- package/docs/nautical-marks.md +308 -0
- package/docs/public-api-and-browser-subpath.md +101 -0
- package/docs/route-drawing.md +191 -0
- package/docs/shared-visual-primitives.md +101 -0
- package/docs/street-lights.md +127 -0
- package/docs/street-sky.md +156 -0
- package/docs/style-states.md +73 -0
- package/docs/sun-and-light.md +167 -0
- package/docs/theme-transitions-and-blends.md +317 -0
- package/docs/themes-and-module-styles.md +156 -0
- package/docs/trees-3d.md +295 -0
- package/package.json +67 -8
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
# Nautical marks
|
|
2
|
+
|
|
3
|
+
The `nautical` module draws navigation marks from a `nautical-v1` vector source: buoys, beacons,
|
|
4
|
+
lighthouses, lights that flash in their rhythm, rocks and other hazards, wrecks, reefs, navigation
|
|
5
|
+
areas, routes, submarine and overhead cables, bridges with their clearances, harbours, marinas,
|
|
6
|
+
berths, small-craft facilities, inland notice boards, waterway distance marks, ports, and a
|
|
7
|
+
restrained indication of where a provider publishes marks. It is reference cartography for
|
|
8
|
+
general-purpose maps. It is not a nautical chart, and a map that draws it always shows a "Not for
|
|
9
|
+
navigation" notice.
|
|
10
|
+
|
|
11
|
+
## Enable Nautical on a map
|
|
12
|
+
|
|
13
|
+
Nautical is opt-in through the map's `marine` option. `'nautical'` adds it alone, `'chart'` adds it
|
|
14
|
+
with Bathymetry, and the object form selects or replaces each member. The official Soundings map
|
|
15
|
+
enables it with its own chart symbols; every other official map draws it with the module's default
|
|
16
|
+
symbology once the map opts in.
|
|
17
|
+
|
|
18
|
+
<!-- docs:check -->
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import {defineMap} from '@tileflow/core';
|
|
22
|
+
import {streets} from '@tileflow/maps';
|
|
23
|
+
|
|
24
|
+
export default defineMap({
|
|
25
|
+
id: 'harbour-guide',
|
|
26
|
+
version: 1,
|
|
27
|
+
extends: streets,
|
|
28
|
+
marine: 'nautical',
|
|
29
|
+
view: {center: [-1.3, 50.77], zoom: 12},
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`marine` is atomic: declaring it replaces the inherited value. Without a URL, the source is the
|
|
34
|
+
TileJSON at `/tiles/nautical/tiles.json` on the map's API base, with the style source ID
|
|
35
|
+
`tileflow-nautical`. Compiling a map that names this URL does not establish that a hosted Nautical
|
|
36
|
+
source is available to it. To use any schema-compatible source, name its TileJSON or PMTiles
|
|
37
|
+
archive and, when the TileJSON does not carry one, its attribution:
|
|
38
|
+
|
|
39
|
+
<!-- docs:check -->
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import {defineMap} from '@tileflow/core';
|
|
43
|
+
import {streets} from '@tileflow/maps';
|
|
44
|
+
|
|
45
|
+
export default defineMap({
|
|
46
|
+
id: 'harbour-guide',
|
|
47
|
+
version: 1,
|
|
48
|
+
extends: streets,
|
|
49
|
+
marine: {
|
|
50
|
+
bathymetry: false,
|
|
51
|
+
nautical: {
|
|
52
|
+
url: 'https://tiles.example.com/nautical/tiles.json',
|
|
53
|
+
attribution: '© Example © OpenStreetMap contributors',
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The selected TileJSON owns the provider credit. Core never invents a nautical provider or
|
|
60
|
+
attribution, and an explicit `attribution` replaces the one the TileJSON supplies.
|
|
61
|
+
|
|
62
|
+
## The "Not for navigation" notice
|
|
63
|
+
|
|
64
|
+
When any layer of the compiled style reads the Nautical source, the style declares a notice in its
|
|
65
|
+
`tileflow:notices` metadata:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
[
|
|
69
|
+
{
|
|
70
|
+
"id": "nautical-not-for-navigation",
|
|
71
|
+
"sources": ["tileflow-nautical"],
|
|
72
|
+
"text": "Not for navigation"
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
React, Vue, Svelte, the development preview, and standalone capture render it as a compact,
|
|
78
|
+
always-visible control beside the attribution, and keep it in step with style replacements. A map
|
|
79
|
+
that does not draw Nautical, including one whose `nautical` module is disabled, declares no notice.
|
|
80
|
+
The notice is separate from the source attribution, so the provider credit stays complete.
|
|
81
|
+
|
|
82
|
+
A direct MapLibre integration attaches the same control after constructing the map:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
import maplibregl from 'maplibre-gl';
|
|
86
|
+
import {attachTileflowNotices} from '@tileflow/core/browser';
|
|
87
|
+
|
|
88
|
+
const map = new maplibregl.Map({
|
|
89
|
+
container: 'map',
|
|
90
|
+
style: '/tileflow/styles/harbour-guide/light.json',
|
|
91
|
+
});
|
|
92
|
+
const detach = attachTileflowNotices(map, {position: 'bottom-right'});
|
|
93
|
+
// Call detach() to remove the control early; removing the map also removes it.
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`readTileflowNotices(style.metadata)` returns the bounded notices of a style for an application
|
|
97
|
+
that draws its own legend or exports images by other means. Show the notice wherever such a map is
|
|
98
|
+
displayed.
|
|
99
|
+
|
|
100
|
+
## Source layers and fields
|
|
101
|
+
|
|
102
|
+
Every feature carries `provider`, `provenance`, `edition`, `coverage`, `licence`, and `min_zoom`,
|
|
103
|
+
the first zoom at which the feature appears. `rank` (1 is the most important feature of its layer)
|
|
104
|
+
and `name` are optional. Colours are S-57 colour names, and multi-valued colours and categories are
|
|
105
|
+
comma-separated in source order, for example `black,yellow`. Clearances, depths, and heights are in
|
|
106
|
+
metres. `tileflowNauticalV1Schema` lists the field names, layers, geometry types, and known
|
|
107
|
+
providers: `openstreetmap` (coverage class `community`), `nga-list-of-lights` (`list`), and the
|
|
108
|
+
`chart` providers `noaa-office-of-coast-survey` and `usace-ienc` (U.S. Army Corps of Engineers
|
|
109
|
+
Inland ENCs). The source's TileJSON owns every provider credit.
|
|
110
|
+
|
|
111
|
+
| Source layer | Geometry | Fields the module reads |
|
|
112
|
+
| ----------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
113
|
+
| `aid` | Point | `class`, `subclass`, `category`, `color`, `rank`, `name`, `information`, `distance`, `distance_unit` |
|
|
114
|
+
| `light` | Point | `class` (`major` or `minor`), `color`, `label`, `rank`, `character`, `group`, `period_s`, `sequence` |
|
|
115
|
+
| `hazard` | Point, LineString, Polygon | `class`, `water_level`, `name` |
|
|
116
|
+
| `wreck` | Point, Polygon | `class`, `name` |
|
|
117
|
+
| `reef` | Polygon | `name` |
|
|
118
|
+
| `navigation_area` | Point, LineString, Polygon | `class`, `subclass`, `size`, `rank`, `name`, `vertical_clearance` and its `_closed`, `_open`, and `_safe` variants |
|
|
119
|
+
| `coverage` | Polygon | `families` |
|
|
120
|
+
| `sounding` | Point | `depth` |
|
|
121
|
+
|
|
122
|
+
The Nautical source promotes each light's `provenance` as its feature ID
|
|
123
|
+
(`promoteId: {light: 'provenance'}`), so lights can be animated with MapLibre feature state.
|
|
124
|
+
|
|
125
|
+
Every layer filters on `min_zoom`, so a compatible source that keeps features in lower-zoom tiles
|
|
126
|
+
still shows each one from its own first zoom. Point groups place a lower `rank` first.
|
|
127
|
+
|
|
128
|
+
## Semantic groups
|
|
129
|
+
|
|
130
|
+
Each group is a style option of `nautical(...)`, with the same marker, symbol, area, and line style
|
|
131
|
+
objects as other modules.
|
|
132
|
+
|
|
133
|
+
| Option | Draws | Default symbology |
|
|
134
|
+
| ----------------- | ---------------------------------------------------------------------------- | --------------------------------------------------------- |
|
|
135
|
+
| `buoys` | `aid` buoys, light floats, and light vessels | Circle in the first colour, ringed with the second |
|
|
136
|
+
| `beacons` | `aid` beacons and daymarks | Small circle in the first colour |
|
|
137
|
+
| `lighthouses` | `aid` lighthouses | Ink circle and name |
|
|
138
|
+
| `aids` | Other `aid` classes, such as moorings, fog signals, and racons | Small hollow circle |
|
|
139
|
+
| `lights` | `light` points, one per sector | Flare in the light's first colour and its chart `label` |
|
|
140
|
+
| `hazards` | `hazard` points | `+` for rocks, `*` for rocks that show; circled obstacles |
|
|
141
|
+
| `hazardAreas` | `hazard` polygons; the outline also strokes linear hazards | Accent wash with a dotted outline |
|
|
142
|
+
| `wrecks` | `wreck` points | `Wk`, in the accent colour when dangerous |
|
|
143
|
+
| `wreckAreas` | `wreck` polygons | Ink wash with a dashed outline |
|
|
144
|
+
| `reefs` | `reef` polygons | Sand wash with a dotted outline |
|
|
145
|
+
| `navigationAreas` | `navigation_area` polygons | Dashed outlines; accent for operational areas |
|
|
146
|
+
| `routes` | `navigation_area` lines of class `route` and `traffic-separation` | Dashed line; accent for traffic separation |
|
|
147
|
+
| `cables` | `navigation_area` lines of class `cable`, `pipeline`, and their area classes | Fine dashed accent line |
|
|
148
|
+
| `overheadCables` | `navigation_area` lines of class `overhead-cable` | Dash-dot accent line |
|
|
149
|
+
| `bridges` | `navigation_area` bridge polygons; the outline also strokes bridge lines | Land-coloured deck with an ink outline |
|
|
150
|
+
| `berths` | `navigation_area` berth polygons; the outline also strokes berth lines | Thin ink outline, wider and darker for `guest` berths |
|
|
151
|
+
| `harbourAreas` | `navigation_area` harbour and marina polygons | Faint ink wash with a solid outline |
|
|
152
|
+
| `harbours` | `navigation_area` harbour points, and a symbol inside harbour polygons | Ink circle and name; the marina token for marinas |
|
|
153
|
+
| `facilities` | `navigation_area` facility points, polygons, and line centres, from zoom 13 | Hollow circle; facility icons from the theme |
|
|
154
|
+
| `notices` | `aid` notice boards, from zoom 12 | Circle in the board's function colour and `information` |
|
|
155
|
+
| `distanceMarks` | `aid` distance marks, from zoom 11 | Ink dot and distance with its unit, fainter if not posted |
|
|
156
|
+
| `ports` | `navigation_area` points of class `port` | Ink circle and name sized by `size`, from low zooms |
|
|
157
|
+
| `coverage` | `coverage` polygons that cover every family | Faint tint at low zooms only |
|
|
158
|
+
| `soundings` | `sounding` points | Depth figure |
|
|
159
|
+
| `labels` | Names inside polygons, bridge and overhead-cable clearances; coverage opt-in | Collision-aware text |
|
|
160
|
+
|
|
161
|
+
Bridge, berth, facility, and harbour polygons are drawn by their own groups rather than as
|
|
162
|
+
navigation areas. `labels.bridges` shows `clearance 4.5 m`, or `closed 3.6 m · open 12 m` for an
|
|
163
|
+
opening bridge, at bridge points, inside bridge polygons, and at the centre of bridge lines, from
|
|
164
|
+
zoom 13. `labels.overheadCables` shows `safe clearance 28.5 m`, or the plain clearance, at cable
|
|
165
|
+
points and along cable lines. Distance marks read `12 km`, `5 hm`, `300 m`, `12 mi`, or `4.5 NM`
|
|
166
|
+
from zoom 13. Notice boards follow the CEVNI colours: red for prohibitions, regulations, and
|
|
167
|
+
restrictions, green for recommendations, and blue for information; their `information`, such as a
|
|
168
|
+
speed limit, appears from zoom 14. Board orientation and impact are not drawn.
|
|
169
|
+
|
|
170
|
+
Operational areas are restricted, military, anchorage, anchor-berth, dumping-ground, and
|
|
171
|
+
traffic-separation areas. Marks keep their conventional colours in every theme; a white light is
|
|
172
|
+
drawn as a warm yellow so it remains visible on pale water. Ink, halo, and accent come from the
|
|
173
|
+
theme's `hydro.label`, `hydro.water`, and `poi.transport` colours, so a theme can restyle Nautical
|
|
174
|
+
without new options. Override any group like any other module style:
|
|
175
|
+
|
|
176
|
+
<!-- docs:check -->
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
import {defineMap, fixed, nautical} from '@tileflow/core';
|
|
180
|
+
import {streets} from '@tileflow/maps';
|
|
181
|
+
|
|
182
|
+
export default defineMap({
|
|
183
|
+
id: 'harbour-guide',
|
|
184
|
+
version: 1,
|
|
185
|
+
extends: streets,
|
|
186
|
+
marine: 'nautical',
|
|
187
|
+
modules: {
|
|
188
|
+
nautical: nautical({
|
|
189
|
+
buoys: {minZoom: 12},
|
|
190
|
+
cables: {visible: false},
|
|
191
|
+
navigationAreas: {
|
|
192
|
+
fill: {opacity: fixed(0.04, {reason: 'Keep operational areas quiet on the base map'})},
|
|
193
|
+
},
|
|
194
|
+
labels: {coverage: {visible: true}},
|
|
195
|
+
}),
|
|
196
|
+
},
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Flashing lights
|
|
201
|
+
|
|
202
|
+
In React, Vue, Svelte, and the development preview, every light with a rhythm flashes: its flare or
|
|
203
|
+
circle draws at its styled opacity while the light shines and at 15 % of it during an eclipse.
|
|
204
|
+
Fixed lights, lights without a usable characteristic, reduced motion, capture, native renderers, and
|
|
205
|
+
static images show every light steadily, exactly as it is styled. Set `animateLights: false` to keep
|
|
206
|
+
a map's lights steady everywhere:
|
|
207
|
+
|
|
208
|
+
<!-- docs:check -->
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
import {defineMap, nautical} from '@tileflow/core';
|
|
212
|
+
import {streets} from '@tileflow/maps';
|
|
213
|
+
|
|
214
|
+
export default defineMap({
|
|
215
|
+
id: 'harbour-guide',
|
|
216
|
+
version: 1,
|
|
217
|
+
extends: streets,
|
|
218
|
+
marine: 'nautical',
|
|
219
|
+
modules: {nautical: nautical({animateLights: false})},
|
|
220
|
+
});
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
A light flashes by its published `sequence` when it has one: light and eclipse durations in
|
|
224
|
+
seconds, eclipses in parentheses, for example `0.5+(1.5)+0.5+(4.5)`. Otherwise
|
|
225
|
+
`tileflowLightRhythm(properties)` derives a conventional rhythm from `character`, `group`, and
|
|
226
|
+
`period_s`; `tileflowLightRhythmConventions` holds the values below.
|
|
227
|
+
|
|
228
|
+
| Character | Rhythm |
|
|
229
|
+
| ------------------------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
230
|
+
| `Fl` | Flashes of `min(1 s, 0.3 × period ÷ flashes)`; gaps within a group at most twice the flash |
|
|
231
|
+
| `Fl` with a group such as `2+1` | Groups separated by twice the inner gap; the rest of the period is the final eclipse |
|
|
232
|
+
| `LFl` | The same layout with 2 s flashes, shorter only when the period cannot hold them |
|
|
233
|
+
| `Q`, `VQ`, `UQ` | 60, 120, and 240 flashes a minute, lit for 30 % of each; a group of `n` flashes then eclipses |
|
|
234
|
+
| `IQ`, `IVQ`, `IUQ` | Quick flashes for 60 % of the period, then an eclipse |
|
|
235
|
+
| `Iso` | Equal light and eclipse |
|
|
236
|
+
| `Oc` | Eclipses totalling 25 % of the period, laid out like `Fl`, so the light is always longer |
|
|
237
|
+
| `Mo` | The Morse letter in `group`: 0.5 s dots, three-unit dashes, one-unit gaps, then the rest of the period |
|
|
238
|
+
| `FFl`, `F+LFl` | A fixed light at half intensity with full flashes, or long flashes |
|
|
239
|
+
| `Q+LFl`, `VQ+LFl`, `UQ+LFl`, `Fl+LFl` | The group (six quick flashes by default), one 2 s long flash, then the eclipse |
|
|
240
|
+
| `Oc+Fl` | Its occulting part |
|
|
241
|
+
| `Al.<character>`, `Al` | Each lit phase shows the next colour of `color`; `Al` alone shows each colour for an equal share |
|
|
242
|
+
| `F`, unknown, or missing period | Steady; grouped `Q` and `VQ` cardinal marks without a period use the IALA periods |
|
|
243
|
+
|
|
244
|
+
`tileflowLightStateAt(rhythm, seconds)` returns the intensity, colour index, and time to the next
|
|
245
|
+
change at any moment. Lights with the same rhythm flash together.
|
|
246
|
+
|
|
247
|
+
React, Vue, Svelte, the development preview, and standalone capture call
|
|
248
|
+
`attachTileflowNauticalLights(map)` from `@tileflow/core/browser`. It reads the light layers the
|
|
249
|
+
style declares in `metadata['tileflow:nautical-lights']`, and writes each rendered light's
|
|
250
|
+
`tileflowLightIntensity` and `tileflowLightColour` feature state only when its phase changes. It runs
|
|
251
|
+
one timer for the next change, and none while the page is hidden, while no light layer is visible at
|
|
252
|
+
the current zoom, or under reduced motion. A direct MapLibre integration attaches it after
|
|
253
|
+
constructing the map:
|
|
254
|
+
|
|
255
|
+
```ts
|
|
256
|
+
import maplibregl from 'maplibre-gl';
|
|
257
|
+
import {attachTileflowNauticalLights, attachTileflowNotices} from '@tileflow/core/browser';
|
|
258
|
+
|
|
259
|
+
const map = new maplibregl.Map({
|
|
260
|
+
container: 'map',
|
|
261
|
+
style: '/tileflow/styles/harbour-guide/light.json',
|
|
262
|
+
});
|
|
263
|
+
attachTileflowNotices(map);
|
|
264
|
+
const detach = attachTileflowNauticalLights(map);
|
|
265
|
+
// Call detach() to return every light to steady; removing the map also detaches it.
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
`steadyTileflowNauticalLights(style)` returns a copy that draws every light steadily without feature
|
|
269
|
+
state; native artifact preparation applies it automatically.
|
|
270
|
+
|
|
271
|
+
## Chart symbols from the theme
|
|
272
|
+
|
|
273
|
+
A theme that declares the image tokens below replaces a point group's circle marker with that icon.
|
|
274
|
+
Buoy variants fall back to `nautical.buoy`. `tileflowNauticalImageRoles` lists the tokens.
|
|
275
|
+
|
|
276
|
+
| Token | Group |
|
|
277
|
+
| ------------------------- | ------------------------------------------ |
|
|
278
|
+
| `nautical.buoy` | `buoys` |
|
|
279
|
+
| `nautical.buoy.port` | Lateral buoys of a port-hand category |
|
|
280
|
+
| `nautical.buoy.starboard` | Lateral buoys of a starboard-hand category |
|
|
281
|
+
| `nautical.buoy.cardinal` | Cardinal buoys |
|
|
282
|
+
| `nautical.beacon` | `beacons` |
|
|
283
|
+
| `nautical.lighthouse` | `lighthouses` |
|
|
284
|
+
| `nautical.light` | `lights` |
|
|
285
|
+
| `nautical.aid` | `aids` |
|
|
286
|
+
| `nautical.wreck` | `wrecks` |
|
|
287
|
+
| `nautical.harbour` | `harbours` |
|
|
288
|
+
| `nautical.marina` | Harbours whose `subclass` lists a marina |
|
|
289
|
+
| `nautical.port` | `ports` |
|
|
290
|
+
| `nautical.notice` | `notices` |
|
|
291
|
+
| `nautical.notice.<role>` | Notices of that function |
|
|
292
|
+
| `nautical.distance-mark` | `distanceMarks` |
|
|
293
|
+
| `nautical.facility` | `facilities` |
|
|
294
|
+
| `nautical.facility.<cat>` | Facilities listing that category |
|
|
295
|
+
|
|
296
|
+
Notice roles are `prohibition`, `regulation`, `restriction`, `recommendation`, and `information`.
|
|
297
|
+
Facility categories are `fuel-station`, `slipway`, `boat-hoist`, `pump-out`, `water-tap`,
|
|
298
|
+
`visitor-berth` (also used for `visitors-mooring`), and `boatyard`: a facility listing several shows
|
|
299
|
+
the first in that order (`tileflowNauticalFacilityIcons`), and the others show `nautical.facility`.
|
|
300
|
+
Every icon expression selects among the declared image names only.
|
|
301
|
+
|
|
302
|
+
Buoys, beacons, other aids, and lights colour their icon with the mark's own colour, so declare
|
|
303
|
+
them as [SDF icons](https://github.com/tileflow/tileflow-sdk/blob/main/packages/dev/docs/native-icons.md)
|
|
304
|
+
that share one representation within each group. The defaults size icons for the SDF profile,
|
|
305
|
+
whose drawing occupies the central 12 of 24 pixels; set `icon.size` for other artwork. Notice
|
|
306
|
+
boards take their function colour. Soundings declares these tokens with its own buoy, light,
|
|
307
|
+
lighthouse, wreck, harbour, marina, notice-board, distance-mark, and facility symbols and keeps
|
|
308
|
+
beacons as coloured dots.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Public API and browser subpath
|
|
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
|
+
Config, data, modules, compilation, validation, runtime resolution, and capture-scene APIs remain
|
|
6
|
+
available from the package root. Capture scenes, manifests, and browser-runtime surfaces also have
|
|
7
|
+
explicit `@tileflow/core/capture`, `@tileflow/core/manifest`, and `@tileflow/core/runtime`
|
|
8
|
+
subpaths. Node build integrations import the small deterministic map-identity contract from
|
|
9
|
+
`@tileflow/core/build`: `collectTileflowMapBuildLineage`, `createTileflowMapBuildManifest`,
|
|
10
|
+
`hashTileflowMapRevision`, `hashTileflowAssetSet`, and `hashTileflowAssetSetIdentities`. The latter
|
|
11
|
+
reproduces the same asset-set v1 hash from exact per-file identities after another system has
|
|
12
|
+
independently confirmed the immutable bytes; package or bundle hashes are not substitutes. The
|
|
13
|
+
previous aggregate-wrapper and recipe-selector APIs, `renderer`, top-level `tiles`/`tileset`, module
|
|
14
|
+
arrays, and top-level raw `layers` are not part of this API. Raw MapLibre layers are accepted only
|
|
15
|
+
inside a named `maplibreOverlay()` bound to a named Team source.
|
|
16
|
+
|
|
17
|
+
Advanced cartography remains in the same public language: `withRenderStack()`, `renderPass()`, and
|
|
18
|
+
`refineRenderTarget()` address owner-local semantic targets without exposing physical layer IDs,
|
|
19
|
+
sources, source layers, raw filters, or physical before/after layer anchors. Typed `field()`
|
|
20
|
+
references and `expr.*` builders stay semantic until the compiler's single lowering boundary. There
|
|
21
|
+
is no recipe subpath or alternate compiler integration API.
|
|
22
|
+
|
|
23
|
+
`mapRevisionSha256` hashes only resolved cartography: the effective design after `extends`, the
|
|
24
|
+
semantic language, compiler-owned effective contributions, and exact source icon/font identities.
|
|
25
|
+
Leaf `id`, `name`, editorial `mapVersion`, default `view`, capture `scenes`, and `delivery` policy do
|
|
26
|
+
not change that content identity. They remain explicit on the map, manifest, Style, capture receipt,
|
|
27
|
+
or Hosted deployment fingerprint that owns them. Compiler ABI, package versions, generated assets,
|
|
28
|
+
and the concrete release selected by World `current` likewise have separate identities.
|
|
29
|
+
|
|
30
|
+
Runtime manifest version 1 has one shape for local and Hosted delivery. Every map entry owns
|
|
31
|
+
`defaultTheme`, optional `systemThemes`, and a `themes` record whose leaves contain
|
|
32
|
+
`colorScheme`, `styleUrl`, and optional font/deployment identity. Hosted-only identity is additive
|
|
33
|
+
metadata on the same map entry; there is no delivery discriminator or parallel `styles` alias.
|
|
34
|
+
`parseTileflowRuntimeManifest()` accepts only this canonical shape. The strict bounded schema uses
|
|
35
|
+
the same portable map and theme IDs as authoring, rejects `system` as a published name, duplicate
|
|
36
|
+
font identities, unsafe owner-relative URLs, prototype-bearing input, unknown fields, and JSON
|
|
37
|
+
larger than 1 MiB.
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"version": 1,
|
|
42
|
+
"maps": {
|
|
43
|
+
"madrid": {
|
|
44
|
+
"defaultTheme": "light",
|
|
45
|
+
"systemThemes": {"light": "light", "dark": "dark"},
|
|
46
|
+
"themes": {
|
|
47
|
+
"light": {"colorScheme": "light", "styleUrl": "/styles/madrid/light.json"},
|
|
48
|
+
"dark": {"colorScheme": "dark", "styleUrl": "/styles/madrid/dark.json"}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Runtime fetches share a successful result for 30 seconds, never cache failures, use
|
|
56
|
+
`cache: 'no-store'`, enforce a 10-second timeout (configurable up to 60 seconds), compose an
|
|
57
|
+
external abort signal, and can be invalidated with `clearTileflowManifestCache()`.
|
|
58
|
+
|
|
59
|
+
Named map `view` values travel in the manifest. `resolveTileflowRuntimeTheme()` turns an omitted,
|
|
60
|
+
explicit, or `system` request with a supplied color scheme into one concrete published entry;
|
|
61
|
+
unknown names fail closed. `resolveTileflowRuntimeView()` defines the shared precedence as explicit
|
|
62
|
+
runtime values, then the manifest view, then the single exported `defaultTileflowRuntimeView`
|
|
63
|
+
(`[0, 20]`, zoom 2, bearing/pitch 0).
|
|
64
|
+
|
|
65
|
+
`TileflowRuntimeSource` is one object, `{map, manifestUrl?}`, selecting a named Tileflow map only
|
|
66
|
+
through its published manifest. React, Vue and Svelte share that source contract. Omitting the URL
|
|
67
|
+
means exactly `/tileflow/manifest.json`; other locations must be explicit. The native Core contract
|
|
68
|
+
uses `{map, manifestUrl}` with a required absolute URL and no discovery, as described in the
|
|
69
|
+
[native guide](native-resource-urls.md). The React Native type contract preserves that requirement.
|
|
70
|
+
No public framework Map source exposes a renderer discriminator or direct-style branch. The obsolete
|
|
71
|
+
`kind` and `style` fields are rejected; completely unmanaged maps use upstream MapLibre directly.
|
|
72
|
+
The runtime subpath does not import the config compiler, invent a localhost style URL, or change
|
|
73
|
+
image mode by environment.
|
|
74
|
+
|
|
75
|
+
Framework adapters import the browser-only lifecycle kernel explicitly:
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import {
|
|
79
|
+
attachTileflowAtmosphere,
|
|
80
|
+
attachTileflowFairUseNotice,
|
|
81
|
+
attachTileflowMapLifecycle,
|
|
82
|
+
attachTileflowNauticalLights,
|
|
83
|
+
attachTileflowNotices,
|
|
84
|
+
createTileflowSessionStarter,
|
|
85
|
+
createTileflowTransformRequest,
|
|
86
|
+
registerTileflowWorldRequestBridge,
|
|
87
|
+
} from '@tileflow/core/browser';
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`@tileflow/core/3d` holds only `createTileflowMap3D` and the 3D renderers it mounts, so an
|
|
91
|
+
application can load them with a dynamic import when a style declares a 3D scene; see
|
|
92
|
+
[3D buildings](buildings-3d.md#the-maps-3d-scene). The browser entry exports the same function.
|
|
93
|
+
|
|
94
|
+
`attachTileflowNotices(map)` renders the notices a compiled style declares, such as Nautical's
|
|
95
|
+
"Not for navigation", as a compact map control, and `attachTileflowNauticalLights(map)` flashes
|
|
96
|
+
Nautical lights in their rhythm; see [Nautical marks](nautical-marks.md). The browser entry is not re-exported from the root. It is SSR-safe to import, has no MapLibre
|
|
97
|
+
runtime dependency, and reads no browser global during module evaluation. See the
|
|
98
|
+
[framework browser runtime contract](https://github.com/tileflow/tileflow-sdk/blob/main/docs/contracts/framework-browser-runtime.md) and the
|
|
99
|
+
[cartographic authoring contract](https://github.com/tileflow/tileflow-sdk/blob/main/docs/contracts/cartographic-authoring.md). Exact field
|
|
100
|
+
resolution and asset rules live in the
|
|
101
|
+
[map inheritance contract](https://github.com/tileflow/tileflow-sdk/blob/main/docs/contracts/map-inheritance.md).
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# Route drawing
|
|
2
|
+
|
|
3
|
+
An application that draws a route on a Tileflow map can take the route's colours from the theme and
|
|
4
|
+
draw the line on with a moving head. Themes set route inks; the theme controller returns them for
|
|
5
|
+
the theme on screen; `createTileflowLineProgress` animates a group of line layers along their
|
|
6
|
+
length; `createTileflowGroundLayers` keeps them on the ground, under the map's 3D buildings.
|
|
7
|
+
|
|
8
|
+
## Set route inks in a theme
|
|
9
|
+
|
|
10
|
+
Route inks are optional theme tokens. A theme that sets none uses defaults for its colour scheme:
|
|
11
|
+
a blue line on a dark edge for light themes, a lighter blue with a glow and a bright core for dark
|
|
12
|
+
themes.
|
|
13
|
+
|
|
14
|
+
| Token | Kind | Use |
|
|
15
|
+
| -------------------- | ------ | ----------------------------------------------------- |
|
|
16
|
+
| `route.line` | colour | The chosen route. |
|
|
17
|
+
| `route.casing` | colour | The edge each side of the line, apart from the roads. |
|
|
18
|
+
| `route.core` | colour | A thin line along the middle. |
|
|
19
|
+
| `route.glow` | colour | A soft halo around the route. |
|
|
20
|
+
| `route.alternative` | colour | Other routes offered beside the chosen one. |
|
|
21
|
+
| `route.glow.opacity` | number | The halo's opacity, from 0 (none) to 1. |
|
|
22
|
+
| `route.core.opacity` | number | The core's opacity, from 0 (none) to 1. |
|
|
23
|
+
|
|
24
|
+
Every theme of a map carries the same tokens, so a map that sets route inks sets them in each of
|
|
25
|
+
its themes:
|
|
26
|
+
|
|
27
|
+
<!-- docs:check -->
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import {defineTheme, type TileflowTheme} from '@tileflow/core';
|
|
31
|
+
|
|
32
|
+
export function withNeonRoute(base: TileflowTheme, id: string): TileflowTheme {
|
|
33
|
+
return defineTheme(base, {
|
|
34
|
+
id,
|
|
35
|
+
version: 1,
|
|
36
|
+
colorScheme: base.colorScheme,
|
|
37
|
+
tokens: {
|
|
38
|
+
color: {
|
|
39
|
+
'route.line': '#ff4fae',
|
|
40
|
+
'route.casing': '#0b0f12',
|
|
41
|
+
'route.core': '#ffe0f0',
|
|
42
|
+
'route.glow': '#ff4fae',
|
|
43
|
+
},
|
|
44
|
+
number: {'route.glow.opacity': 0.55, 'route.core.opacity': 0.9},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The compiler publishes the resolved inks in the style's `tileflow:route` metadata.
|
|
51
|
+
`readTileflowRouteInks(style.metadata)` reads them from a style document;
|
|
52
|
+
`tileflowStyleRouteInks(style)` also falls back on the defaults for a style compiled without them.
|
|
53
|
+
|
|
54
|
+
## Draw a route in the theme's inks
|
|
55
|
+
|
|
56
|
+
The theme controller's `getRouteInks()` returns the inks of the theme on screen. During a blend it
|
|
57
|
+
mixes them between the neighbouring themes at the blend's position, in the same colour space as
|
|
58
|
+
the map's own colours. Read them again after `setTheme` or `setBlend`.
|
|
59
|
+
|
|
60
|
+
`createTileflowLineProgress(map, {layers})` owns the `line-gradient` and `line-opacity` of a group of
|
|
61
|
+
line layers. Their source must be GeoJSON with `lineMetrics: true`. The controller shows the line
|
|
62
|
+
from `start` to `end` (shares of its length), a highlight at the head while the line is being drawn,
|
|
63
|
+
and an optional light at `light`. It writes only what changed, paints a layer again when a style
|
|
64
|
+
change re-creates it, and skips layers that are not on the map.
|
|
65
|
+
|
|
66
|
+
This example assumes an existing MapLibre map named `map` whose style already holds four line
|
|
67
|
+
layers over a GeoJSON source with `lineMetrics: true`:
|
|
68
|
+
|
|
69
|
+
<!-- docs:check -->
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import {
|
|
73
|
+
createTileflowLineProgress,
|
|
74
|
+
type TileflowLineProgressMap,
|
|
75
|
+
type TileflowRouteInks,
|
|
76
|
+
} from '@tileflow/core/browser';
|
|
77
|
+
|
|
78
|
+
const layers = (inks: TileflowRouteInks) => [
|
|
79
|
+
{id: 'route-glow', color: inks.glow, highlight: '#ffffff', opacity: inks.glowOpacity},
|
|
80
|
+
{id: 'route-casing', color: inks.casing},
|
|
81
|
+
{id: 'route-line', color: inks.line, highlight: inks.core},
|
|
82
|
+
{id: 'route-core', color: inks.core, highlight: '#ffffff', opacity: inks.coreOpacity},
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
export async function drawRoute(
|
|
86
|
+
map: TileflowLineProgressMap,
|
|
87
|
+
inks: TileflowRouteInks,
|
|
88
|
+
lengthInMetres: number,
|
|
89
|
+
) {
|
|
90
|
+
const route = createTileflowLineProgress(map, {
|
|
91
|
+
layers: layers(inks),
|
|
92
|
+
// A 90 m highlight, whatever the route's length.
|
|
93
|
+
headLength: Math.min(0.2, 90 / lengthInMetres),
|
|
94
|
+
initial: {end: 0},
|
|
95
|
+
});
|
|
96
|
+
await route.animate({to: {end: 1}, duration: 2500});
|
|
97
|
+
// A light runs along the drawn route.
|
|
98
|
+
await route.animate({to: {light: 1}, duration: 1500});
|
|
99
|
+
route.set({light: undefined});
|
|
100
|
+
return {
|
|
101
|
+
recolour: (next: TileflowRouteInks) => route.configure({layers: layers(next)}),
|
|
102
|
+
fadeOut: () => route.animate({to: {opacity: 0}, duration: 400}),
|
|
103
|
+
dispose: () => route.dispose(),
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`animate` resolves `true` when the line gets where it was sent, and `false` when `set`, another
|
|
109
|
+
animation, or `dispose` stops it first; the line stays where it was stopped. A browser preference
|
|
110
|
+
for reduced motion shows the target at once. `tileflowLineProgressGradient(state, options)` returns
|
|
111
|
+
the same gradient for a single state, for styles built ahead of time.
|
|
112
|
+
|
|
113
|
+
## Keep a route under 3D buildings
|
|
114
|
+
|
|
115
|
+
MapLibre draws a 2D layer that comes after a 3D layer, such as extruded buildings or a custom layer
|
|
116
|
+
drawn in 3D, without testing depth. A route added under the labels therefore crosses in front of
|
|
117
|
+
the buildings. A route that lies on the ground goes before the first 3D layer: every building then
|
|
118
|
+
hides it exactly where it stands in front of it.
|
|
119
|
+
|
|
120
|
+
`tileflowGroundBeforeId(map)` returns that layer: the first 3D layer above the roads, or the start
|
|
121
|
+
of the vegetation when the buildings are flat, so a ground layer still covers the roads and the
|
|
122
|
+
flat buildings. Pass it as `beforeId` to `map.addLayer` for a single layer.
|
|
123
|
+
|
|
124
|
+
`createTileflowGroundLayers(map, {layers, occludedOpacity})` keeps a group of layers there, bottom
|
|
125
|
+
to top as given:
|
|
126
|
+
|
|
127
|
+
- It adds the layers, or moves those already on the map. A layer whose source is not on the map yet
|
|
128
|
+
is added when the source is.
|
|
129
|
+
- After a style change, it brings back the layers the change dropped, with the paint and layout
|
|
130
|
+
last written through the group.
|
|
131
|
+
- When a 3D layer lands above the group, such as a custom layer added later, the group moves under
|
|
132
|
+
it.
|
|
133
|
+
- `occludedOpacity` lets a line show through 3D content: by layer id, how much of the line shows
|
|
134
|
+
where buildings hide it, from 0 (nothing, the default) to 1. The group draws a copy of the line
|
|
135
|
+
over the 3D content at the line's opacity times that share, as a navigation app shows a route
|
|
136
|
+
through buildings. The copy lies over the group's other layers too, so where the line shows, it
|
|
137
|
+
tints the layers drawn above the line slightly; a line at the top of the group shows no change.
|
|
138
|
+
Only line layers whose `line-opacity` is a number can show through.
|
|
139
|
+
|
|
140
|
+
Paint the group's layers through the group, so the copies follow them. A helper that paints layers
|
|
141
|
+
takes the group in place of the map:
|
|
142
|
+
|
|
143
|
+
<!-- docs:check -->
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
import {
|
|
147
|
+
createTileflowGroundLayers,
|
|
148
|
+
createTileflowLineProgress,
|
|
149
|
+
type TileflowGroundLayersMap,
|
|
150
|
+
type TileflowRouteInks,
|
|
151
|
+
} from '@tileflow/core/browser';
|
|
152
|
+
|
|
153
|
+
export function addRoute(map: TileflowGroundLayersMap, inks: TileflowRouteInks) {
|
|
154
|
+
// The map already holds a GeoJSON source named 'route' with `lineMetrics: true`.
|
|
155
|
+
const line = (id: string, width: number) => ({
|
|
156
|
+
id,
|
|
157
|
+
type: 'line',
|
|
158
|
+
source: 'route',
|
|
159
|
+
layout: {'line-cap': 'round', 'line-join': 'round'},
|
|
160
|
+
paint: {'line-width': width},
|
|
161
|
+
});
|
|
162
|
+
const ground = createTileflowGroundLayers(map, {
|
|
163
|
+
layers: [line('route-casing', 12), line('route-line', 8), line('route-core', 2)],
|
|
164
|
+
occludedOpacity: {'route-line': 0.35},
|
|
165
|
+
});
|
|
166
|
+
const route = createTileflowLineProgress(ground, {
|
|
167
|
+
layers: [
|
|
168
|
+
{id: 'route-casing', color: inks.casing},
|
|
169
|
+
{id: 'route-line', color: inks.line, highlight: inks.core},
|
|
170
|
+
{id: 'route-core', color: inks.core, opacity: inks.coreOpacity},
|
|
171
|
+
],
|
|
172
|
+
initial: {end: 0},
|
|
173
|
+
});
|
|
174
|
+
return {
|
|
175
|
+
draw: () => route.animate({to: {end: 1}, duration: 2500}),
|
|
176
|
+
remove: () => {
|
|
177
|
+
route.dispose();
|
|
178
|
+
ground.dispose();
|
|
179
|
+
},
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
`dispose` takes the group's layers and copies off the map. The copies keep the layer's id with
|
|
185
|
+
`:occluded` after it.
|
|
186
|
+
|
|
187
|
+
## Cost
|
|
188
|
+
|
|
189
|
+
Each frame of an animation writes one `line-gradient` per layer, and MapLibre rebuilds that layer's
|
|
190
|
+
gradient texture. A route of a few layers costs little; avoid animating dozens of long lines at
|
|
191
|
+
once.
|