@tileflow/core 0.1.0-alpha.4 → 0.1.0-alpha.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +318 -26
  3. package/THIRD_PARTY_NOTICES.md +444 -0
  4. package/dist/3d-CzLTD0RK.d.ts +1092 -0
  5. package/dist/3d.d.ts +1 -0
  6. package/dist/3d.js +12660 -0
  7. package/dist/browser.d.ts +2278 -0
  8. package/dist/browser.js +21826 -0
  9. package/dist/build.d.ts +595 -0
  10. package/dist/build.js +29737 -0
  11. package/dist/capture-shot-ChPQvPyi.d.ts +291 -0
  12. package/dist/capture.d.ts +9 -0
  13. package/dist/capture.js +510 -0
  14. package/dist/config-reference.json +40527 -0
  15. package/dist/icon-composition-HUh_Lj8Z.d.ts +2516 -0
  16. package/dist/index.d.ts +1805 -162
  17. package/dist/index.js +26400 -3488
  18. package/dist/manifest-types-DnhSJjCM.d.ts +902 -0
  19. package/dist/manifest.d.ts +9 -0
  20. package/dist/manifest.js +449 -0
  21. package/dist/native-profile.d.ts +206 -0
  22. package/dist/native-profile.js +9339 -0
  23. package/dist/native.d.ts +365 -0
  24. package/dist/native.js +5970 -0
  25. package/dist/runtime.d.ts +1 -0
  26. package/dist/runtime.js +1445 -0
  27. package/dist/worker/camera-tile-worker.global.js +20 -0
  28. package/docs/application-tile-reading.md +86 -0
  29. package/docs/authoring-model.md +269 -0
  30. package/docs/boundary-areas-and-choropleths.md +217 -0
  31. package/docs/buildings-3d.md +608 -0
  32. package/docs/camera-moves-and-tile-cache.md +112 -0
  33. package/docs/capture-scenes.md +40 -0
  34. package/docs/capture-shots.md +173 -0
  35. package/docs/cartographic-defaults.md +210 -0
  36. package/docs/compiled-style-performance.md +286 -0
  37. package/docs/data-is-separate-from-design.md +610 -0
  38. package/docs/depth-markers.md +65 -0
  39. package/docs/dynamic-style-images.md +100 -0
  40. package/docs/globe-atmosphere.md +113 -0
  41. package/docs/hosted-session-authorization.md +106 -0
  42. package/docs/map-and-terrain-examples.md +156 -0
  43. package/docs/map-emphasis.md +89 -0
  44. package/docs/native-artifact-profile.md +152 -0
  45. package/docs/native-resource-urls.md +369 -0
  46. package/docs/nautical-marks.md +308 -0
  47. package/docs/public-api-and-browser-subpath.md +101 -0
  48. package/docs/route-drawing.md +191 -0
  49. package/docs/shared-visual-primitives.md +101 -0
  50. package/docs/street-lights.md +127 -0
  51. package/docs/street-sky.md +156 -0
  52. package/docs/style-states.md +73 -0
  53. package/docs/sun-and-light.md +167 -0
  54. package/docs/theme-transitions-and-blends.md +317 -0
  55. package/docs/themes-and-module-styles.md +156 -0
  56. package/docs/trees-3d.md +295 -0
  57. package/package.json +67 -8
@@ -0,0 +1,510 @@
1
+ // src/capture-scene.ts
2
+ import { z as z3 } from "zod";
3
+
4
+ // src/manifest-schema-classic.ts
5
+ import { z as z2 } from "zod";
6
+
7
+ // src/native-zod-object.ts
8
+ import { z } from "zod";
9
+ function strictNativeObject(shape) {
10
+ const object = new z.core.$ZodObject({
11
+ type: "object",
12
+ shape,
13
+ catchall: z.never()
14
+ });
15
+ return z.lazy(() => object);
16
+ }
17
+
18
+ // src/manifest-schema-classic.ts
19
+ function classic(schema) {
20
+ return schema;
21
+ }
22
+ var classicManifestStringOperations = {
23
+ string: () => z2.string(),
24
+ minLength(schema, minimum) {
25
+ return schema.min(
26
+ minimum
27
+ );
28
+ },
29
+ maxLength(schema, maximum) {
30
+ return schema.max(
31
+ maximum
32
+ );
33
+ },
34
+ regex: (schema, pattern, message) => schema.regex(pattern, { message }),
35
+ refine: (schema, check, message) => classic(schema).refine(check, message)
36
+ };
37
+ var classicManifestSchemaOperations = {
38
+ ...classicManifestStringOperations,
39
+ number: (minimum, maximum) => z2.number().finite().min(minimum).max(maximum),
40
+ unknown: () => z2.unknown(),
41
+ optional: (schema) => classic(schema).optional(),
42
+ array: (schema) => z2.array(classic(schema)),
43
+ enum(values) {
44
+ return z2.enum(values);
45
+ },
46
+ literal: (value) => z2.literal(value),
47
+ union: (left, right) => z2.union([classic(left), classic(right)]),
48
+ tuplePair(left, right) {
49
+ return z2.tuple([classic(left), classic(right)]);
50
+ },
51
+ object(shape) {
52
+ return strictNativeObject(shape);
53
+ },
54
+ record(key, value) {
55
+ return z2.record(classic(key), classic(value));
56
+ },
57
+ superRefine: (schema, check) => classic(schema).superRefine(check),
58
+ pipe: (input, output) => classic(input).pipe(classic(output))
59
+ };
60
+
61
+ // src/portable-identity-rules.ts
62
+ var tileflowPortableIdMaximumLength = 64;
63
+ var tileflowPortableIdPattern = /^[a-z][a-z0-9-]{0,63}$/u;
64
+ function isTileflowPortableId(value) {
65
+ return typeof value === "string" && value.length <= tileflowPortableIdMaximumLength && tileflowPortableIdPattern.test(value) && !["constructor", "prototype"].includes(value) && !/^(?:AUX|CON|NUL|PRN|COM[1-9]|LPT[1-9])$/i.test(value);
66
+ }
67
+ function isTileflowThemeName(value) {
68
+ return isTileflowPortableId(value) && value !== "system";
69
+ }
70
+
71
+ // src/portable-identity-schema.ts
72
+ function createPortableIdentitySchemas(operations) {
73
+ const bounded = operations.maxLength(
74
+ operations.minLength(operations.string(), 1),
75
+ tileflowPortableIdMaximumLength
76
+ );
77
+ const pattern = operations.regex(
78
+ bounded,
79
+ tileflowPortableIdPattern,
80
+ "Expected lowercase kebab-case beginning with a letter"
81
+ );
82
+ const tileflowPortableIdSchema2 = operations.refine(
83
+ pattern,
84
+ (name) => !["constructor", "prototype"].includes(name) && !/^(?:AUX|CON|NUL|PRN|COM[1-9]|LPT[1-9])$/i.test(name),
85
+ "Expected a portable identifier that is not a reserved filename or prototype key"
86
+ );
87
+ const tileflowThemeNameSchema2 = operations.refine(
88
+ tileflowPortableIdSchema2,
89
+ isTileflowThemeName,
90
+ "Expected a concrete theme name; system is browser-only"
91
+ );
92
+ return { tileflowPortableIdSchema: tileflowPortableIdSchema2, tileflowThemeNameSchema: tileflowThemeNameSchema2 };
93
+ }
94
+
95
+ // src/portable-identity.ts
96
+ var schemas = createPortableIdentitySchemas(classicManifestStringOperations);
97
+ var tileflowPortableIdSchema = schemas.tileflowPortableIdSchema;
98
+ var tileflowThemeNameSchema = schemas.tileflowThemeNameSchema;
99
+
100
+ // src/camera-limits.ts
101
+ var tileflowMaxPitch = 85;
102
+
103
+ // src/capture-scene.ts
104
+ var tileflowCaptureSceneSchemaVersion = 1;
105
+ var tileflowCaptureSceneLimits = Object.freeze({
106
+ applicationPathLength: 2048,
107
+ boundsPadding: { maximum: 1024, minimum: 0 },
108
+ captureIdLength: tileflowPortableIdMaximumLength,
109
+ maximumPhysicalPixels: 16777216,
110
+ pitch: { maximum: tileflowMaxPitch, minimum: 0 },
111
+ selectorLength: 256,
112
+ viewport: { maximum: 4096, minimum: 64 },
113
+ zoom: { maximum: 24, minimum: 0 }
114
+ });
115
+ var finiteLongitudeSchema = z3.number().finite().min(-180).max(180);
116
+ var finiteLatitudeSchema = z3.number().finite().min(-90).max(90);
117
+ var bearingSchema = z3.number().finite().min(-180).max(180).optional();
118
+ var pitchSchema = z3.number().finite().min(tileflowCaptureSceneLimits.pitch.minimum).max(tileflowCaptureSceneLimits.pitch.maximum).optional();
119
+ var tileflowCaptureCenterCameraSchema = z3.object({
120
+ type: z3.literal("center"),
121
+ center: z3.tuple([finiteLongitudeSchema, finiteLatitudeSchema]),
122
+ zoom: z3.number().finite().min(tileflowCaptureSceneLimits.zoom.minimum).max(tileflowCaptureSceneLimits.zoom.maximum),
123
+ bearing: bearingSchema,
124
+ pitch: pitchSchema
125
+ }).strict();
126
+ var tileflowCaptureBoundsCameraSchema = z3.object({
127
+ type: z3.literal("bounds"),
128
+ bounds: z3.tuple([
129
+ finiteLongitudeSchema,
130
+ finiteLatitudeSchema,
131
+ finiteLongitudeSchema,
132
+ finiteLatitudeSchema
133
+ ]),
134
+ padding: z3.number().finite().min(tileflowCaptureSceneLimits.boundsPadding.minimum).max(tileflowCaptureSceneLimits.boundsPadding.maximum).optional(),
135
+ bearing: bearingSchema,
136
+ pitch: pitchSchema
137
+ }).strict().superRefine((camera, context) => {
138
+ const [west, south, east, north] = camera.bounds;
139
+ if (south >= north) {
140
+ context.addIssue({
141
+ code: "custom",
142
+ message: "Expected south latitude to be less than north latitude",
143
+ path: ["bounds"]
144
+ });
145
+ }
146
+ if (west === east) {
147
+ context.addIssue({
148
+ code: "custom",
149
+ message: "Expected west and east longitude to define a non-empty span",
150
+ path: ["bounds"]
151
+ });
152
+ }
153
+ });
154
+ var tileflowCaptureCameraSchema = z3.discriminatedUnion("type", [
155
+ tileflowCaptureCenterCameraSchema,
156
+ tileflowCaptureBoundsCameraSchema
157
+ ]);
158
+ var tileflowCaptureViewportSchema = z3.object({
159
+ width: z3.number().int().min(tileflowCaptureSceneLimits.viewport.minimum).max(tileflowCaptureSceneLimits.viewport.maximum),
160
+ height: z3.number().int().min(tileflowCaptureSceneLimits.viewport.minimum).max(tileflowCaptureSceneLimits.viewport.maximum),
161
+ dpr: z3.union([z3.literal(1), z3.literal(2)]).optional()
162
+ }).strict().superRefine((viewport, context) => {
163
+ const dpr = viewport.dpr ?? 1;
164
+ const physicalWidth = viewport.width * dpr;
165
+ const physicalHeight = viewport.height * dpr;
166
+ const physicalPixels = viewport.width * viewport.height * dpr * dpr;
167
+ if (physicalWidth > tileflowCaptureSceneLimits.viewport.maximum || physicalHeight > tileflowCaptureSceneLimits.viewport.maximum || physicalPixels > tileflowCaptureSceneLimits.maximumPhysicalPixels) {
168
+ context.addIssue({
169
+ code: "custom",
170
+ message: `Expected physical width and height at most ${tileflowCaptureSceneLimits.viewport.maximum} pixels`,
171
+ path: ["dpr"]
172
+ });
173
+ }
174
+ });
175
+ var tileflowCaptureIdSchema = z3.string().min(1).max(tileflowCaptureSceneLimits.captureIdLength).regex(/^[A-Za-z0-9_-]+$/, {
176
+ message: "Expected letters, numbers, underscores, or hyphens"
177
+ }).refine((name) => name !== "__proto__", {
178
+ message: "Expected an identifier that cannot mutate an object prototype"
179
+ });
180
+ var tileflowCaptureSceneNameSchema = tileflowPortableIdSchema;
181
+ var applicationPathSchema = z3.string().min(1).max(tileflowCaptureSceneLimits.applicationPathLength).refine(isPortableApplicationPath, {
182
+ message: "Expected a root-relative application path without an origin, credentials, fragment, backslash, or control character"
183
+ });
184
+ var tileflowCaptureMapTargetSchema = z3.object({ kind: z3.literal("map") }).strict();
185
+ var tileflowCaptureApplicationTargetSchema = z3.object({
186
+ kind: z3.literal("application"),
187
+ path: applicationPathSchema,
188
+ captureId: tileflowCaptureIdSchema.optional(),
189
+ selector: z3.string().trim().min(1).max(tileflowCaptureSceneLimits.selectorLength).optional(),
190
+ frame: z3.enum(["map", "viewport"]).optional()
191
+ }).strict().superRefine((target, context) => {
192
+ if (target.captureId && target.selector) {
193
+ context.addIssue({
194
+ code: "custom",
195
+ message: "Expected either captureId or selector, not both",
196
+ path: ["selector"]
197
+ });
198
+ }
199
+ });
200
+ var tileflowCaptureTargetSchema = z3.discriminatedUnion("kind", [
201
+ tileflowCaptureMapTargetSchema,
202
+ tileflowCaptureApplicationTargetSchema
203
+ ]);
204
+ var tileflowCaptureSceneSchema = z3.object({
205
+ map: tileflowPortableIdSchema,
206
+ theme: tileflowThemeNameSchema,
207
+ camera: tileflowCaptureCameraSchema,
208
+ viewport: tileflowCaptureViewportSchema,
209
+ target: tileflowCaptureTargetSchema.optional()
210
+ }).strict();
211
+ function tileflowCaptureSceneFitIssue(scene) {
212
+ if (scene.camera.type !== "bounds" || scene.camera.padding === void 0) return void 0;
213
+ const room = Math.min(scene.viewport.width, scene.viewport.height);
214
+ if (scene.camera.padding * 2 < room) return void 0;
215
+ return {
216
+ message: `Expected bounds padding less than half the viewport's shorter side (${room / 2} pixels)`,
217
+ path: ["camera", "padding"]
218
+ };
219
+ }
220
+ function normalizeTileflowCaptureScene(input) {
221
+ const scene = tileflowCaptureSceneSchema.parse(input);
222
+ const fit = tileflowCaptureSceneFitIssue(scene);
223
+ if (fit) throw new RangeError(`${fit.path.join(".")}: ${fit.message}`);
224
+ const camera = scene.camera.type === "center" ? {
225
+ type: scene.camera.type,
226
+ center: scene.camera.center,
227
+ zoom: scene.camera.zoom,
228
+ bearing: scene.camera.bearing ?? 0,
229
+ pitch: scene.camera.pitch ?? 0
230
+ } : {
231
+ type: scene.camera.type,
232
+ bounds: scene.camera.bounds,
233
+ padding: scene.camera.padding ?? 0,
234
+ bearing: scene.camera.bearing ?? 0,
235
+ pitch: scene.camera.pitch ?? 0
236
+ };
237
+ const target = scene.target ?? { kind: "map" };
238
+ return {
239
+ map: scene.map,
240
+ theme: scene.theme,
241
+ camera,
242
+ viewport: { ...scene.viewport, dpr: scene.viewport.dpr ?? 1 },
243
+ target: target.kind === "map" ? target : {
244
+ kind: target.kind,
245
+ path: target.path,
246
+ ...target.captureId ? { captureId: target.captureId } : {},
247
+ ...target.selector ? { selector: target.selector } : {},
248
+ frame: target.frame ?? "map"
249
+ }
250
+ };
251
+ }
252
+ function normalizeTileflowCaptureId(value) {
253
+ return value === void 0 ? void 0 : tileflowCaptureIdSchema.parse(value);
254
+ }
255
+ function isPortableApplicationPath(value) {
256
+ if (value !== value.trim() || !value.startsWith("/") || value.startsWith("//") || value.includes("#") || value.includes("\\") || hasControlCharacter(value)) {
257
+ return false;
258
+ }
259
+ try {
260
+ const base = new URL("http://tileflow.local");
261
+ const resolved = new URL(value, base);
262
+ return resolved.origin === base.origin && resolved.username === "" && resolved.password === "" && resolved.pathname.startsWith("/");
263
+ } catch {
264
+ return false;
265
+ }
266
+ }
267
+ function hasControlCharacter(value) {
268
+ for (let index = 0; index < value.length; index += 1) {
269
+ const code = value.charCodeAt(index);
270
+ if (code <= 31 || code === 127) return true;
271
+ }
272
+ return false;
273
+ }
274
+
275
+ // src/capture-shot.ts
276
+ import { z as z4 } from "zod";
277
+
278
+ // src/capture-shot-motion.ts
279
+ function tileflowShotStateAt(shot, at) {
280
+ const { keyframes } = shot;
281
+ const first = keyframes[0];
282
+ const last = keyframes.at(-1);
283
+ if (!first || !last || keyframes.length < 2)
284
+ throw new TypeError("A shot needs at least two keyframes.");
285
+ const time = Math.min(last.at, Math.max(first.at, Number.isFinite(at) ? at : first.at));
286
+ let segment = 0;
287
+ while (segment < keyframes.length - 2 && time > keyframes[segment + 1].at) segment += 1;
288
+ const from = keyframes[segment];
289
+ const to = keyframes[segment + 1];
290
+ const linear = Math.min(1, Math.max(0, (time - from.at) / (to.at - from.at)));
291
+ const t = shot.easing === "linear" ? linear : smoothstep(linear);
292
+ return {
293
+ at: time,
294
+ camera: interpolateCamera(cameraOf(from), cameraOf(to), t),
295
+ ...from.blend && to.blend ? { blendPosition: interpolateNumber(from.blend.position, to.blend.position, t) } : {}
296
+ };
297
+ }
298
+ function cameraOf({ camera }) {
299
+ return {
300
+ type: "center",
301
+ center: [camera.center[0], camera.center[1]],
302
+ zoom: camera.zoom,
303
+ bearing: camera.bearing ?? 0,
304
+ pitch: camera.pitch ?? 0
305
+ };
306
+ }
307
+ var maximumMercatorLatitude = 85.051129;
308
+ function interpolateCamera(from, to, t) {
309
+ return {
310
+ type: "center",
311
+ center: interpolateCenter(from.center, to.center, t),
312
+ zoom: interpolateNumber(from.zoom, to.zoom, t),
313
+ bearing: interpolateBearing(from.bearing, to.bearing, t),
314
+ pitch: interpolateNumber(from.pitch, to.pitch, t)
315
+ };
316
+ }
317
+ function interpolateNumber(from, to, t) {
318
+ if (t <= 0 || from === to) return from;
319
+ if (t >= 1) return to;
320
+ return from + (to - from) * t;
321
+ }
322
+ function interpolateCenter(from, to, t) {
323
+ if (t <= 0 || from[0] === to[0] && from[1] === to[1]) return [from[0], from[1]];
324
+ if (t >= 1) return [to[0], to[1]];
325
+ const start = mercatorFromLngLat(from);
326
+ const end = mercatorFromLngLat(to);
327
+ let dx = end[0] - start[0];
328
+ if (dx > 0.5) dx -= 1;
329
+ else if (dx < -0.5) dx += 1;
330
+ return lngLatFromMercator([start[0] + dx * t, start[1] + (end[1] - start[1]) * t]);
331
+ }
332
+ function interpolateBearing(from, to, t) {
333
+ if (t <= 0 || from === to) return from;
334
+ if (t >= 1) return to;
335
+ const delta = ((to - from) % 360 + 540) % 360 - 180;
336
+ return wrapDegrees(from + delta * t);
337
+ }
338
+ function mercatorFromLngLat([longitude, latitude]) {
339
+ const clamped = Math.max(-maximumMercatorLatitude, Math.min(maximumMercatorLatitude, latitude));
340
+ return [
341
+ (180 + longitude) / 360,
342
+ (180 - 180 / Math.PI * Math.log(Math.tan(Math.PI / 4 + clamped * Math.PI / 360))) / 360
343
+ ];
344
+ }
345
+ function lngLatFromMercator([x, y]) {
346
+ const latitude = 360 / Math.PI * Math.atan(Math.exp((180 - y * 360) * Math.PI / 180)) - 90;
347
+ return [wrapDegrees(x * 360 - 180), latitude];
348
+ }
349
+ function wrapDegrees(value) {
350
+ if (value >= -180 && value <= 180) return value;
351
+ return ((value + 180) % 360 + 360) % 360 - 180;
352
+ }
353
+ function smoothstep(t) {
354
+ return t * t * (3 - 2 * t);
355
+ }
356
+
357
+ // src/capture-shot.ts
358
+ var tileflowCaptureShotSchemaVersion = 1;
359
+ var tileflowCaptureShotLimits = Object.freeze({
360
+ blendThemes: Object.freeze({ maximum: 8, minimum: 2 }),
361
+ defaultFps: 30,
362
+ durationMs: Object.freeze({ maximum: 6e4 }),
363
+ fps: Object.freeze([24, 25, 30, 50, 60]),
364
+ keyframes: Object.freeze({ maximum: 64, minimum: 2 }),
365
+ maximumFrames: 3600
366
+ });
367
+ var tileflowCaptureShotNameSchema = tileflowCaptureSceneNameSchema;
368
+ var tileflowCaptureShotBlendSchema = z4.object({
369
+ themes: z4.array(tileflowThemeNameSchema).min(tileflowCaptureShotLimits.blendThemes.minimum).max(tileflowCaptureShotLimits.blendThemes.maximum),
370
+ position: z4.number().finite().min(0)
371
+ }).strict().superRefine((blend, context) => {
372
+ if (new Set(blend.themes).size !== blend.themes.length) {
373
+ context.addIssue({ code: "custom", message: "Expected distinct themes", path: ["themes"] });
374
+ }
375
+ if (blend.position > blend.themes.length - 1) {
376
+ context.addIssue({
377
+ code: "custom",
378
+ message: `Expected a position from 0 to ${blend.themes.length - 1}`,
379
+ path: ["position"]
380
+ });
381
+ }
382
+ });
383
+ var tileflowCaptureShotKeyframeSchema = z4.object({
384
+ at: z4.number().int().min(0).max(tileflowCaptureShotLimits.durationMs.maximum),
385
+ camera: tileflowCaptureCenterCameraSchema,
386
+ blend: tileflowCaptureShotBlendSchema.optional()
387
+ }).strict();
388
+ var tileflowCaptureShotFields = {
389
+ theme: tileflowThemeNameSchema,
390
+ viewport: tileflowCaptureViewportSchema,
391
+ fps: z4.literal(tileflowCaptureShotLimits.fps).optional(),
392
+ keyframes: z4.array(tileflowCaptureShotKeyframeSchema).min(tileflowCaptureShotLimits.keyframes.minimum).max(tileflowCaptureShotLimits.keyframes.maximum),
393
+ easing: z4.enum(["smooth", "linear"]).optional()
394
+ };
395
+ var tileflowCaptureShotSchema = z4.object({ map: tileflowPortableIdSchema, ...tileflowCaptureShotFields }).strict().superRefine(checkShotTiming);
396
+ var tileflowMapShotSchema = z4.object(tileflowCaptureShotFields).strict().superRefine(checkShotTiming);
397
+ function normalizeTileflowCaptureShot(input) {
398
+ const shot = tileflowCaptureShotSchema.parse(input);
399
+ return { map: shot.map, ...normalizeShotFields(shot) };
400
+ }
401
+ function tileflowCaptureShotFrameCount(shot) {
402
+ const fps = shot.fps ?? tileflowCaptureShotLimits.defaultFps;
403
+ const duration = shot.keyframes.at(-1)?.at ?? 0;
404
+ return Math.floor(duration * fps / 1e3 + 1e-9) + 1;
405
+ }
406
+ function tileflowCaptureShotFrames(shot) {
407
+ const { map: _map, ...fields } = shot;
408
+ const normalized = normalizeShotFields(tileflowMapShotSchema.parse(fields));
409
+ const count = tileflowCaptureShotFrameCount(normalized);
410
+ const duration = normalized.keyframes.at(-1).at;
411
+ const frames = [];
412
+ for (let index = 0; index < count; index += 1) {
413
+ const at = Math.min(duration, index * 1e3 / normalized.fps);
414
+ frames.push({ index, ...tileflowShotStateAt(normalized, at) });
415
+ }
416
+ return frames;
417
+ }
418
+ function normalizeShotFields(shot) {
419
+ return {
420
+ theme: shot.theme,
421
+ viewport: { ...shot.viewport, dpr: shot.viewport.dpr ?? 1 },
422
+ fps: shot.fps ?? tileflowCaptureShotLimits.defaultFps,
423
+ easing: shot.easing ?? "smooth",
424
+ keyframes: shot.keyframes.map((keyframe) => ({
425
+ at: keyframe.at,
426
+ camera: {
427
+ type: "center",
428
+ center: keyframe.camera.center,
429
+ zoom: keyframe.camera.zoom,
430
+ bearing: keyframe.camera.bearing ?? 0,
431
+ pitch: keyframe.camera.pitch ?? 0
432
+ },
433
+ ...keyframe.blend ? { blend: { themes: [...keyframe.blend.themes], position: keyframe.blend.position } } : {}
434
+ }))
435
+ };
436
+ }
437
+ function checkShotTiming(shot, context) {
438
+ const { keyframes } = shot;
439
+ if (keyframes[0] && keyframes[0].at !== 0) {
440
+ context.addIssue({
441
+ code: "custom",
442
+ message: "Expected the first keyframe at 0 milliseconds",
443
+ path: ["keyframes", 0, "at"]
444
+ });
445
+ }
446
+ for (let index = 1; index < keyframes.length; index += 1) {
447
+ if (keyframes[index].at <= keyframes[index - 1].at) {
448
+ context.addIssue({
449
+ code: "custom",
450
+ message: "Expected a time after the previous keyframe",
451
+ path: ["keyframes", index, "at"]
452
+ });
453
+ }
454
+ }
455
+ const blended = keyframes.filter((keyframe) => keyframe.blend !== void 0);
456
+ if (blended.length > 0) {
457
+ const themes = JSON.stringify(blended[0].blend.themes);
458
+ keyframes.forEach((keyframe, index) => {
459
+ if (!keyframe.blend) {
460
+ context.addIssue({
461
+ code: "custom",
462
+ message: "Expected a blend on every keyframe when one keyframe blends themes",
463
+ path: ["keyframes", index, "blend"]
464
+ });
465
+ } else if (JSON.stringify(keyframe.blend.themes) !== themes) {
466
+ context.addIssue({
467
+ code: "custom",
468
+ message: "Expected the same themes, in the same order, on every keyframe",
469
+ path: ["keyframes", index, "blend", "themes"]
470
+ });
471
+ }
472
+ });
473
+ }
474
+ const frames = tileflowCaptureShotFrameCount(shot);
475
+ if (frames > tileflowCaptureShotLimits.maximumFrames) {
476
+ context.addIssue({
477
+ code: "custom",
478
+ message: `Expected at most ${tileflowCaptureShotLimits.maximumFrames} frames; this shot renders ${frames}`,
479
+ path: ["keyframes", keyframes.length - 1, "at"]
480
+ });
481
+ }
482
+ }
483
+ export {
484
+ normalizeTileflowCaptureId,
485
+ normalizeTileflowCaptureScene,
486
+ normalizeTileflowCaptureShot,
487
+ tileflowCaptureApplicationTargetSchema,
488
+ tileflowCaptureBoundsCameraSchema,
489
+ tileflowCaptureCameraSchema,
490
+ tileflowCaptureCenterCameraSchema,
491
+ tileflowCaptureIdSchema,
492
+ tileflowCaptureMapTargetSchema,
493
+ tileflowCaptureSceneFitIssue,
494
+ tileflowCaptureSceneLimits,
495
+ tileflowCaptureSceneNameSchema,
496
+ tileflowCaptureSceneSchema,
497
+ tileflowCaptureSceneSchemaVersion,
498
+ tileflowCaptureShotBlendSchema,
499
+ tileflowCaptureShotFrameCount,
500
+ tileflowCaptureShotFrames,
501
+ tileflowCaptureShotKeyframeSchema,
502
+ tileflowCaptureShotLimits,
503
+ tileflowCaptureShotNameSchema,
504
+ tileflowCaptureShotSchema,
505
+ tileflowCaptureShotSchemaVersion,
506
+ tileflowCaptureTargetSchema,
507
+ tileflowCaptureViewportSchema,
508
+ tileflowPortableIdSchema,
509
+ tileflowThemeNameSchema
510
+ };