@tileflow/core 0.1.0-alpha.44 → 0.1.0-alpha.46

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 CHANGED
@@ -11,9 +11,8 @@ it does not start a server, prepare files on disk, render a browser map, or depl
11
11
  npm install @tileflow/core@alpha @tileflow/maps@alpha
12
12
  ```
13
13
 
14
- `@tileflow/maps` is needed for the official map used below, not for every Core application. Use
15
- ES module imports. For config loading and asset preparation, use the Node.js 22+ CLI or a build
16
- integration. Browser applications should use a framework adapter with prepared assets.
14
+ Use ES modules. `@tileflow/maps` supplies the official map below. Load configs and prepare assets
15
+ with the Node.js 22+ CLI or build integrations; browser adapters consume prepared assets.
17
16
 
18
17
  ## Define a map
19
18
 
@@ -73,33 +72,27 @@ Module object order does not determine rendering order.
73
72
 
74
73
  ## Team Icon Sets foundations
75
74
 
76
- `iconSet('@team/set')` is an explicit icon contributor alongside local and package-owned directories.
77
- It performs no I/O. A resolved map accepts at most 32 contributors, and the same set reference may
78
- appear only once. Shared sets use the same explicit array order and later-wins semantics as ordinary
79
- icon directories.
80
-
81
- An exact `tileflow.icons.lock.json` identifies immutable set revisions and generated artifacts. The
82
- lock parser rejects duplicate JSON keys, stale reference sets, mixed Teams, invalid IDs, floating
83
- versions, unsafe URLs, and manifest/hash mismatches. Serialization is canonical. Hashes are internal
84
- integrity machinery, not identifiers that application authors manage.
85
-
86
- Shared-set content identifies the effective published artifact. Git owns original artwork history;
87
- source-only SVG edits producing the same artifact are not shared content changes. No original-source
88
- hash, source format, or filesystem path is added to a shared package. Local/package originals retain
89
- their existing source identity. Shared winners use explicit `rendered-icon` identity, while an
90
- ordered versioned icon-composition receipt records consumed revisions separately, including
91
- fully shadowed sets and dependency changes that preserve rendered pixels.
92
-
93
- Map revision hashing preserves the existing v1 result for maps without shared sets. Maps with sets
94
- require a complete receipt and use the domain-separated v2 revision contract. Build-manifest map
95
- entries identify that contract with `mapRevisionSchemaVersion: 2`; omission means legacy v1. The
96
- Metadata-free RGBA icon packages retain `tileflow-icon-package-v1` identity. SDF appearance or text-fitting metadata uses
97
- `tileflow-icon-package-v2` and v2 composition receipts; defaults and layout participate in identity.
98
-
99
- These are portable contracts. `@tileflow/dev` composes declared contributors on its normal
100
- preparation path, and the `tileflow` CLI owns catalog management and exact lock maintenance.
101
- Importing `iconSet` adds a declaration; it resolves no revision and does not by itself make a
102
- Team catalog available to your deployment.
75
+ `iconSet('@team/set')` declares a contributor alongside local/package directories, without I/O.
76
+ Maps accept at most 32 contributors; set references must be unique. Explicit array order and
77
+ later-wins icon precedence apply to all contributors.
78
+
79
+ `tileflow.icons.lock.json` pins immutable set revisions and artifacts. Its parser rejects duplicate
80
+ keys, stale references, mixed Teams, invalid IDs, floating versions, unsafe URLs and manifest/hash
81
+ mismatches. Serialization is canonical; hashes are internal integrity details.
82
+
83
+ Shared identity follows published artwork, not source-only SVG edits yielding identical artifacts.
84
+ Git retains original artwork history. Shared packages contain no original-source hash, format or
85
+ filesystem path; local/package originals retain source identity. Shared winners use `rendered-icon`
86
+ identity. Ordered, versioned composition receipts record consumed revisions, including shadowed
87
+ sets and dependency changes preserving rendered pixels.
88
+
89
+ Maps without shared sets retain v1 revision hashing. Shared sets require complete receipts and the
90
+ domain-separated v2 contract, identified by `mapRevisionSchemaVersion: 2`; omission means v1.
91
+ Metadata-free RGBA packages retain `tileflow-icon-package-v1`. SDF appearance or text-fitting
92
+ metadata requires `tileflow-icon-package-v2` and v2 composition receipts, including defaults/layout.
93
+
94
+ `@tileflow/dev` prepares declared contributors; the CLI manages catalogs and exact locks.
95
+ Importing `iconSet` neither resolves revisions nor makes a Team catalog available to deployments.
103
96
 
104
97
  ## Style with themes and semantic modules
105
98
 
@@ -150,25 +143,34 @@ export default defineMap({
150
143
  `system` is a runtime selection policy, not a stored theme. Builds, captures, static scenes, and
151
144
  receipts must use a concrete theme such as `light` or `dark`.
152
145
 
153
- Theme and `timeOfDay` changes animate over 450 ms by default, respecting reduced motion.
154
- The same controller can make chosen modules recede and the map's labels fade so an application's
155
- own content reads first.
156
- It also sets the style-wide states that themes read with `expr.globalState`, easing numbers so the
157
- values a theme interpolates on them move smoothly.
158
- For application-drawn RGBA symbols, it also manages fixed-size
159
- dynamic style images,
160
- including state refresh, theme changes and restoration without changing layer placement.
161
- Applications draw their own routes in the theme's inks, read with `getRouteInks()`, and draw them
162
- on with `createTileflowLineProgress`. `createTileflowGroundLayers` keeps them under 3D buildings,
163
- which hide them where they stand in front, and can show the hidden stretches faintly.
164
- A theme can describe its sun and sky light (`lighting.sun`, `lighting.ambient`); the controller
165
- returns the sun the map shows with `getSun()`, mixed during a blend, for an application's own 3D
166
- layers, and `setSun()` places it by direction or by the real sun of a date and place.
167
- `createTileflowBuildings3D` enables worker-meshed buildings rising in at zoom 15–15.3, with scene
168
- sun, cast/contact shadows and 0.8 m rounded corners. Each effect is independently overridable.
169
- Street lights default to off, including in Streets. Set `roads.streetLights.enabled: true` and mount
170
- `createTileflowStreetLights` to enable them.
171
- `createTileflowVegetation` controls all trees using the map's `3d`, `flat` or `auto` policy.
146
+ Theme and `timeOfDay` changes animate over 450 ms, respecting reduced motion. Web manifests v3
147
+ add `familyUrl`, a bounded `tileflow-style-family` v1 document sharing structure and parameters;
148
+ flat `styleUrl` exports remain. `createTileflowStyleFamily` (`@tileflow/core/build`) factors styles;
149
+ `parseTileflowStyleFamily` and `materializeTileflowStyleFamily` (`@tileflow/core/runtime`) validate
150
+ and expand them. Controllers load each family once. Compatible appearances preserve sources,
151
+ application layers and 3D palettes; structural variants swap styles. Feature-dependent branches
152
+ prepare once; discrete values and RGBA icons switch at the dominant theme without relayout.
153
+ Parameter columns are not semantic tokens.
154
+
155
+ `controller.setColors({'surface.water': '#008800'})` overrides named tokens; `{}` restores authored
156
+ colours. Fixed colours and application layers remain. Web builds retain token bindings; direct
157
+ `createStyle` calls opt in with `runtimeColors: true`. `createTileflowAppearanceController().set()`
158
+ selects author-owned `fixed`, `system` or local `clock` behaviour without UI or location requests.
159
+ Profile performance on target devices.
160
+
161
+ Theme controllers also provide module/label emphasis, eased numeric `expr.globalState` values,
162
+ and fixed-size dynamic RGBA images with state refresh and restoration across theme changes.
163
+ `getRouteInks()` supplies route colours; `createTileflowLineProgress` animates drawing routes.
164
+ `createTileflowGroundLayers` places them under 3D buildings, optionally showing occluded stretches
165
+ faintly. Themes declare `lighting.sun` and `lighting.ambient`; `getSun()` returns the displayed,
166
+ blended sun for application 3D layers. `setSun()` accepts a direction or a date and location.
167
+
168
+ `createTileflowBuildings3D` enables worker-meshed buildings rising at zoom 15–15.3, scene sun,
169
+ cast/contact shadows and 0.8 m rounded corners; effects are independently overridable. Its
170
+ `tileflow-buildings-scene-3d` layer replaces `tileflow-buildings-native-extrusion` only after visible
171
+ building tiles draw. Failure keeps the native fallback; 2D restores authored visibility.
172
+ Street lights default off, including in Streets: enable `roads.streetLights.enabled` and mount
173
+ `createTileflowStreetLights`. `createTileflowVegetation` follows the map's `3d`, `flat` or `auto` policy.
172
174
 
173
175
  POI icons and names place together; `placement.coupleIconAndLabel: false` separates them.
174
176
 
@@ -188,6 +190,11 @@ validates the authoring input and throws on failure. `createStyle(map, options)`
188
190
  throws; `createStyleResult(map, options)` returns structured diagnostics and a compilation report.
189
191
  Only a successful result contains `style`.
190
192
 
193
+ Compilation compacts redundant expressions and shares repeated predicates and values with
194
+ MapLibre `let` bindings. Themes still produce standalone Style JSON, with the same layer order,
195
+ appearance and assets. Inspect semantic targets rather than depending on the emitted expression
196
+ shape; it may change when the compiler removes repetition.
197
+
191
198
  Maps with package/local icon or font directories need the CLI, a build plugin, or
192
199
  [`@tileflow/dev/artifacts`](https://github.com/tileflow/tileflow-sdk/blob/main/packages/dev/README.md)
193
200
  to prepare assets. Browser components consume the resulting manifest.
@@ -256,6 +263,39 @@ template, zoom limits, thresholds, and the Tileflow contour protocol. Framework
256
263
  tooling prepare browser resources; direct MapLibre integrations must register required protocols
257
264
  before loading a style.
258
265
 
266
+ ### Load a portable style in MapLibre
267
+
268
+ Await `loadTileflowRuntimeStyle` before giving MapLibre a runtime style. React, Vue and Svelte do
269
+ this automatically. The loader prepares flat styles or shared families, resolving sprites, glyphs,
270
+ fonts, sources and model/landmark URLs against their declaring documents. HTTP TileJSON loads once
271
+ per preparation; explicit source options win. Artifacts and input objects remain unchanged.
272
+
273
+ <!-- docs:check -->
274
+
275
+ ```ts
276
+ import {loadTileflowRuntimeStyle, loadTileflowStyleFonts} from '@tileflow/core/browser';
277
+ import type {TileflowRuntimeStyle} from '@tileflow/core/runtime';
278
+
279
+ export async function prepareMapStyle(runtime: TileflowRuntimeStyle, signal?: AbortSignal) {
280
+ const prepared = await loadTileflowRuntimeStyle(runtime, {signal});
281
+ await loadTileflowStyleFonts(prepared.style, {fontFaces: prepared.fontFaces});
282
+ return prepared.style; // Use as new maplibregl.Map({container, style}).
283
+ }
284
+ ```
285
+
286
+ Resolve the runtime with `resolveTileflowRuntimeStyle`. For inline styles, `baseUrl` supplies the
287
+ document URL (default: `document.baseURI`). Absolute URLs, signatures, template tokens and
288
+ application data retain their meaning. Custom source protocols remain with MapLibre's handlers.
289
+
290
+ `fetch`, `signal` and `transformRequest(url, 'Style' | 'Source')` control document requests, including
291
+ families. Defaults use same-origin credentials and reject redirects. Invalid documents, failed
292
+ requests and size limits (style/family: 16 MiB; TileJSON: 1 MiB) reject preparation.
293
+
294
+ For theme changes, pass `initial: prepared` and `styleLoadOptions` to `createTileflowThemeController`.
295
+ With flat styles, `initialStyle: prepared.style` can instead preserve the original `initial` and
296
+ `getCurrent()` identity. Inline themes and `loadStyle` overrides must already be prepared. Disposal
297
+ aborts pending loads; blends and rollback reuse prepared resources.
298
+
259
299
  With `projection: 'globe'`, `atmosphere: true` adds a halo and stars; an object configures colors, star count and size.
260
300
  `sky` follows the sun at street level. Frameworks and capture attach both; direct
261
301
  MapLibre consumers call `attachTileflowAtmosphere(map)` from `@tileflow/core/browser`.
@@ -264,18 +304,20 @@ Applications that need the map's data themselves, such as streets to route over
264
304
  under the camera, read chosen layers of a vector source for an area at a fixed zoom with
265
305
  `createTileflowTileReader` from `@tileflow/core/browser`, which also runs in a module worker.
266
306
 
267
- Browser 3D scenes support `camera.adaptivePerspective`: caller override,
268
- map default, then `false`. Streets enables it. Depth markers let buildings
269
- occlude application markers.
270
- Custom 3D layers load visible ground from the bottom of the viewport towards the horizon before
271
- spending tiles offscreen. Buildings fade down at the far boundary, across the view's width, and
272
- distance haze follows that boundary. Coverage follows the viewport and its projection on resize,
273
- within each layer's `maxTiles` budget (25 by default); views exceeding that budget still have
274
- bounded coverage, with the nearest ground taking priority.
275
- Model roles use `modelLighting` for independent colours and materials. `colorScale` (0–1,
276
- default 1) subtly darkens a role after recolouring. Map-shaded models share the buildings’
277
- vertical/contact gradient; physical roles keep their own lighting. Model corner geometry is
278
- authored in the asset, while ordinary tile corners use `edgeRadius`.
307
+ Browser 3D scenes resolve `camera.adaptivePerspective` from caller override, map default, then
308
+ `false`; Streets enables it. Buildings occlude depth markers. `camera.pitchLimit: {maxZoom, maxPitch}`
309
+ caps inclination through `maxZoom`, respecting stricter application caps. Closer views and disposal
310
+ restore the application's maximum.
311
+ 3D layers prioritize visible ground from viewport bottom toward the horizon. Buildings fade across
312
+ the far boundary, followed by haze. Coverage follows resize and projection within each layer's
313
+ `maxTiles` budget (default 25), prioritizing nearest ground.
314
+ Model roles use `modelLighting` for colours/materials and `colorScale` (0–1, default 1) for darkening
315
+ recoloured assets. Ordinary facades use soft daylight and a gradient through their lower 85%, leaving
316
+ roofs and upper edges light. Map-shaded models retain a short base gradient; physical roles retain
317
+ their lighting. Model corners belong to the asset; ordinary buildings use `edgeRadius`.
318
+ `buildings.threeDimensional.entrance: false` shows buildings/models at full height and opacity at
319
+ entrance zooms, without zoom/arrival growth or fading. Equal endpoints such as
320
+ `entrance: {buildings: [14.25, 14.25], models: [14.25, 14.25]}` switch immediately at that zoom.
279
321
 
280
322
  Text requires exactly one provider. Soundings and Blueprint use URL glyphs; Streets packages DINish
281
323
  and Noto Sans; Baedeker, 1777 and Siegfried package Cormorant; Cívica packages its lettering. Hosted
@@ -565,6 +565,10 @@ type TileflowBuildings3DOptions = Readonly<{
565
565
  beforeId?: string;
566
566
  /** The map's request rules, for the tiles the renderer reads. */
567
567
  transformRequest?: TileflowTileRequestTransform;
568
+ /** Called when the custom layer gains or loses a drawable frame. */
569
+ onReadyChange?: (ready: boolean) => void;
570
+ /** Rendering failures leave the compiled extrusion available as a fallback. */
571
+ onError?: (error: unknown) => void;
568
572
  }>;
569
573
  type TileflowBuildings3DChange = Readonly<{
570
574
  transition?: Readonly<{
@@ -583,6 +587,8 @@ type TileflowBuildings3D = {
583
587
  grow(scale: number, options?: TileflowBuildings3DChange): Promise<void>;
584
588
  /** The height scale shown now. */
585
589
  readonly scale: number;
590
+ /** True after a frame has drawn with its visible building tiles prepared. */
591
+ readonly ready: boolean;
586
592
  /**
587
593
  * Whether the map's style describes its 3D buildings (the buildings module's
588
594
  * `threeDimensional`), tiles raised, buildings and vertices, and the placed models standing, for
@@ -598,7 +604,7 @@ type TileflowBuildings3D = {
598
604
  /** Takes the layer off the map and lets go of its buffers. */
599
605
  dispose(): void;
600
606
  };
601
- declare const tileflowBuildings3DLayerId = "tileflow-buildings-3d";
607
+ declare const tileflowBuildings3DLayerId = "tileflow-buildings-scene-3d";
602
608
  /**
603
609
  * Creates the renderer, showing buildings automatically above zoom 15 unless hidden. It reads the source's
604
610
  * z15 tiles round the camera, the zoom at which World's buildings carry their heights.
@@ -609,12 +615,19 @@ declare function createTileflowBuildings3D(options: TileflowBuildings3DOptions):
609
615
  type TileflowCameraOptions = Readonly<{
610
616
  /** Subtle top-down perspective at street zooms. Omission uses the map's default, else false. */
611
617
  adaptivePerspective?: boolean | undefined;
618
+ /** Cap pitch at and below this zoom; closer views keep the application's maximum. */
619
+ pitchLimit?: Readonly<{
620
+ maxZoom: number;
621
+ maxPitch: number;
622
+ }>;
612
623
  }>;
613
624
 
614
625
  /** Public camera capabilities; renderers without a field-of-view setter keep their own lens. */
615
626
  type TileflowAdaptiveCameraMap = {
616
627
  getPitch(): number;
617
628
  getZoom(): number;
629
+ getMaxPitch?(): number;
630
+ setMaxPitch?(degrees: number): unknown;
618
631
  getCanvas?(): {
619
632
  clientHeight: number;
620
633
  };
@@ -1092,6 +1105,8 @@ type TileflowMap3DOptions = Readonly<{
1092
1105
  camera?: TileflowCameraOptions;
1093
1106
  /** The map's request rules, for the tiles the renderers read. */
1094
1107
  transformRequest?: TileflowTileRequestTransform;
1108
+ /** Reports a building-renderer failure while the native extrusion stays visible. */
1109
+ onError?: (error: unknown) => void;
1095
1110
  }>;
1096
1111
  type TileflowMap3D = {
1097
1112
  /** Shows the scene. A transition animates the buildings' rise; other parts change at once. */
package/dist/3d.d.ts CHANGED
@@ -1 +1 @@
1
- export { C as TileflowCameraOptions, u as TileflowMap3D, D as TileflowMap3DMap, t as TileflowMap3DOptions, ab as createTileflowMap3D } from './3d-CW5Ls0An.js';
1
+ export { C as TileflowCameraOptions, u as TileflowMap3D, D as TileflowMap3DMap, t as TileflowMap3DOptions, ab as createTileflowMap3D } from './3d-EHN80Dhw.js';