@tileflow/core 0.1.0-alpha.32 → 0.1.0-alpha.33
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 +33 -1
- package/THIRD_PARTY_NOTICES.md +25 -2
- package/dist/browser.d.ts +889 -1
- package/dist/browser.js +6336 -1486
- package/dist/build.d.ts +5 -4
- package/dist/build.js +625 -205
- package/dist/{capture-scene-BaAJjGq7.d.ts → capture-shot-ChPQvPyi.d.ts} +121 -1
- package/dist/capture.d.ts +1 -1
- package/dist/capture.js +218 -0
- package/dist/config-reference.json +300 -4
- package/dist/{icon-composition-Befmn-zZ.d.ts → icon-composition-CSnN2-Xt.d.ts} +130 -2
- package/dist/index.d.ts +49 -5
- package/dist/index.js +1617 -764
- package/dist/native.js +1893 -1884
- package/docs/application-tile-reading.md +80 -0
- package/docs/authoring-model.md +11 -2
- package/docs/buildings-3d.md +168 -0
- package/docs/camera-moves-and-tile-cache.md +112 -0
- package/docs/capture-scenes.md +4 -0
- package/docs/capture-shots.md +173 -0
- package/docs/depth-markers.md +65 -0
- package/docs/public-api-and-browser-subpath.md +3 -3
- package/docs/route-drawing.md +191 -0
- package/docs/street-lights.md +80 -0
- package/docs/sun-and-light.md +125 -0
- package/docs/themes-and-module-styles.md +7 -0
- package/package.json +4 -1
|
@@ -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.
|
|
@@ -0,0 +1,80 @@
|
|
|
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
|
+
It is a custom WebGL2 layer for MapLibre GL JS, drawn above the map's buildings and below its
|
|
10
|
+
labels. When `createTileflowBuildings3D` raises the buildings, they hide the lamps behind them. It
|
|
11
|
+
needs WebGL2 and the Mercator projection, and shines from zoom 14 by default.
|
|
12
|
+
|
|
13
|
+
## Light the streets
|
|
14
|
+
|
|
15
|
+
This example assumes an existing MapLibre map showing a Tileflow map whose vector source is called
|
|
16
|
+
`tileflow`, as Tileflow's maps call World, and a theme controller for it:
|
|
17
|
+
|
|
18
|
+
<!-- docs:check -->
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import {
|
|
22
|
+
createTileflowStreetLights,
|
|
23
|
+
type TileflowStreetLightsMap,
|
|
24
|
+
type TileflowThemeController,
|
|
25
|
+
} from '@tileflow/core/browser';
|
|
26
|
+
|
|
27
|
+
export function lightTheStreets(map: TileflowStreetLightsMap, controller: TileflowThemeController) {
|
|
28
|
+
// The lights switch on as the theme's or the application's sun darkens the map.
|
|
29
|
+
return createTileflowStreetLights({map, controller});
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The lights follow `controller.getSun()`: they switch on as its `brightness` falls through dusk, each
|
|
34
|
+
lamp at its own moment, and are all on at night. A theme whose night has no `lighting.sun` keeps
|
|
35
|
+
the default daylight sun, so its lights stay off; see
|
|
36
|
+
[sun and light](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/docs/sun-and-light.md).
|
|
37
|
+
`on` reports how far they have switched on, from 0 to 1, `stats` the lamps on screen, and
|
|
38
|
+
`dispose()` takes the layer off the map.
|
|
39
|
+
|
|
40
|
+
## What the light comes from
|
|
41
|
+
|
|
42
|
+
The layer reads the source's z15 tiles round the camera, the zoom at which World carries its street
|
|
43
|
+
detail:
|
|
44
|
+
|
|
45
|
+
- Lamps from World's `street_furniture` points whose `subclass` is `street_lamp`. Where the data
|
|
46
|
+
gives them, a lamp's `height`, `lamp_mount`, `light_count`, `lamp_type` and `light_colour` set how
|
|
47
|
+
high it stands, how far its light reaches and its colour: sodium lamps shine orange, LED and
|
|
48
|
+
metal-halide lamps white. Other lamps take `color`, a warm white by default.
|
|
49
|
+
- Streets in World's `transportation` layer, and pavements in its `sidewalk` layer, that the data
|
|
50
|
+
maps as lit (`lit`). A street mapped as unlit never takes light.
|
|
51
|
+
|
|
52
|
+
How much of this a city's data holds varies widely: some map most of their lamps or most of their
|
|
53
|
+
lit streets, others almost none. Where the data says nothing, the streets stay dark.
|
|
54
|
+
|
|
55
|
+
`estimate` chooses where the layer adds light the data does not map as lamps:
|
|
56
|
+
|
|
57
|
+
- `lit` (the default): along the streets and pavements mapped as lit.
|
|
58
|
+
- `streets`: also along streets the data says nothing about, in tiles where the data maps few
|
|
59
|
+
lamps. This invents light, as night windows do, for maps that want every street lit; a tile whose
|
|
60
|
+
data maps its lamps keeps to them.
|
|
61
|
+
- `none`: only mapped lamps shine.
|
|
62
|
+
|
|
63
|
+
Estimated light keeps to the middle of its street and shows no lamp head, so it reads as a lit
|
|
64
|
+
street rather than as lamps that may not stand there.
|
|
65
|
+
|
|
66
|
+
## Options
|
|
67
|
+
|
|
68
|
+
`intensity` scales the light from 0 to 2 (1 by default). `minzoom` (14 by default) and `maxTiles`
|
|
69
|
+
(25 by default, at most 64) bound where and how far the lights shine. `beforeId` places the layer
|
|
70
|
+
before another one; `source` names a vector source other than `tileflow`; `transformRequest`
|
|
71
|
+
applies the map's request rules to the tiles the layer reads.
|
|
72
|
+
|
|
73
|
+
Layers that read the same source share each tile's download, so the street lights and the 3D
|
|
74
|
+
buildings fetch a tile once between them.
|
|
75
|
+
|
|
76
|
+
## Limits
|
|
77
|
+
|
|
78
|
+
- Mercator only; the layer draws nothing below its `minzoom`.
|
|
79
|
+
- The light falls on the ground; walls the lamps face are not lit by them.
|
|
80
|
+
- No terrain: lamps stand on flat ground.
|
|
@@ -0,0 +1,125 @@
|
|
|
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.5, full
|
|
19
|
+
shadows, a white sky at 0.5):
|
|
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
|
+
## Read the sun in an application
|
|
47
|
+
|
|
48
|
+
`themeController.getSun()` returns the sun the map shows:
|
|
49
|
+
|
|
50
|
+
- `azimuth` and `altitude`, in degrees, and `direction`, a unit vector towards the sun with x east,
|
|
51
|
+
y north and z up.
|
|
52
|
+
- `color` and `rgb` (sRGB channels from 0 to 1) of the direct light, and its `intensity`, which fades
|
|
53
|
+
to 0 over the sun's last degrees above the horizon: a sun below it lights nothing.
|
|
54
|
+
- `ambient`, the light from the sky, with its own `color`, `rgb` and `intensity`.
|
|
55
|
+
- `shadowIntensity`, how dark the sun's shadows fall.
|
|
56
|
+
- `brightness`, how bright flat, open ground is under this light, from 0 to 1: the sky's light plus
|
|
57
|
+
the sun's at its height, each weighted by its colour's luminance. Use it to switch lamps or windows
|
|
58
|
+
on as a scene darkens, whatever theme or sun lights it.
|
|
59
|
+
- `source`: `theme`, `direction`, or `date`.
|
|
60
|
+
|
|
61
|
+
During a blend the sun is mixed between the neighbouring themes' suns: the azimuth turns the short
|
|
62
|
+
way round, colours mix in OKLab as the map's colours do, and numbers mix linearly. Read it when a
|
|
63
|
+
custom layer draws; the map redraws whenever the sun changes.
|
|
64
|
+
|
|
65
|
+
## Place the sun
|
|
66
|
+
|
|
67
|
+
`setSun` places the sun by direction, or by the real sun of a date over a place given as
|
|
68
|
+
`[longitude, latitude]`, the map's centre when it is left out. The themes keep the sun's colours,
|
|
69
|
+
strengths and shadow strength; only its direction changes. `setSun(undefined)` returns it to the
|
|
70
|
+
themes. This example assumes an existing MapLibre map and a controller for it:
|
|
71
|
+
|
|
72
|
+
<!-- docs:check -->
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import type {TileflowThemeController} from '@tileflow/core/browser';
|
|
76
|
+
|
|
77
|
+
export function followTheRealSun(controller: TileflowThemeController) {
|
|
78
|
+
// Where the sun stands over Miami Beach now; a later call moves it on.
|
|
79
|
+
void controller.setSun({date: Date.now(), location: [-80.13, 25.79]});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function lowWesternSun(controller: TileflowThemeController) {
|
|
83
|
+
// Turns the short way round to the west over a second.
|
|
84
|
+
return controller.setSun({azimuth: 270, altitude: 8}, {transition: {duration: 1000}});
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
A request that follows an animation, such as a clock that moves every frame, passes no transition.
|
|
89
|
+
A request with a transition supersedes one still in progress, which resolves with
|
|
90
|
+
`status: 'superseded'`; a browser preference for reduced motion changes at once.
|
|
91
|
+
|
|
92
|
+
`tileflowSunPosition(date, [longitude, latitude])` returns the sun's azimuth and apparent altitude,
|
|
93
|
+
with atmospheric refraction, from NOAA's solar equations (accurate to about a hundredth of a degree
|
|
94
|
+
for years 1800 to 2200). It runs anywhere, without a map:
|
|
95
|
+
|
|
96
|
+
<!-- docs:check -->
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
import {tileflowSunPosition} from '@tileflow/core/browser';
|
|
100
|
+
|
|
101
|
+
// Solar noon in Miami at the June solstice, 17:22 UTC: the sun stands about 87.7° high, due south.
|
|
102
|
+
export const noon = tileflowSunPosition(Date.UTC(2026, 5, 21, 17, 22), [-80.19, 25.77]);
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Light a custom layer
|
|
106
|
+
|
|
107
|
+
For a custom WebGL layer that draws 3D content, light each surface with the sky's light, plus the
|
|
108
|
+
sun's where the surface faces it and nothing stands in the way:
|
|
109
|
+
|
|
110
|
+
light = ambient.rgb × ambient.intensity + rgb × intensity × max(normal · direction, 0) × (1 − shadowIntensity × shadowed)
|
|
111
|
+
|
|
112
|
+
Convert the colours to linear light before adding them and back to sRGB after. MapLibre's own 2D
|
|
113
|
+
layers take no shadows, so a layer that casts shadows on the ground darkens the map it is drawn over:
|
|
114
|
+
draw the ground under the scene, after the scene's own geometry, with multiplying blending and a
|
|
115
|
+
depth test against it.
|
|
116
|
+
|
|
117
|
+
## Limits
|
|
118
|
+
|
|
119
|
+
- MapLibre shades extrusions with its one light; it has no shadow maps, ambient occlusion or
|
|
120
|
+
emissive light. The sun gives custom layers what they need to draw them.
|
|
121
|
+
- Themes interpolate the sun linearly between presets; a request by date follows the real sun, not
|
|
122
|
+
the themes' presets.
|
|
123
|
+
- Style expressions cannot read the sun yet. An application that wants a theme to react to it sets a
|
|
124
|
+
[style state](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/docs/style-states.md)
|
|
125
|
+
from `getSun().brightness`.
|
|
@@ -15,6 +15,13 @@ same token keys, so changing a theme can never change map structure or silently
|
|
|
15
15
|
role. `defineTheme(base, definition)` is an authoring convenience that returns a fully materialized
|
|
16
16
|
document; it does not leave an inheritance edge in the resolved config.
|
|
17
17
|
|
|
18
|
+
Some optional tokens are for the application rather than the map's own layers. Route inks
|
|
19
|
+
(`route.line`, `route.casing`, `route.core`, `route.glow`, `route.alternative`,
|
|
20
|
+
`route.glow.opacity` and `route.core.opacity`) set how an application draws its routes; a theme
|
|
21
|
+
without them uses its colour scheme's defaults. The compiler publishes them in the style's metadata
|
|
22
|
+
and the theme controller returns them; see
|
|
23
|
+
[route drawing](https://github.com/tileflow/tileflow-sdk/blob/main/packages/core/docs/route-drawing.md).
|
|
24
|
+
|
|
18
25
|
The key in the `themes` record is its concrete runtime selector and output-path segment. The
|
|
19
26
|
theme's own `id` and `version` are its editorial identity and build provenance, so they need not
|
|
20
27
|
equal that key. Concrete keys may be names such as `day` and `night`; every `systemThemes.light` or
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tileflow/core",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.33",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"description": "Typed Tileflow config and MapLibre style compiler.",
|
|
6
6
|
"type": "module",
|
|
@@ -81,7 +81,10 @@
|
|
|
81
81
|
"zod": "^4.4.3"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
|
+
"@mapbox/vector-tile": "3.0.0",
|
|
85
|
+
"earcut": "3.2.4",
|
|
84
86
|
"maplibre-contour": "0.1.0",
|
|
87
|
+
"pbf": "5.1.2",
|
|
85
88
|
"pmtiles": "4.4.0",
|
|
86
89
|
"whatwg-url": "15.1.0"
|
|
87
90
|
},
|