@tileflow/core 0.1.0-alpha.42 → 0.1.0-alpha.43
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -68
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/dist/{3d-CzLTD0RK.d.ts → 3d-CW5Ls0An.d.ts} +32 -2
- package/dist/3d.d.ts +1 -1
- package/dist/3d.js +301 -22
- package/dist/browser.d.ts +95 -5
- package/dist/browser.js +713 -45
- package/dist/build.d.ts +8 -4
- package/dist/build.js +250 -3
- package/dist/config-reference.json +3395 -2140
- package/dist/{icon-composition-B1A2udKb.d.ts → icon-composition-Bbw9umUA.d.ts} +37 -2
- package/dist/index.d.ts +13 -4
- package/dist/index.js +193 -3
- package/dist/{manifest-types-B0lQjabX.d.ts → manifest-types-CwjHd4qc.d.ts} +8 -0
- package/dist/manifest.d.ts +2 -2
- package/dist/native-profile.d.ts +4 -0
- package/dist/native-profile.js +2 -0
- package/dist/native.js +789 -462
- package/dist/runtime.d.ts +1 -1
- package/dist/worker/camera-tile-worker.global.js +2 -2
- package/package.json +4 -5
- package/docs/application-tile-reading.md +0 -86
- package/docs/authoring-model.md +0 -269
- package/docs/boundary-areas-and-choropleths.md +0 -230
- package/docs/buildings-3d.md +0 -624
- package/docs/camera-moves-and-tile-cache.md +0 -112
- package/docs/capture-scenes.md +0 -40
- package/docs/capture-shots.md +0 -173
- package/docs/cartographic-defaults.md +0 -214
- package/docs/compiled-style-performance.md +0 -286
- package/docs/data-is-separate-from-design.md +0 -610
- package/docs/depth-markers.md +0 -65
- package/docs/dynamic-style-images.md +0 -100
- package/docs/globe-atmosphere.md +0 -113
- package/docs/hosted-session-authorization.md +0 -106
- package/docs/map-and-terrain-examples.md +0 -156
- package/docs/map-emphasis.md +0 -89
- package/docs/native-artifact-profile.md +0 -152
- package/docs/native-resource-urls.md +0 -369
- package/docs/nautical-marks.md +0 -308
- package/docs/public-api-and-browser-subpath.md +0 -101
- package/docs/route-drawing.md +0 -191
- package/docs/shared-visual-primitives.md +0 -101
- package/docs/street-lights.md +0 -127
- package/docs/street-sky.md +0 -156
- package/docs/style-states.md +0 -73
- package/docs/sun-and-light.md +0 -167
- package/docs/theme-transitions-and-blends.md +0 -317
- package/docs/themes-and-module-styles.md +0 -156
- package/docs/trees-3d.md +0 -295
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
# Shared visual primitives
|
|
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
|
-
The same small visual language is reused across every geographic domain. This keeps an agent from
|
|
6
|
-
having to learn different spellings for the same MapLibre behavior:
|
|
7
|
-
|
|
8
|
-
- `BackgroundStyle`: color, opacity, pattern, visibility, and zoom range.
|
|
9
|
-
- `FillStyle`: color, opacity, pattern, antialiasing, visibility, and zoom range.
|
|
10
|
-
- `LineStyle`: color, width, opacity, dash, blur, gap, offset, pattern, caps, joins, and zoom range.
|
|
11
|
-
- `LineHatchStyle`: repeated diagonal detail with color, opacity, spacing, size, angle, and zoom
|
|
12
|
-
range for a road structure.
|
|
13
|
-
- `TextStyle`: field, exact font face, exact fallback faces, size, color, halo, line-fitted
|
|
14
|
-
background, spacing metrics, transform, collision policy, rotation, fixed/variable anchoring, line
|
|
15
|
-
constraints, and zoom range.
|
|
16
|
-
- `IconStyle`: image, size, color, halo, rotation/alignment, collision policy, and zoom range.
|
|
17
|
-
- `CircleStyle`: radius, fill/stroke appearance, blur, opacity, pitch behavior, and zoom range.
|
|
18
|
-
- `ExtrusionStyle`: color, height, base, opacity, pattern, vertical gradient, and zoom range.
|
|
19
|
-
|
|
20
|
-
Compounds express common cartographic structures: `AreaStyle` has `fill` and `outline`,
|
|
21
|
-
`LineStackStyle` has `shadow`, `casing`, and `fill`, and `SymbolStyle` combines placement with
|
|
22
|
-
optional `text`, `icon`, and `marker`. Geographic selection remains owned by semantic modules;
|
|
23
|
-
ordinary visual styles intentionally do not accept raw source filters.
|
|
24
|
-
|
|
25
|
-
## Symbol overlap modes
|
|
26
|
-
|
|
27
|
-
`text.allowOverlap` and `icon.allowOverlap` either hide a part that collides with a symbol placed
|
|
28
|
-
before it or always show it. `overlap` selects one of three modes instead:
|
|
29
|
-
|
|
30
|
-
- `never`: hide the part when it collides.
|
|
31
|
-
- `always`: show the part even when it collides.
|
|
32
|
-
- `cooperative`: show the part unless it collides with a symbol placed with `never`. It may overlap
|
|
33
|
-
symbols placed with `always` or `cooperative`.
|
|
34
|
-
|
|
35
|
-
MapLibre places symbols from the top layer down, so a symbol placed before another is usually higher
|
|
36
|
-
in the stack. `overlap` takes precedence over `allowOverlap` on the same part, including an
|
|
37
|
-
`allowOverlap` default supplied by a module or already present on a refined target, so the compiled
|
|
38
|
-
layer carries only `text-overlap` or `icon-overlap`. MapLibre Native has no overlap modes, so native
|
|
39
|
-
artifact preparation replaces the mode with the matching `text-allow-overlap` or
|
|
40
|
-
`icon-allow-overlap`: `false` for `never` and `true` for `always` and `cooperative`. There a
|
|
41
|
-
cooperative part no longer gives way to symbols placed with `never`. The
|
|
42
|
-
[canopy grove recipe](data-is-separate-from-design.md) uses a cooperative text to decide where
|
|
43
|
-
icons draw.
|
|
44
|
-
|
|
45
|
-
## Line-fitted text backgrounds
|
|
46
|
-
|
|
47
|
-
`text.background` draws one opaque strip behind each shaped line of a label, fitted to that line's
|
|
48
|
-
own width. Use it for captions whose lines differ in length, where a stretched icon plate
|
|
49
|
-
(`icon.textFit`) would cover the whole block.
|
|
50
|
-
|
|
51
|
-
<!-- docs:check -->
|
|
52
|
-
|
|
53
|
-
```ts
|
|
54
|
-
import {fixed, poi, zoom} from '@tileflow/core';
|
|
55
|
-
|
|
56
|
-
export const captions = poi({
|
|
57
|
-
categories: ['arts-entertainment'],
|
|
58
|
-
styles: {
|
|
59
|
-
'arts-entertainment': {
|
|
60
|
-
text: {
|
|
61
|
-
background: {
|
|
62
|
-
color: fixed('#080E11', {reason: 'Caption strip'}),
|
|
63
|
-
fit: 'lines',
|
|
64
|
-
padding: 0.33,
|
|
65
|
-
},
|
|
66
|
-
color: fixed('#ECEEE9', {reason: 'Caption text'}),
|
|
67
|
-
font: fixed('Noto Sans Bold', {reason: 'Caption face'}),
|
|
68
|
-
letterSpacing: fixed(0.08, {reason: 'Caption tracking'}),
|
|
69
|
-
lineHeight: fixed(1.2, {reason: 'Caption leading'}),
|
|
70
|
-
size: zoom.linear([
|
|
71
|
-
[14, 11],
|
|
72
|
-
[18, 14],
|
|
73
|
-
]),
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
});
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
Tileflow lowers the background to MapLibre properties only. `text-font` becomes a derived stack,
|
|
81
|
-
such as `Noto Sans Bold lines-v1-t80-l1200-p330`. Its glyphs keep the source advances and shapes and
|
|
82
|
-
add a rectangular cell, which the text halo paints. The halo width tracks `text-size / 6`, including
|
|
83
|
-
zoom curves. Shaping, wrapping, collision, variable anchors, fading and right-to-left text therefore
|
|
84
|
-
stay native, and the compiled style needs no runtime extension.
|
|
85
|
-
|
|
86
|
-
- The colour must be opaque. Neighbouring cells overlap where they join.
|
|
87
|
-
- `font` must name one stack served by the map's `glyphs` provider, without `fallbacks`. Maps that
|
|
88
|
-
use browser-rendered `fonts` reject backgrounds.
|
|
89
|
-
- `letterSpacing` and `lineHeight` must be constants. The derived stack encodes them in thousandths
|
|
90
|
-
of an em, and the layer uses those rounded values. Tracking runs from 0 to 0.5em, leading from 0.8
|
|
91
|
-
to 3 and padding from 0 to 1em.
|
|
92
|
-
- The background replaces the text halo. While a background is active, `haloWidth` and `haloBlur`
|
|
93
|
-
are derived, and `haloColor` is the strip colour. Later refinements of size, tracking, leading or
|
|
94
|
-
font re-derive the stack and halo.
|
|
95
|
-
- Collision still reserves the shaped block. Padding beyond it is drawn outside that box, so keep
|
|
96
|
-
`padding` (text padding) at least as large as the strip padding in pixels.
|
|
97
|
-
|
|
98
|
-
The map's `glyphs` provider must serve derived stacks. `deriveTileflowLineBackgroundGlyphs`
|
|
99
|
-
computes any range from the source stack's range, and `parseTileflowLineBackgroundFontStack`
|
|
100
|
-
recognises derived requests. Local previews and captures derive ranges themselves; hosted and
|
|
101
|
-
self-hosted providers must do the same.
|
package/docs/street-lights.md
DELETED
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
# Street lights
|
|
2
|
-
|
|
3
|
-
`createTileflowStreetLights` lights a Tileflow map's streets at night from its own vector tiles. The
|
|
4
|
-
lamps the map's data holds shine where they stand, each with a pool of light on the ground and a
|
|
5
|
-
glowing head. Streets and pavements the data maps as lit, but whose lamps it does not hold, take a
|
|
6
|
-
soft light along them that claims no lamp's place. As the theme controller's sun darkens the map,
|
|
7
|
-
the lights switch on one by one; they go out as day comes.
|
|
8
|
-
|
|
9
|
-
Street lights are off by default in the SDK and in Streets. A compiled map must explicitly set
|
|
10
|
-
`roads.streetLights.enabled: true` before the renderer or preview will show lamp glows.
|
|
11
|
-
|
|
12
|
-
React, Vue and Svelte maps light a map that enables street lights automatically, as part of its
|
|
13
|
-
[3D scene](buildings-3d.md#the-maps-3d-scene); the 2D view has no street lights.
|
|
14
|
-
|
|
15
|
-
It is a custom WebGL2 layer for MapLibre GL JS, drawn above the map's buildings and below its
|
|
16
|
-
labels. When `createTileflowBuildings3D` raises the buildings, they hide the lamps behind them. It
|
|
17
|
-
needs WebGL2 and the Mercator projection, and shines from zoom 14 by default.
|
|
18
|
-
|
|
19
|
-
## Light the streets
|
|
20
|
-
|
|
21
|
-
This example assumes an existing MapLibre map showing a Tileflow map whose vector source is called
|
|
22
|
-
`tileflow`, as Tileflow's maps call World, with `roads.streetLights.enabled: true` in its map
|
|
23
|
-
definition and a theme controller for it:
|
|
24
|
-
|
|
25
|
-
<!-- docs:check -->
|
|
26
|
-
|
|
27
|
-
```ts
|
|
28
|
-
import {
|
|
29
|
-
createTileflowStreetLights,
|
|
30
|
-
type TileflowStreetLightsMap,
|
|
31
|
-
type TileflowThemeController,
|
|
32
|
-
} from '@tileflow/core/browser';
|
|
33
|
-
|
|
34
|
-
export function lightTheStreets(map: TileflowStreetLightsMap, controller: TileflowThemeController) {
|
|
35
|
-
// The lights switch on as the theme's or the application's sun darkens the map.
|
|
36
|
-
return createTileflowStreetLights({map, controller});
|
|
37
|
-
}
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
The lights follow `controller.getSun()`: they switch on as its `brightness` falls through dusk, each
|
|
41
|
-
lamp at its own moment, and are all on at night. A theme whose night has no `lighting.sun` keeps
|
|
42
|
-
the default daylight sun, so its lights stay off; see
|
|
43
|
-
[sun and light](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/docs/sun-and-light.md).
|
|
44
|
-
`on` reports how far they have switched on, from 0 to 1, `stats` the lamps on screen, and
|
|
45
|
-
`dispose()` takes the layer off the map.
|
|
46
|
-
|
|
47
|
-
## What the light comes from
|
|
48
|
-
|
|
49
|
-
The layer reads the source's z15 tiles round the camera, the zoom at which World carries its street
|
|
50
|
-
detail:
|
|
51
|
-
|
|
52
|
-
- Lamps from World's `street_furniture` points whose `subclass` is `street_lamp`. Where the data
|
|
53
|
-
gives them, a lamp's `height`, `lamp_mount`, `light_count`, `lamp_type` and `light_colour` set how
|
|
54
|
-
high it stands, how far its light reaches and its colour: sodium lamps shine orange, LED and
|
|
55
|
-
metal-halide lamps white. Other lamps take the map's light colour.
|
|
56
|
-
- Streets in World's `transportation` layer, and pavements in its `sidewalk` layer, that the data
|
|
57
|
-
maps as lit (`lit`). A street mapped as unlit never takes light.
|
|
58
|
-
|
|
59
|
-
How much of this a city's data holds varies widely: some map most of their lamps or most of their
|
|
60
|
-
lit streets, others almost none. Where the data says nothing, the streets stay dark.
|
|
61
|
-
|
|
62
|
-
## Design the lights in the map
|
|
63
|
-
|
|
64
|
-
The map describes its street lights in its roads module, next to the other details drawn from
|
|
65
|
-
street furniture, and publishes them with its style for every theme; `stats.declared` tells whether
|
|
66
|
-
it does. Without an enabled description the renderer stays off and mounts no layer:
|
|
67
|
-
|
|
68
|
-
<!-- docs:check -->
|
|
69
|
-
|
|
70
|
-
```ts
|
|
71
|
-
import {defineMap, fixed, refine} from '@tileflow/core';
|
|
72
|
-
import {streets} from '@tileflow/maps';
|
|
73
|
-
|
|
74
|
-
export default defineMap({
|
|
75
|
-
id: 'night-city',
|
|
76
|
-
name: 'Night city',
|
|
77
|
-
version: 1,
|
|
78
|
-
extends: streets,
|
|
79
|
-
modules: {
|
|
80
|
-
// Sodium-orange light, a little brighter, on every street of tiles that map few lamps.
|
|
81
|
-
roads: refine({
|
|
82
|
-
streetLights: {
|
|
83
|
-
enabled: true,
|
|
84
|
-
color: fixed('#ffb35c', {reason: 'Constant sodium-lamp color.'}),
|
|
85
|
-
intensity: 1.3,
|
|
86
|
-
estimate: 'streets',
|
|
87
|
-
},
|
|
88
|
-
}),
|
|
89
|
-
},
|
|
90
|
-
});
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
`estimate` chooses where the layer adds light the data does not map as lamps:
|
|
94
|
-
|
|
95
|
-
- `lit` (the default): along the streets and pavements mapped as lit.
|
|
96
|
-
- `streets`: also along streets the data says nothing about, in tiles where the data maps few
|
|
97
|
-
lamps. This invents light, as night windows do, for maps that want every street lit; a tile whose
|
|
98
|
-
data maps its lamps keeps to them.
|
|
99
|
-
- `none`: only mapped lamps shine.
|
|
100
|
-
|
|
101
|
-
Estimated light keeps to the middle of its street and shows no lamp head, so it reads as a lit
|
|
102
|
-
street rather than as lamps that may not stand there.
|
|
103
|
-
|
|
104
|
-
`color` is the light of the lamps whose data gives no colour, a warm white by default, and
|
|
105
|
-
`intensity` scales the light from 0 to 2 (1 by default); both may be theme tokens and mix during a
|
|
106
|
-
blend. These settings apply only after `enabled: true`; `streetLights: {enabled: false}` gives
|
|
107
|
-
the map none.
|
|
108
|
-
|
|
109
|
-
## Options
|
|
110
|
-
|
|
111
|
-
The layer follows the compiled map by default. `createTileflowStreetLights({map, controller,
|
|
112
|
-
enabled: true})` explicitly enables the fallback design for a style without street-light metadata;
|
|
113
|
-
`enabled: false` keeps the renderer off even when the map declares lights.
|
|
114
|
-
|
|
115
|
-
The delivery options are `minzoom` (14 by default) and `maxTiles` (25
|
|
116
|
-
by default, at most 64) bound where and how far the lights shine, `beforeId` places the layer before
|
|
117
|
-
another one, and `transformRequest` applies the map's request rules to the tiles it reads.
|
|
118
|
-
|
|
119
|
-
Layers that read the same source share each tile's download, so the street lights and the 3D
|
|
120
|
-
buildings fetch a tile once between them. The lamps are placed in the worker the page's 3D layers
|
|
121
|
-
share, which decodes each tile once for all of them.
|
|
122
|
-
|
|
123
|
-
## Limits
|
|
124
|
-
|
|
125
|
-
- Mercator only; the layer draws nothing below its `minzoom`.
|
|
126
|
-
- The light falls on the ground; walls the lamps face are not lit by them.
|
|
127
|
-
- No terrain: lamps stand on flat ground.
|
package/docs/street-sky.md
DELETED
|
@@ -1,156 +0,0 @@
|
|
|
1
|
-
# Street sky
|
|
2
|
-
|
|
3
|
-
A map's `sky` paints the sky above the horizon when the camera tilts up the street, in either
|
|
4
|
-
projection: blue by day, warm at dusk, dark with stars at night. Install `@tileflow/core` and
|
|
5
|
-
`@tileflow/maps` and use a browser adapter from the same compatible SDK release. Streets declares a
|
|
6
|
-
sky in every theme; the example extends it and keeps its sky.
|
|
7
|
-
|
|
8
|
-
<!-- docs:check -->
|
|
9
|
-
|
|
10
|
-
```ts
|
|
11
|
-
import {defineMap} from '@tileflow/core';
|
|
12
|
-
import {streets} from '@tileflow/maps';
|
|
13
|
-
|
|
14
|
-
export default defineMap({
|
|
15
|
-
id: 'street-level',
|
|
16
|
-
version: 1,
|
|
17
|
-
extends: streets,
|
|
18
|
-
view: {center: [-3.6904, 40.4493], zoom: 17, bearing: 8, pitch: 80},
|
|
19
|
-
});
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
The view looks north along Paseo de la Castellana in Madrid, with the sky above the skyline.
|
|
23
|
-
Coordinates are longitude, then latitude.
|
|
24
|
-
|
|
25
|
-
## Camera pitch
|
|
26
|
-
|
|
27
|
-
React, Vue, Svelte, the Dev preview, and browser capture create maps with a maximum pitch of 85
|
|
28
|
-
degrees, `tileflowMaxPitch`, instead of MapLibre's default of 60. Every portable view already admits
|
|
29
|
-
pitch 0–85. Pass `mapOptions: {maxPitch}` to lower the limit for one map. A map constructed directly
|
|
30
|
-
with MapLibre keeps MapLibre's default unless it sets `maxPitch: tileflowMaxPitch` itself.
|
|
31
|
-
|
|
32
|
-
The React Native surface still uses the native engines' 60-degree limit.
|
|
33
|
-
|
|
34
|
-
## Configure the sky
|
|
35
|
-
|
|
36
|
-
`sky: true` uses the defaults. An options object replaces an inherited sky atomically, and
|
|
37
|
-
`sky: false` removes it.
|
|
38
|
-
|
|
39
|
-
| Option | Default | Meaning |
|
|
40
|
-
| --------------- | --------- | ----------------------------------------------------------------- |
|
|
41
|
-
| `color` | `#5c9ce6` | The sky overhead |
|
|
42
|
-
| `horizonColor` | `#dcebf7` | The pale band along the horizon, also 3D terrain's distance fog |
|
|
43
|
-
| `horizonBlend` | `0.6` | How far up the band reaches, as a share of half the view's height |
|
|
44
|
-
| `glowColor` | `#ffc68a` | The light round a low sun, which glows on the horizon towards it |
|
|
45
|
-
| `starIntensity` | `0.6` | The brightest the stars shine, from 0 (none) to 1 |
|
|
46
|
-
|
|
47
|
-
Colors take `token.color(...)`, color operations, or `fixed(color, {reason})`, and must resolve to
|
|
48
|
-
opaque colors. Numbers take `token.number(...)`, `fixed(number, {reason})`, or a number, and must
|
|
49
|
-
resolve to 0–1. Unknown properties are rejected. Because tokens resolve per theme, one declaration
|
|
50
|
-
gives each theme its own sky. Streets uses its themes' `sky.color`, `sky.horizon`,
|
|
51
|
-
`sky.horizonBlend`, and `sky.glow` tokens:
|
|
52
|
-
|
|
53
|
-
```ts
|
|
54
|
-
sky: {
|
|
55
|
-
color: token.color('sky.color'),
|
|
56
|
-
horizonColor: token.color('sky.horizon'),
|
|
57
|
-
horizonBlend: token.number('sky.horizonBlend'),
|
|
58
|
-
glowColor: token.color('sky.glow'),
|
|
59
|
-
starIntensity: 0.6,
|
|
60
|
-
},
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
A map that replaces Streets' themes supplies those tokens or declares its own `sky`.
|
|
64
|
-
|
|
65
|
-
## A sky that follows the sun
|
|
66
|
-
|
|
67
|
-
When an application places the sun with the theme controller's `setSun`, by direction or by the
|
|
68
|
-
real sun of a date and place, the sky follows its height continuously instead of staying on the
|
|
69
|
-
theme's preset. Above about 14 degrees the sky is the day theme's; it warms into the dawn or dusk
|
|
70
|
-
theme's sky as the sun nears the horizon, using dawn while the sun stands in the eastern half of
|
|
71
|
-
the sky and dusk in the western half; it holds that sky within two degrees of sunrise or sunset,
|
|
72
|
-
and it darkens into the night theme's sky as twilight ends, about ten degrees below the horizon.
|
|
73
|
-
The themes come from the map's `timeOfDay` family of the theme on screen, and every colour is
|
|
74
|
-
resolved from that theme's own tokens, so a Monochrome family stays grey and a client's own
|
|
75
|
-
family keeps its palette. A family with only one twilight uses it at both ends of the day; a theme
|
|
76
|
-
outside a family, or a family without a day and a night theme, keeps its own sky.
|
|
77
|
-
`setSun(undefined)` returns the sky to the themes. The map's colours on the ground stay those of
|
|
78
|
-
the theme or blend on screen; pair `setSun` with `setBlend` to move them too. See
|
|
79
|
-
[sun and light](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/docs/sun-and-light.md).
|
|
80
|
-
|
|
81
|
-
<!-- docs:check -->
|
|
82
|
-
|
|
83
|
-
```ts
|
|
84
|
-
import type {TileflowThemeController} from '@tileflow/core/browser';
|
|
85
|
-
|
|
86
|
-
export function sunsetOverMadrid(controller: TileflowThemeController) {
|
|
87
|
-
// 19:15 in Madrid on 21 October 2026: the sun stands 1.5 degrees above the western horizon.
|
|
88
|
-
return controller.setSun({date: Date.UTC(2026, 9, 21, 17, 15), location: [-3.69, 40.45]});
|
|
89
|
-
}
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## Glow, sun and stars
|
|
93
|
-
|
|
94
|
-
A low sun glows on the horizon towards it, in the theme's `glowColor` or, for a sun an application
|
|
95
|
-
placed, in the glow of its hour. The glow is strongest as the sun touches the horizon, fades by
|
|
96
|
-
mid-morning, and is gone once the sun is about nine degrees below. While the sun is low and above
|
|
97
|
-
the horizon, its disc shows too. The sun is the one the theme controller shows, so its
|
|
98
|
-
disc stands where the 3D scene's shadows say it is; without a controller, the theme's own sun.
|
|
99
|
-
|
|
100
|
-
Stars come out as the sky darkens: a night sky shows them, a day or dusk sky does not, and a
|
|
101
|
-
time-of-day blend or a placed sun moving into night brings them in with the dark. They sit on a
|
|
102
|
-
fixed dome, so they turn with the camera's bearing and pitch but not with its position.
|
|
103
|
-
|
|
104
|
-
The glow, the sun, and the stars draw beneath every map layer and only where nothing else has
|
|
105
|
-
drawn, so buildings and trees stand in front of them. With 3D terrain enabled, they are not
|
|
106
|
-
drawn.
|
|
107
|
-
|
|
108
|
-
## Distance haze
|
|
109
|
-
|
|
110
|
-
Above 45 degrees of pitch, the far city fades into the sky's horizon color, so streets meet the sky
|
|
111
|
-
instead of ending in a sharp edge. The haze starts at the camera's distance to the map's center and
|
|
112
|
-
is complete where MapLibre stops drawing the ground, about 6.7 times farther, where the sky starts in
|
|
113
|
-
the same color. It comes in between 45 and 60 degrees, follows the current sky (theme blends
|
|
114
|
-
and a sky that follows the sun included), and leaves the globe alone. Place and POI labels above the
|
|
115
|
-
3D layers stay clear.
|
|
116
|
-
|
|
117
|
-
Tileflow's 3D buildings stand on the tiles round the camera, up to a limit of 25 by default, which
|
|
118
|
-
end well before the horizon. Where that ring ends nearer than the horizon, the haze fits itself to
|
|
119
|
-
it: it is nine-tenths complete at the nearest point where the ring's far side shows across the view,
|
|
120
|
-
and complete soon after, never nearer than three camera distances for the nine-tenths, so a renderer
|
|
121
|
-
held to few tiles does not pull the haze in. Buildings on the ring's far side sink into the ground
|
|
122
|
-
over its last fifth, and nothing past the ring or past the complete haze is drawn. Buildings on the
|
|
123
|
-
near side of a ring held short by the tile limit keep standing.
|
|
124
|
-
|
|
125
|
-
The haze is drawn twice, from one model: Tileflow's 3D buildings, trees, and placed models haze
|
|
126
|
-
each pixel by its depth, and a band over the flat map, just under the first 3D layer, hazes the
|
|
127
|
-
flat ground by the depth its screen row has. Road names and one-way arrows that a style draws on the
|
|
128
|
-
ground before its 3D layers fade with the ground, and so do distant 3D shadows, contact shade, and
|
|
129
|
-
night floodlight. A style without a sky, or whose sky has no opaque horizon color, has no haze.
|
|
130
|
-
|
|
131
|
-
## Browser integration
|
|
132
|
-
|
|
133
|
-
The compiler emits MapLibre `sky` in every concrete style and versioned `metadata['tileflow:sky']`
|
|
134
|
-
with the star brightness, the glow, and, for a theme in a time-of-day family, the family's skies;
|
|
135
|
-
`readTileflowSky` reads it and `tileflowSkyAtSun` mixes the sky of a sun's height. MapLibre draws the sky itself, so raw MapLibre consumers see it. On a
|
|
136
|
-
globe, the sky blends into MapLibre's atmosphere at world zooms; when a map also declares
|
|
137
|
-
`atmosphere`, the sky's colors replace the atmosphere's sky colors while its space background and
|
|
138
|
-
globe stars stay.
|
|
139
|
-
|
|
140
|
-
React, Vue, Svelte, and standalone browser capture draw the glow, the sun, the stars, and the flat
|
|
141
|
-
map's haze through `attachTileflowAtmosphere(map)`. A direct MapLibre integration calls that
|
|
142
|
-
function, or `attachTileflowSky(map)` or `attachTileflowSkyHaze(map)` from `@tileflow/core/browser`
|
|
143
|
-
for one of them alone, after constructing the map; each returns a cleanup function. The sky is the
|
|
144
|
-
custom layer `tileflow-sky` at the bottom of the layer stack, and the haze the custom layer
|
|
145
|
-
`tileflow-sky-haze` under the first 3D layer, or the first label layer without one. Tileflow's 3D
|
|
146
|
-
layers haze themselves. A sky that follows the sun needs the theme controller, which writes the
|
|
147
|
-
sky's colours; raw MapLibre consumers see each theme's own sky.
|
|
148
|
-
|
|
149
|
-
These helpers can attach before the first style is set. They wait for style events, follow style
|
|
150
|
-
replacements, and tolerate a cleared style. Dispose them when the integration releases the map.
|
|
151
|
-
|
|
152
|
-
MapLibre applies its own fog only to 3D terrain; with 3D terrain enabled, the flat haze band is not
|
|
153
|
-
drawn and the terrain's fog takes its place. Other layers drawn by an application, such as
|
|
154
|
-
`fill-extrusion` layers, stay sharp. Native artifacts remove the sky during preparation and record
|
|
155
|
-
the removal; see the
|
|
156
|
-
[native artifact profile](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/docs/native-artifact-profile.md).
|
package/docs/style-states.md
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# Style states
|
|
2
|
-
|
|
3
|
-
A theme can read a value that the application sets once for the whole style, such as whether
|
|
4
|
-
anything is selected. The theme reads it with `expr.globalState(name)`; the application sets it with
|
|
5
|
-
the theme controller's `setState(name, value)`. MapLibre calls these values global state (GL JS 5.6
|
|
6
|
-
or later).
|
|
7
|
-
|
|
8
|
-
## Read a state in a theme
|
|
9
|
-
|
|
10
|
-
A state reads `null` until the application sets it, so wrap it in a typed assertion with a fallback.
|
|
11
|
-
To let a value move smoothly, make the state a number and interpolate on it:
|
|
12
|
-
|
|
13
|
-
<!-- docs:check -->
|
|
14
|
-
|
|
15
|
-
```ts
|
|
16
|
-
import {expr} from '@tileflow/core';
|
|
17
|
-
|
|
18
|
-
// 0 shows the standing highlight, 1 the quiet plate; values between mix the two.
|
|
19
|
-
const selection = expr.toNumber(expr.globalState('selection'), 0);
|
|
20
|
-
export const captionPlate = expr.interpolate({kind: 'linear'}, selection, [
|
|
21
|
-
[0, '#ef5f57'],
|
|
22
|
-
[1, '#fff9ee'],
|
|
23
|
-
]);
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
A boolean works too, through `expr.case`, but it can only switch.
|
|
27
|
-
|
|
28
|
-
## Set a state from the application
|
|
29
|
-
|
|
30
|
-
This example assumes an existing MapLibre map named `map` that shows the `light` theme of a
|
|
31
|
-
published Tileflow map:
|
|
32
|
-
|
|
33
|
-
<!-- docs:check -->
|
|
34
|
-
|
|
35
|
-
```ts
|
|
36
|
-
import {createTileflowThemeController, type TileflowStyleSwitchMap} from '@tileflow/core/browser';
|
|
37
|
-
|
|
38
|
-
// A MapLibre map satisfies TileflowStyleSwitchMap.
|
|
39
|
-
export function selectionStates(map: TileflowStyleSwitchMap, styleUrl: string) {
|
|
40
|
-
const controller = createTileflowThemeController({
|
|
41
|
-
initial: {style: styleUrl, theme: 'light'},
|
|
42
|
-
map,
|
|
43
|
-
});
|
|
44
|
-
void controller.setState('selection', 0);
|
|
45
|
-
return {
|
|
46
|
-
select: () => controller.setState('selection', 1, {transition: {duration: 300}}),
|
|
47
|
-
clear: () => controller.setState('selection', 0, {transition: {duration: 300}}),
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
A number eases from the value the map shows to the new one over the transition, so the plate mixes
|
|
53
|
-
smoothly from one colour to the other. Booleans, strings, `null`, and a number set for the first
|
|
54
|
-
time change at once, so set a starting value before easing it. A browser preference for
|
|
55
|
-
reduced motion changes at once. Each call supersedes an easing of the same state still in progress,
|
|
56
|
-
which resolves with `status: 'superseded'`; the new easing starts from where the old one stood.
|
|
57
|
-
|
|
58
|
-
States stay through `setTheme` and every `setBlend`: the controller writes them again after each
|
|
59
|
-
new style. `getState(name)` returns the value set last.
|
|
60
|
-
|
|
61
|
-
## Keep eased values free of feature data
|
|
62
|
-
|
|
63
|
-
Keep a value that eases on a state free of feature data and feature state. MapLibre evaluates such
|
|
64
|
-
a value for the whole layer at each frame. A value that also reads a feature's data or state is
|
|
65
|
-
evaluated per feature when its tiles are laid out, so each change of the state lays them out
|
|
66
|
-
again: the value follows late, in steps, and each frame costs far more. Put the per-feature choice
|
|
67
|
-
in another layer, or let the application draw the feature it marks.
|
|
68
|
-
|
|
69
|
-
## Cost
|
|
70
|
-
|
|
71
|
-
Each frame of an easing sets the state once, and MapLibre then evaluates again every paint value
|
|
72
|
-
that reads it. A state read by a few layers costs little; a state read by most layers of a map can
|
|
73
|
-
cost more per frame than the blend itself on slower devices.
|
package/docs/sun-and-light.md
DELETED
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
# Sun and light
|
|
2
|
-
|
|
3
|
-
A theme can describe its sun and the light from its sky, as a light preset for that theme: a high
|
|
4
|
-
sun in white light for a day theme, a low amber sun in the west for an evening theme, a cold moon
|
|
5
|
-
with faint shadows for a night theme. In a browser, the theme controller returns the sun the map
|
|
6
|
-
shows, mixed between neighbouring themes during a blend, so an application's own 3D layers can light
|
|
7
|
-
their models and cast their shadows from it. An application can also place the sun itself, by
|
|
8
|
-
direction or by the real position of the sun for a date and place.
|
|
9
|
-
|
|
10
|
-
MapLibre lights its `fill-extrusion` layers with one directional light and casts no shadows. When a
|
|
11
|
-
theme describes a sun, the map's light is anchored to the map and points from the sun, so Tileflow's
|
|
12
|
-
3D buildings are shaded from where it stands. Shadows, ambient occlusion and lit windows are for the
|
|
13
|
-
application's own WebGL layers to draw, from the values `getSun()` returns.
|
|
14
|
-
|
|
15
|
-
## Describe a theme's sun
|
|
16
|
-
|
|
17
|
-
Set `lighting.sun` and `lighting.ambient` in the theme. Every value is optional; unset values take
|
|
18
|
-
the defaults in `tileflowDefaultSunPreset` (azimuth 210°, altitude 60°, white light at 0.2, full
|
|
19
|
-
shadow strength, a white sky at 0.8 for soft daylight shadows):
|
|
20
|
-
|
|
21
|
-
<!-- docs:check -->
|
|
22
|
-
|
|
23
|
-
```ts
|
|
24
|
-
import {defineTheme} from '@tileflow/core';
|
|
25
|
-
import {streetsThemes} from '@tileflow/maps';
|
|
26
|
-
|
|
27
|
-
export const evening = defineTheme(streetsThemes.dark, {
|
|
28
|
-
id: 'city-evening',
|
|
29
|
-
version: 1,
|
|
30
|
-
colorScheme: 'dark',
|
|
31
|
-
lighting: {
|
|
32
|
-
// Degrees clockwise from north, and above the horizon.
|
|
33
|
-
sun: {azimuth: 285, altitude: 9, color: '#ff9a50', intensity: 1, shadowIntensity: 0.9},
|
|
34
|
-
ambient: {color: '#5a4290', intensity: 0.3},
|
|
35
|
-
},
|
|
36
|
-
});
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
`intensity` values run from 0 to 1. `shadowIntensity` says how dark the shadows the sun casts fall,
|
|
40
|
-
from 0 (none) to 1. A theme derived from another changes single values of its sun and sky light; the
|
|
41
|
-
others are inherited. The compiled style carries the resolved sun in its metadata
|
|
42
|
-
(`tileflow:sun`) and a map-anchored `light` that points from it; MapLibre's `anchor` and the
|
|
43
|
-
direction in `lighting.position` no longer apply to a theme with a sun. A theme without `sun` or
|
|
44
|
-
`ambient` compiles exactly as before.
|
|
45
|
-
|
|
46
|
-
## Replace inherited lighting
|
|
47
|
-
|
|
48
|
-
`defineTheme(base, definition)` normally merges lighting field by field. An empty `lighting`,
|
|
49
|
-
`sun`, or `ambient` object therefore preserves inherited values. Use the existing `reset()`
|
|
50
|
-
operation to remove a preset explicitly while keeping the base theme's palette and typography:
|
|
51
|
-
|
|
52
|
-
<!-- docs:check -->
|
|
53
|
-
|
|
54
|
-
```ts
|
|
55
|
-
import {defineTheme, reset} from '@tileflow/core';
|
|
56
|
-
import {streetsThemes} from '@tileflow/maps';
|
|
57
|
-
|
|
58
|
-
export const studio = defineTheme(streetsThemes.light, {
|
|
59
|
-
id: 'studio',
|
|
60
|
-
version: 1,
|
|
61
|
-
colorScheme: 'light',
|
|
62
|
-
lighting: {
|
|
63
|
-
sun: reset(),
|
|
64
|
-
ambient: reset(),
|
|
65
|
-
anchor: 'viewport',
|
|
66
|
-
position: [1.15, 180, 40],
|
|
67
|
-
color: '#FFFFFF',
|
|
68
|
-
intensity: 0.15,
|
|
69
|
-
},
|
|
70
|
-
});
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
Removing both presets lets the native extrusion light use the authored `anchor` and `position`.
|
|
74
|
-
Resetting only `sun` keeps an inherited ambient preset, and resetting only `ambient` keeps the sun;
|
|
75
|
-
the missing counterpart then uses the SDK defaults. `lighting: reset()` clears all inherited
|
|
76
|
-
lighting properties. A direct property such as `position`, `color`, or `intensity` can also be
|
|
77
|
-
reset. The result is a complete theme with those properties absent; it contains no reset nodes.
|
|
78
|
-
To replace a whole sun or ambient object, first derive a theme that resets that object, then derive
|
|
79
|
-
the replacement values from the cleared theme.
|
|
80
|
-
|
|
81
|
-
Removing a preset does not turn off the renderer's lighting, cast shadows, or ambient occlusion.
|
|
82
|
-
The SDK's 3D scene uses its fallback light when no preset is published. For a graphic building
|
|
83
|
-
style, choose the building module's `lighting: 'style'`, `shadows: false`, and `occlusion: false`
|
|
84
|
-
explicitly. A single static theme needs no time-of-day family or running clock.
|
|
85
|
-
|
|
86
|
-
## Read the sun in an application
|
|
87
|
-
|
|
88
|
-
`themeController.getSun()` returns the sun the map shows:
|
|
89
|
-
|
|
90
|
-
- `azimuth` and `altitude`, in degrees, and `direction`, a unit vector towards the sun with x east,
|
|
91
|
-
y north and z up.
|
|
92
|
-
- `color` and `rgb` (sRGB channels from 0 to 1) of the direct light, and its `intensity`, which fades
|
|
93
|
-
to 0 over the sun's last degrees above the horizon: a sun below it lights nothing.
|
|
94
|
-
- `ambient`, the light from the sky, with its own `color`, `rgb` and `intensity`.
|
|
95
|
-
- `shadowIntensity`, how dark the sun's shadows fall.
|
|
96
|
-
- `brightness`, how bright flat, open ground is under this light, from 0 to 1: the sky's light plus
|
|
97
|
-
the sun's at its height, each weighted by its colour's luminance. Use it to switch lamps or windows
|
|
98
|
-
on as a scene darkens, whatever theme or sun lights it.
|
|
99
|
-
- `source`: `theme`, `direction`, or `date`.
|
|
100
|
-
|
|
101
|
-
During a blend the sun is mixed between the neighbouring themes' suns: the azimuth turns the short
|
|
102
|
-
way round, colours mix in OKLab as the map's colours do, and numbers mix linearly. Read it when a
|
|
103
|
-
custom layer draws; the map redraws whenever the sun changes.
|
|
104
|
-
|
|
105
|
-
## Place the sun
|
|
106
|
-
|
|
107
|
-
`setSun` places the sun by direction, or by the real sun of a date over a place given as
|
|
108
|
-
`[longitude, latitude]`, the map's centre when it is left out. The themes keep the sun's colours,
|
|
109
|
-
strengths and shadow strength; only its direction changes. A map with a
|
|
110
|
-
[street sky](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/docs/street-sky.md)
|
|
111
|
-
also takes the sky of the sun's hour from its time-of-day themes. `setSun(undefined)` returns both
|
|
112
|
-
to the themes. This example assumes an existing MapLibre map and a controller for it:
|
|
113
|
-
|
|
114
|
-
<!-- docs:check -->
|
|
115
|
-
|
|
116
|
-
```ts
|
|
117
|
-
import type {TileflowThemeController} from '@tileflow/core/browser';
|
|
118
|
-
|
|
119
|
-
export function followTheRealSun(controller: TileflowThemeController) {
|
|
120
|
-
// Where the sun stands over Miami Beach now; a later call moves it on.
|
|
121
|
-
void controller.setSun({date: Date.now(), location: [-80.13, 25.79]});
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export function lowWesternSun(controller: TileflowThemeController) {
|
|
125
|
-
// Turns the short way round to the west over a second.
|
|
126
|
-
return controller.setSun({azimuth: 270, altitude: 8}, {transition: {duration: 1000}});
|
|
127
|
-
}
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
A request that follows an animation, such as a clock that moves every frame, passes no transition.
|
|
131
|
-
A request with a transition supersedes one still in progress, which resolves with
|
|
132
|
-
`status: 'superseded'`; a browser preference for reduced motion changes at once.
|
|
133
|
-
|
|
134
|
-
`tileflowSunPosition(date, [longitude, latitude])` returns the sun's azimuth and apparent altitude,
|
|
135
|
-
with atmospheric refraction, from NOAA's solar equations (accurate to about a hundredth of a degree
|
|
136
|
-
for years 1800 to 2200). It runs anywhere, without a map:
|
|
137
|
-
|
|
138
|
-
<!-- docs:check -->
|
|
139
|
-
|
|
140
|
-
```ts
|
|
141
|
-
import {tileflowSunPosition} from '@tileflow/core/browser';
|
|
142
|
-
|
|
143
|
-
// Solar noon in Miami at the June solstice, 17:22 UTC: the sun stands about 87.7° high, due south.
|
|
144
|
-
export const noon = tileflowSunPosition(Date.UTC(2026, 5, 21, 17, 22), [-80.19, 25.77]);
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## Light a custom layer
|
|
148
|
-
|
|
149
|
-
For a custom WebGL layer that draws 3D content, light each surface with the sky's light, plus the
|
|
150
|
-
sun's where the surface faces it and nothing stands in the way:
|
|
151
|
-
|
|
152
|
-
light = ambient.rgb × ambient.intensity + rgb × intensity × max(normal · direction, 0) × (1 − shadowIntensity × shadowed)
|
|
153
|
-
|
|
154
|
-
Convert the colours to linear light before adding them and back to sRGB after. MapLibre's own 2D
|
|
155
|
-
layers take no shadows, so a layer that casts shadows on the ground darkens the map it is drawn over:
|
|
156
|
-
draw the ground under the scene, after the scene's own geometry, with multiplying blending and a
|
|
157
|
-
depth test against it.
|
|
158
|
-
|
|
159
|
-
## Limits
|
|
160
|
-
|
|
161
|
-
- MapLibre shades extrusions with its one light; it has no shadow maps, ambient occlusion or
|
|
162
|
-
emissive light. The sun gives custom layers what they need to draw them.
|
|
163
|
-
- Themes interpolate the sun linearly between presets; a request by date follows the real sun, not
|
|
164
|
-
the themes' presets.
|
|
165
|
-
- Style expressions cannot read the sun yet. An application that wants a theme to react to it sets a
|
|
166
|
-
[style state](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/docs/style-states.md)
|
|
167
|
-
from `getSun().brightness`.
|