@tileflow/core 0.1.0-alpha.31 → 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.
Files changed (40) hide show
  1. package/README.md +41 -2
  2. package/THIRD_PARTY_NOTICES.md +25 -2
  3. package/dist/browser.d.ts +1008 -16
  4. package/dist/browser.js +6661 -1392
  5. package/dist/build.d.ts +64 -56
  6. package/dist/build.js +702 -253
  7. package/dist/capture-shot-ChPQvPyi.d.ts +291 -0
  8. package/dist/capture.d.ts +1 -1
  9. package/dist/capture.js +230 -0
  10. package/dist/config-reference.json +1710 -1370
  11. package/dist/{icon-composition-BiOTwrvD.d.ts → icon-composition-CSnN2-Xt.d.ts} +169 -33
  12. package/dist/index.d.ts +57 -13
  13. package/dist/index.js +1684 -800
  14. package/dist/{manifest-types-CTT2eLbp.d.ts → manifest-types-E7m23eXL.d.ts} +18 -1
  15. package/dist/manifest.d.ts +2 -2
  16. package/dist/native-profile.d.ts +25 -11
  17. package/dist/native-profile.js +21 -1
  18. package/dist/native.js +1893 -1884
  19. package/dist/runtime.d.ts +1 -1
  20. package/docs/application-tile-reading.md +80 -0
  21. package/docs/authoring-model.md +16 -6
  22. package/docs/buildings-3d.md +168 -0
  23. package/docs/camera-moves-and-tile-cache.md +112 -0
  24. package/docs/capture-scenes.md +5 -1
  25. package/docs/capture-shots.md +173 -0
  26. package/docs/compiled-style-performance.md +4 -1
  27. package/docs/data-is-separate-from-design.md +103 -9
  28. package/docs/depth-markers.md +65 -0
  29. package/docs/dynamic-style-images.md +100 -0
  30. package/docs/native-artifact-profile.md +5 -3
  31. package/docs/public-api-and-browser-subpath.md +3 -3
  32. package/docs/route-drawing.md +191 -0
  33. package/docs/shared-visual-primitives.md +20 -0
  34. package/docs/street-lights.md +80 -0
  35. package/docs/style-states.md +73 -0
  36. package/docs/sun-and-light.md +125 -0
  37. package/docs/theme-transitions-and-blends.md +41 -2
  38. package/docs/themes-and-module-styles.md +7 -0
  39. package/package.json +4 -1
  40. package/dist/capture-scene-D6soWztE.d.ts +0 -161
@@ -0,0 +1,291 @@
1
+ import { z } from 'zod';
2
+
3
+ declare const tileflowCaptureSceneSchemaVersion: 1;
4
+ declare const tileflowCaptureSceneLimits: Readonly<{
5
+ applicationPathLength: 2048;
6
+ boundsPadding: {
7
+ maximum: number;
8
+ minimum: number;
9
+ };
10
+ captureIdLength: 64;
11
+ maximumPhysicalPixels: 16777216;
12
+ pitch: {
13
+ maximum: number;
14
+ minimum: number;
15
+ };
16
+ selectorLength: 256;
17
+ viewport: {
18
+ maximum: number;
19
+ minimum: number;
20
+ };
21
+ zoom: {
22
+ maximum: number;
23
+ minimum: number;
24
+ };
25
+ }>;
26
+ declare const tileflowCaptureCenterCameraSchema: z.ZodObject<{
27
+ type: z.ZodLiteral<"center">;
28
+ center: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
29
+ zoom: z.ZodNumber;
30
+ bearing: z.ZodOptional<z.ZodNumber>;
31
+ pitch: z.ZodOptional<z.ZodNumber>;
32
+ }, z.core.$strict>;
33
+ declare const tileflowCaptureBoundsCameraSchema: z.ZodObject<{
34
+ type: z.ZodLiteral<"bounds">;
35
+ bounds: z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>;
36
+ padding: z.ZodOptional<z.ZodNumber>;
37
+ bearing: z.ZodOptional<z.ZodNumber>;
38
+ pitch: z.ZodOptional<z.ZodNumber>;
39
+ }, z.core.$strict>;
40
+ declare const tileflowCaptureCameraSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
41
+ type: z.ZodLiteral<"center">;
42
+ center: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
43
+ zoom: z.ZodNumber;
44
+ bearing: z.ZodOptional<z.ZodNumber>;
45
+ pitch: z.ZodOptional<z.ZodNumber>;
46
+ }, z.core.$strict>, z.ZodObject<{
47
+ type: z.ZodLiteral<"bounds">;
48
+ bounds: z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>;
49
+ padding: z.ZodOptional<z.ZodNumber>;
50
+ bearing: z.ZodOptional<z.ZodNumber>;
51
+ pitch: z.ZodOptional<z.ZodNumber>;
52
+ }, z.core.$strict>], "type">;
53
+ declare const tileflowCaptureViewportSchema: z.ZodObject<{
54
+ width: z.ZodNumber;
55
+ height: z.ZodNumber;
56
+ dpr: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<2>]>>;
57
+ }, z.core.$strict>;
58
+ declare const tileflowCaptureIdSchema: z.ZodString;
59
+ declare const tileflowCaptureSceneNameSchema: z.ZodString;
60
+ declare const tileflowCaptureMapTargetSchema: z.ZodObject<{
61
+ kind: z.ZodLiteral<"map">;
62
+ }, z.core.$strict>;
63
+ declare const tileflowCaptureApplicationTargetSchema: z.ZodObject<{
64
+ kind: z.ZodLiteral<"application">;
65
+ path: z.ZodString;
66
+ captureId: z.ZodOptional<z.ZodString>;
67
+ selector: z.ZodOptional<z.ZodString>;
68
+ frame: z.ZodOptional<z.ZodEnum<{
69
+ map: "map";
70
+ viewport: "viewport";
71
+ }>>;
72
+ }, z.core.$strict>;
73
+ declare const tileflowCaptureTargetSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
74
+ kind: z.ZodLiteral<"map">;
75
+ }, z.core.$strict>, z.ZodObject<{
76
+ kind: z.ZodLiteral<"application">;
77
+ path: z.ZodString;
78
+ captureId: z.ZodOptional<z.ZodString>;
79
+ selector: z.ZodOptional<z.ZodString>;
80
+ frame: z.ZodOptional<z.ZodEnum<{
81
+ map: "map";
82
+ viewport: "viewport";
83
+ }>>;
84
+ }, z.core.$strict>], "kind">;
85
+ declare const tileflowCaptureSceneSchema: z.ZodObject<{
86
+ map: z.ZodString;
87
+ theme: z.ZodString;
88
+ camera: z.ZodDiscriminatedUnion<[z.ZodObject<{
89
+ type: z.ZodLiteral<"center">;
90
+ center: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
91
+ zoom: z.ZodNumber;
92
+ bearing: z.ZodOptional<z.ZodNumber>;
93
+ pitch: z.ZodOptional<z.ZodNumber>;
94
+ }, z.core.$strict>, z.ZodObject<{
95
+ type: z.ZodLiteral<"bounds">;
96
+ bounds: z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber, z.ZodNumber], null>;
97
+ padding: z.ZodOptional<z.ZodNumber>;
98
+ bearing: z.ZodOptional<z.ZodNumber>;
99
+ pitch: z.ZodOptional<z.ZodNumber>;
100
+ }, z.core.$strict>], "type">;
101
+ viewport: z.ZodObject<{
102
+ width: z.ZodNumber;
103
+ height: z.ZodNumber;
104
+ dpr: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<2>]>>;
105
+ }, z.core.$strict>;
106
+ target: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
107
+ kind: z.ZodLiteral<"map">;
108
+ }, z.core.$strict>, z.ZodObject<{
109
+ kind: z.ZodLiteral<"application">;
110
+ path: z.ZodString;
111
+ captureId: z.ZodOptional<z.ZodString>;
112
+ selector: z.ZodOptional<z.ZodString>;
113
+ frame: z.ZodOptional<z.ZodEnum<{
114
+ map: "map";
115
+ viewport: "viewport";
116
+ }>>;
117
+ }, z.core.$strict>], "kind">>;
118
+ }, z.core.$strict>;
119
+ /**
120
+ * Why a scene's bounds padding leaves no room for its bounds, or undefined when it fits: padding on
121
+ * both sides must be less than the viewport's shorter side. MapLibre GL JS 6.11.2+ leaves a globe
122
+ * camera where it was when it cannot fit, so the capture would show the wrong view. Checked where
123
+ * scenes are validated rather than in the schema, so the published reference keeps its shape.
124
+ */
125
+ declare function tileflowCaptureSceneFitIssue(scene: Pick<TileflowCaptureScene, 'camera' | 'viewport'>): {
126
+ message: string;
127
+ path: ['camera', 'padding'];
128
+ } | undefined;
129
+ type TileflowCaptureCenterCamera = z.infer<typeof tileflowCaptureCenterCameraSchema>;
130
+ type TileflowCaptureBoundsCamera = z.infer<typeof tileflowCaptureBoundsCameraSchema>;
131
+ type TileflowCaptureCamera = z.infer<typeof tileflowCaptureCameraSchema>;
132
+ type TileflowCaptureViewport = z.infer<typeof tileflowCaptureViewportSchema>;
133
+ type TileflowCaptureMapTarget = z.infer<typeof tileflowCaptureMapTargetSchema>;
134
+ type TileflowCaptureApplicationTarget = z.infer<typeof tileflowCaptureApplicationTargetSchema>;
135
+ type TileflowCaptureTarget = z.infer<typeof tileflowCaptureTargetSchema>;
136
+ type TileflowCaptureScene = z.infer<typeof tileflowCaptureSceneSchema>;
137
+ type NormalizedTileflowCaptureScene = {
138
+ map: string;
139
+ theme: string;
140
+ camera: {
141
+ type: 'center';
142
+ center: [number, number];
143
+ zoom: number;
144
+ bearing: number;
145
+ pitch: number;
146
+ } | {
147
+ type: 'bounds';
148
+ bounds: [number, number, number, number];
149
+ padding: number;
150
+ bearing: number;
151
+ pitch: number;
152
+ };
153
+ viewport: {
154
+ width: number;
155
+ height: number;
156
+ dpr: 1 | 2;
157
+ };
158
+ target: {
159
+ kind: 'map';
160
+ } | {
161
+ kind: 'application';
162
+ path: string;
163
+ captureId?: string;
164
+ selector?: string;
165
+ frame: 'map' | 'viewport';
166
+ };
167
+ };
168
+ declare function normalizeTileflowCaptureScene(input: TileflowCaptureScene): NormalizedTileflowCaptureScene;
169
+ declare function normalizeTileflowCaptureId(value: string | undefined): string | undefined;
170
+
171
+ /** A camera between keyframes: always the center form, with bearing and pitch resolved. */
172
+ type TileflowShotCamera = {
173
+ type: 'center';
174
+ center: [number, number];
175
+ zoom: number;
176
+ bearing: number;
177
+ pitch: number;
178
+ };
179
+
180
+ declare const tileflowCaptureShotSchemaVersion: 1;
181
+ declare const tileflowCaptureShotLimits: Readonly<{
182
+ blendThemes: Readonly<{
183
+ maximum: 8;
184
+ minimum: 2;
185
+ }>;
186
+ defaultFps: 30;
187
+ durationMs: Readonly<{
188
+ maximum: 60000;
189
+ }>;
190
+ fps: readonly [24, 25, 30, 50, 60];
191
+ keyframes: Readonly<{
192
+ maximum: 64;
193
+ minimum: 2;
194
+ }>;
195
+ maximumFrames: 3600;
196
+ }>;
197
+ /** Shot names follow the same portable artifact-name rules as scene names. */
198
+ declare const tileflowCaptureShotNameSchema: z.ZodString;
199
+ declare const tileflowCaptureShotBlendSchema: z.ZodObject<{
200
+ themes: z.ZodArray<z.ZodString>;
201
+ position: z.ZodNumber;
202
+ }, z.core.$strict>;
203
+ declare const tileflowCaptureShotKeyframeSchema: z.ZodObject<{
204
+ at: z.ZodNumber;
205
+ camera: z.ZodObject<{
206
+ type: z.ZodLiteral<"center">;
207
+ center: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
208
+ zoom: z.ZodNumber;
209
+ bearing: z.ZodOptional<z.ZodNumber>;
210
+ pitch: z.ZodOptional<z.ZodNumber>;
211
+ }, z.core.$strict>;
212
+ blend: z.ZodOptional<z.ZodObject<{
213
+ themes: z.ZodArray<z.ZodString>;
214
+ position: z.ZodNumber;
215
+ }, z.core.$strict>>;
216
+ }, z.core.$strict>;
217
+ declare const tileflowCaptureShotSchema: z.ZodObject<{
218
+ theme: z.ZodString;
219
+ viewport: z.ZodObject<{
220
+ width: z.ZodNumber;
221
+ height: z.ZodNumber;
222
+ dpr: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<2>]>>;
223
+ }, z.core.$strict>;
224
+ fps: z.ZodOptional<z.ZodLiteral<24 | 25 | 30 | 50 | 60>>;
225
+ keyframes: z.ZodArray<z.ZodObject<{
226
+ at: z.ZodNumber;
227
+ camera: z.ZodObject<{
228
+ type: z.ZodLiteral<"center">;
229
+ center: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
230
+ zoom: z.ZodNumber;
231
+ bearing: z.ZodOptional<z.ZodNumber>;
232
+ pitch: z.ZodOptional<z.ZodNumber>;
233
+ }, z.core.$strict>;
234
+ blend: z.ZodOptional<z.ZodObject<{
235
+ themes: z.ZodArray<z.ZodString>;
236
+ position: z.ZodNumber;
237
+ }, z.core.$strict>>;
238
+ }, z.core.$strict>>;
239
+ easing: z.ZodOptional<z.ZodEnum<{
240
+ linear: "linear";
241
+ smooth: "smooth";
242
+ }>>;
243
+ map: z.ZodString;
244
+ }, z.core.$strict>;
245
+ type TileflowCaptureShotBlend = z.infer<typeof tileflowCaptureShotBlendSchema>;
246
+ type TileflowCaptureShotKeyframe = z.infer<typeof tileflowCaptureShotKeyframeSchema>;
247
+ type TileflowCaptureShot = z.infer<typeof tileflowCaptureShotSchema>;
248
+ type TileflowCaptureShotEasing = 'linear' | 'smooth';
249
+ type NormalizedTileflowCaptureShotCamera = TileflowShotCamera;
250
+ type NormalizedTileflowCaptureShot = {
251
+ map: string;
252
+ theme: string;
253
+ viewport: {
254
+ width: number;
255
+ height: number;
256
+ dpr: 1 | 2;
257
+ };
258
+ fps: 24 | 25 | 30 | 50 | 60;
259
+ easing: TileflowCaptureShotEasing;
260
+ keyframes: Array<{
261
+ at: number;
262
+ camera: NormalizedTileflowCaptureShotCamera;
263
+ blend?: {
264
+ themes: string[];
265
+ position: number;
266
+ };
267
+ }>;
268
+ };
269
+ /** One rendered frame of a shot: the camera and blend position at `at` milliseconds. */
270
+ type TileflowCaptureShotFrame = {
271
+ index: number;
272
+ at: number;
273
+ camera: NormalizedTileflowCaptureShotCamera;
274
+ /** Present when the shot blends themes. */
275
+ blendPosition?: number;
276
+ };
277
+ declare function normalizeTileflowCaptureShot(input: TileflowCaptureShot): NormalizedTileflowCaptureShot;
278
+ /**
279
+ * The number of frames a shot renders: one at the start and one every `1 / fps` seconds up to its
280
+ * last keyframe. The last keyframe is a frame when its time is a whole number of frame intervals.
281
+ */
282
+ declare function tileflowCaptureShotFrameCount(shot: Pick<TileflowCaptureShot, 'fps' | 'keyframes'>): number;
283
+ /**
284
+ * Interpolates every frame of a shot. Frame `i` shows the shot at `i * 1000 / fps` milliseconds.
285
+ * Within each keyframe segment the center moves in Web Mercator coordinates along the shorter way
286
+ * around the world, zoom and pitch change linearly, bearing turns along the shorter arc, and the
287
+ * blend position changes linearly; `easing: 'smooth'` eases each segment in and out.
288
+ */
289
+ declare function tileflowCaptureShotFrames(shot: TileflowCaptureShot | Omit<TileflowCaptureShot, 'map'>): TileflowCaptureShotFrame[];
290
+
291
+ export { tileflowCaptureSceneSchemaVersion as A, tileflowCaptureShotBlendSchema as B, tileflowCaptureShotFrameCount as C, tileflowCaptureShotFrames as D, tileflowCaptureShotKeyframeSchema as E, tileflowCaptureShotLimits as F, tileflowCaptureShotNameSchema as G, tileflowCaptureShotSchema as H, tileflowCaptureShotSchemaVersion as I, tileflowCaptureTargetSchema as J, tileflowCaptureViewportSchema as K, tileflowCaptureSceneFitIssue as L, type NormalizedTileflowCaptureScene as N, type TileflowCaptureScene as T, type TileflowCaptureShot as a, type NormalizedTileflowCaptureShot as b, type NormalizedTileflowCaptureShotCamera as c, type TileflowCaptureApplicationTarget as d, type TileflowCaptureBoundsCamera as e, type TileflowCaptureCamera as f, type TileflowCaptureCenterCamera as g, type TileflowCaptureMapTarget as h, type TileflowCaptureShotBlend as i, type TileflowCaptureShotEasing as j, type TileflowCaptureShotFrame as k, type TileflowCaptureShotKeyframe as l, type TileflowCaptureTarget as m, type TileflowCaptureViewport as n, normalizeTileflowCaptureId as o, normalizeTileflowCaptureScene as p, normalizeTileflowCaptureShot as q, tileflowCaptureBoundsCameraSchema as r, tileflowCaptureCameraSchema as s, tileflowCaptureApplicationTargetSchema as t, tileflowCaptureCenterCameraSchema as u, tileflowCaptureIdSchema as v, tileflowCaptureMapTargetSchema as w, tileflowCaptureSceneLimits as x, tileflowCaptureSceneNameSchema as y, tileflowCaptureSceneSchema as z };
package/dist/capture.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { N as NormalizedTileflowCaptureScene, a as TileflowCaptureApplicationTarget, b as TileflowCaptureBoundsCamera, c as TileflowCaptureCamera, d as TileflowCaptureCenterCamera, e as TileflowCaptureMapTarget, T as TileflowCaptureScene, f as TileflowCaptureTarget, g as TileflowCaptureViewport, n as normalizeTileflowCaptureId, h as normalizeTileflowCaptureScene, t as tileflowCaptureApplicationTargetSchema, i as tileflowCaptureBoundsCameraSchema, j as tileflowCaptureCameraSchema, k as tileflowCaptureCenterCameraSchema, l as tileflowCaptureIdSchema, m as tileflowCaptureMapTargetSchema, o as tileflowCaptureSceneLimits, p as tileflowCaptureSceneNameSchema, q as tileflowCaptureSceneSchema, r as tileflowCaptureSceneSchemaVersion, s as tileflowCaptureTargetSchema, u as tileflowCaptureViewportSchema } from './capture-scene-D6soWztE.js';
1
+ export { N as NormalizedTileflowCaptureScene, b as NormalizedTileflowCaptureShot, c as NormalizedTileflowCaptureShotCamera, d as TileflowCaptureApplicationTarget, e as TileflowCaptureBoundsCamera, f as TileflowCaptureCamera, g as TileflowCaptureCenterCamera, h as TileflowCaptureMapTarget, T as TileflowCaptureScene, a as TileflowCaptureShot, i as TileflowCaptureShotBlend, j as TileflowCaptureShotEasing, k as TileflowCaptureShotFrame, l as TileflowCaptureShotKeyframe, m as TileflowCaptureTarget, n as TileflowCaptureViewport, o as normalizeTileflowCaptureId, p as normalizeTileflowCaptureScene, q as normalizeTileflowCaptureShot, t as tileflowCaptureApplicationTargetSchema, r as tileflowCaptureBoundsCameraSchema, s as tileflowCaptureCameraSchema, u as tileflowCaptureCenterCameraSchema, v as tileflowCaptureIdSchema, w as tileflowCaptureMapTargetSchema, L as tileflowCaptureSceneFitIssue, x as tileflowCaptureSceneLimits, y as tileflowCaptureSceneNameSchema, z as tileflowCaptureSceneSchema, A as tileflowCaptureSceneSchemaVersion, B as tileflowCaptureShotBlendSchema, C as tileflowCaptureShotFrameCount, D as tileflowCaptureShotFrames, E as tileflowCaptureShotKeyframeSchema, F as tileflowCaptureShotLimits, G as tileflowCaptureShotNameSchema, H as tileflowCaptureShotSchema, I as tileflowCaptureShotSchemaVersion, J as tileflowCaptureTargetSchema, K as tileflowCaptureViewportSchema } from './capture-shot-ChPQvPyi.js';
2
2
  import { z } from 'zod';
3
3
 
4
4
  /** Canonical, filesystem-safe identity shared by authored and emitted Tileflow resources. */
package/dist/capture.js CHANGED
@@ -204,8 +204,19 @@ var tileflowCaptureSceneSchema = z3.object({
204
204
  viewport: tileflowCaptureViewportSchema,
205
205
  target: tileflowCaptureTargetSchema.optional()
206
206
  }).strict();
207
+ function tileflowCaptureSceneFitIssue(scene) {
208
+ if (scene.camera.type !== "bounds" || scene.camera.padding === void 0) return void 0;
209
+ const room = Math.min(scene.viewport.width, scene.viewport.height);
210
+ if (scene.camera.padding * 2 < room) return void 0;
211
+ return {
212
+ message: `Expected bounds padding less than half the viewport's shorter side (${room / 2} pixels)`,
213
+ path: ["camera", "padding"]
214
+ };
215
+ }
207
216
  function normalizeTileflowCaptureScene(input) {
208
217
  const scene = tileflowCaptureSceneSchema.parse(input);
218
+ const fit = tileflowCaptureSceneFitIssue(scene);
219
+ if (fit) throw new RangeError(`${fit.path.join(".")}: ${fit.message}`);
209
220
  const camera = scene.camera.type === "center" ? {
210
221
  type: scene.camera.type,
211
222
  center: scene.camera.center,
@@ -256,19 +267,238 @@ function hasControlCharacter(value) {
256
267
  }
257
268
  return false;
258
269
  }
270
+
271
+ // src/capture-shot.ts
272
+ import { z as z4 } from "zod";
273
+
274
+ // src/capture-shot-motion.ts
275
+ function tileflowShotStateAt(shot, at) {
276
+ const { keyframes } = shot;
277
+ const first = keyframes[0];
278
+ const last = keyframes.at(-1);
279
+ if (!first || !last || keyframes.length < 2)
280
+ throw new TypeError("A shot needs at least two keyframes.");
281
+ const time = Math.min(last.at, Math.max(first.at, Number.isFinite(at) ? at : first.at));
282
+ let segment = 0;
283
+ while (segment < keyframes.length - 2 && time > keyframes[segment + 1].at) segment += 1;
284
+ const from = keyframes[segment];
285
+ const to = keyframes[segment + 1];
286
+ const linear = Math.min(1, Math.max(0, (time - from.at) / (to.at - from.at)));
287
+ const t = shot.easing === "linear" ? linear : smoothstep(linear);
288
+ return {
289
+ at: time,
290
+ camera: interpolateCamera(cameraOf(from), cameraOf(to), t),
291
+ ...from.blend && to.blend ? { blendPosition: interpolateNumber(from.blend.position, to.blend.position, t) } : {}
292
+ };
293
+ }
294
+ function cameraOf({ camera }) {
295
+ return {
296
+ type: "center",
297
+ center: [camera.center[0], camera.center[1]],
298
+ zoom: camera.zoom,
299
+ bearing: camera.bearing ?? 0,
300
+ pitch: camera.pitch ?? 0
301
+ };
302
+ }
303
+ var maximumMercatorLatitude = 85.051129;
304
+ function interpolateCamera(from, to, t) {
305
+ return {
306
+ type: "center",
307
+ center: interpolateCenter(from.center, to.center, t),
308
+ zoom: interpolateNumber(from.zoom, to.zoom, t),
309
+ bearing: interpolateBearing(from.bearing, to.bearing, t),
310
+ pitch: interpolateNumber(from.pitch, to.pitch, t)
311
+ };
312
+ }
313
+ function interpolateNumber(from, to, t) {
314
+ if (t <= 0 || from === to) return from;
315
+ if (t >= 1) return to;
316
+ return from + (to - from) * t;
317
+ }
318
+ function interpolateCenter(from, to, t) {
319
+ if (t <= 0 || from[0] === to[0] && from[1] === to[1]) return [from[0], from[1]];
320
+ if (t >= 1) return [to[0], to[1]];
321
+ const start = mercatorFromLngLat(from);
322
+ const end = mercatorFromLngLat(to);
323
+ let dx = end[0] - start[0];
324
+ if (dx > 0.5) dx -= 1;
325
+ else if (dx < -0.5) dx += 1;
326
+ return lngLatFromMercator([start[0] + dx * t, start[1] + (end[1] - start[1]) * t]);
327
+ }
328
+ function interpolateBearing(from, to, t) {
329
+ if (t <= 0 || from === to) return from;
330
+ if (t >= 1) return to;
331
+ const delta = ((to - from) % 360 + 540) % 360 - 180;
332
+ return wrapDegrees(from + delta * t);
333
+ }
334
+ function mercatorFromLngLat([longitude, latitude]) {
335
+ const clamped = Math.max(-maximumMercatorLatitude, Math.min(maximumMercatorLatitude, latitude));
336
+ return [
337
+ (180 + longitude) / 360,
338
+ (180 - 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + clamped * Math.PI / 360))) / 360
339
+ ];
340
+ }
341
+ function lngLatFromMercator([x, y]) {
342
+ const latitude = 360 / Math.PI * Math.atan(Math.exp((180 - y * 360) * Math.PI / 180)) - 90;
343
+ return [wrapDegrees(x * 360 - 180), latitude];
344
+ }
345
+ function wrapDegrees(value) {
346
+ if (value >= -180 && value <= 180) return value;
347
+ return ((value + 180) % 360 + 360) % 360 - 180;
348
+ }
349
+ function smoothstep(t) {
350
+ return t * t * (3 - 2 * t);
351
+ }
352
+
353
+ // src/capture-shot.ts
354
+ var tileflowCaptureShotSchemaVersion = 1;
355
+ var tileflowCaptureShotLimits = Object.freeze({
356
+ blendThemes: Object.freeze({ maximum: 8, minimum: 2 }),
357
+ defaultFps: 30,
358
+ durationMs: Object.freeze({ maximum: 6e4 }),
359
+ fps: Object.freeze([24, 25, 30, 50, 60]),
360
+ keyframes: Object.freeze({ maximum: 64, minimum: 2 }),
361
+ maximumFrames: 3600
362
+ });
363
+ var tileflowCaptureShotNameSchema = tileflowCaptureSceneNameSchema;
364
+ var tileflowCaptureShotBlendSchema = z4.object({
365
+ themes: z4.array(tileflowThemeNameSchema).min(tileflowCaptureShotLimits.blendThemes.minimum).max(tileflowCaptureShotLimits.blendThemes.maximum),
366
+ position: z4.number().finite().min(0)
367
+ }).strict().superRefine((blend, context) => {
368
+ if (new Set(blend.themes).size !== blend.themes.length) {
369
+ context.addIssue({ code: "custom", message: "Expected distinct themes", path: ["themes"] });
370
+ }
371
+ if (blend.position > blend.themes.length - 1) {
372
+ context.addIssue({
373
+ code: "custom",
374
+ message: `Expected a position from 0 to ${blend.themes.length - 1}`,
375
+ path: ["position"]
376
+ });
377
+ }
378
+ });
379
+ var tileflowCaptureShotKeyframeSchema = z4.object({
380
+ at: z4.number().int().min(0).max(tileflowCaptureShotLimits.durationMs.maximum),
381
+ camera: tileflowCaptureCenterCameraSchema,
382
+ blend: tileflowCaptureShotBlendSchema.optional()
383
+ }).strict();
384
+ var tileflowCaptureShotFields = {
385
+ theme: tileflowThemeNameSchema,
386
+ viewport: tileflowCaptureViewportSchema,
387
+ fps: z4.literal(tileflowCaptureShotLimits.fps).optional(),
388
+ keyframes: z4.array(tileflowCaptureShotKeyframeSchema).min(tileflowCaptureShotLimits.keyframes.minimum).max(tileflowCaptureShotLimits.keyframes.maximum),
389
+ easing: z4.enum(["smooth", "linear"]).optional()
390
+ };
391
+ var tileflowCaptureShotSchema = z4.object({ map: tileflowPortableIdSchema, ...tileflowCaptureShotFields }).strict().superRefine(checkShotTiming);
392
+ var tileflowMapShotSchema = z4.object(tileflowCaptureShotFields).strict().superRefine(checkShotTiming);
393
+ function normalizeTileflowCaptureShot(input) {
394
+ const shot = tileflowCaptureShotSchema.parse(input);
395
+ return { map: shot.map, ...normalizeShotFields(shot) };
396
+ }
397
+ function tileflowCaptureShotFrameCount(shot) {
398
+ const fps = shot.fps ?? tileflowCaptureShotLimits.defaultFps;
399
+ const duration = shot.keyframes.at(-1)?.at ?? 0;
400
+ return Math.floor(duration * fps / 1e3 + 1e-9) + 1;
401
+ }
402
+ function tileflowCaptureShotFrames(shot) {
403
+ const { map: _map, ...fields } = shot;
404
+ const normalized = normalizeShotFields(tileflowMapShotSchema.parse(fields));
405
+ const count = tileflowCaptureShotFrameCount(normalized);
406
+ const duration = normalized.keyframes.at(-1).at;
407
+ const frames = [];
408
+ for (let index = 0; index < count; index += 1) {
409
+ const at = Math.min(duration, index * 1e3 / normalized.fps);
410
+ frames.push({ index, ...tileflowShotStateAt(normalized, at) });
411
+ }
412
+ return frames;
413
+ }
414
+ function normalizeShotFields(shot) {
415
+ return {
416
+ theme: shot.theme,
417
+ viewport: { ...shot.viewport, dpr: shot.viewport.dpr ?? 1 },
418
+ fps: shot.fps ?? tileflowCaptureShotLimits.defaultFps,
419
+ easing: shot.easing ?? "smooth",
420
+ keyframes: shot.keyframes.map((keyframe) => ({
421
+ at: keyframe.at,
422
+ camera: {
423
+ type: "center",
424
+ center: keyframe.camera.center,
425
+ zoom: keyframe.camera.zoom,
426
+ bearing: keyframe.camera.bearing ?? 0,
427
+ pitch: keyframe.camera.pitch ?? 0
428
+ },
429
+ ...keyframe.blend ? { blend: { themes: [...keyframe.blend.themes], position: keyframe.blend.position } } : {}
430
+ }))
431
+ };
432
+ }
433
+ function checkShotTiming(shot, context) {
434
+ const { keyframes } = shot;
435
+ if (keyframes[0] && keyframes[0].at !== 0) {
436
+ context.addIssue({
437
+ code: "custom",
438
+ message: "Expected the first keyframe at 0 milliseconds",
439
+ path: ["keyframes", 0, "at"]
440
+ });
441
+ }
442
+ for (let index = 1; index < keyframes.length; index += 1) {
443
+ if (keyframes[index].at <= keyframes[index - 1].at) {
444
+ context.addIssue({
445
+ code: "custom",
446
+ message: "Expected a time after the previous keyframe",
447
+ path: ["keyframes", index, "at"]
448
+ });
449
+ }
450
+ }
451
+ const blended = keyframes.filter((keyframe) => keyframe.blend !== void 0);
452
+ if (blended.length > 0) {
453
+ const themes = JSON.stringify(blended[0].blend.themes);
454
+ keyframes.forEach((keyframe, index) => {
455
+ if (!keyframe.blend) {
456
+ context.addIssue({
457
+ code: "custom",
458
+ message: "Expected a blend on every keyframe when one keyframe blends themes",
459
+ path: ["keyframes", index, "blend"]
460
+ });
461
+ } else if (JSON.stringify(keyframe.blend.themes) !== themes) {
462
+ context.addIssue({
463
+ code: "custom",
464
+ message: "Expected the same themes, in the same order, on every keyframe",
465
+ path: ["keyframes", index, "blend", "themes"]
466
+ });
467
+ }
468
+ });
469
+ }
470
+ const frames = tileflowCaptureShotFrameCount(shot);
471
+ if (frames > tileflowCaptureShotLimits.maximumFrames) {
472
+ context.addIssue({
473
+ code: "custom",
474
+ message: `Expected at most ${tileflowCaptureShotLimits.maximumFrames} frames; this shot renders ${frames}`,
475
+ path: ["keyframes", keyframes.length - 1, "at"]
476
+ });
477
+ }
478
+ }
259
479
  export {
260
480
  normalizeTileflowCaptureId,
261
481
  normalizeTileflowCaptureScene,
482
+ normalizeTileflowCaptureShot,
262
483
  tileflowCaptureApplicationTargetSchema,
263
484
  tileflowCaptureBoundsCameraSchema,
264
485
  tileflowCaptureCameraSchema,
265
486
  tileflowCaptureCenterCameraSchema,
266
487
  tileflowCaptureIdSchema,
267
488
  tileflowCaptureMapTargetSchema,
489
+ tileflowCaptureSceneFitIssue,
268
490
  tileflowCaptureSceneLimits,
269
491
  tileflowCaptureSceneNameSchema,
270
492
  tileflowCaptureSceneSchema,
271
493
  tileflowCaptureSceneSchemaVersion,
494
+ tileflowCaptureShotBlendSchema,
495
+ tileflowCaptureShotFrameCount,
496
+ tileflowCaptureShotFrames,
497
+ tileflowCaptureShotKeyframeSchema,
498
+ tileflowCaptureShotLimits,
499
+ tileflowCaptureShotNameSchema,
500
+ tileflowCaptureShotSchema,
501
+ tileflowCaptureShotSchemaVersion,
272
502
  tileflowCaptureTargetSchema,
273
503
  tileflowCaptureViewportSchema,
274
504
  tileflowPortableIdSchema,